我正在编写一个Powershell脚本,它根据XML配置文件询问Active Directory,如下所示:
<domains>
<domain name="DOMAIN.INTERNAL" exclude="false">
<orgunit name="OU1" exclude="false"/>
<orgunit name="OU2" exclude="false">
<orgunit name="OU3" exclude="false"/>
<orgunit name="OU4" exclude="false"/>
<orgunit name="OU5" exclude="true"/>
</orgunit>
<host name="HOST1" exclude="false"/>
<host name="HOST2" exclude="true" />
<host name="HOST3" exclude="true" />
</domain>
<domain name="SUB.DOMAIN.INTERNAL" exclude="false">
<orgunit name="OU6" exclude="false">
<orgunit name="OU7" exclude="false">
<orgunit name="OU8" exclude="false">
<host name="HOST4" exclude="false" />
</orgunit>
</orgunit>
</orgunit>
<host name="HOST5" exclude="false"/>
<orgunit name="OU7" exclude="true" />
</domain>
</domains>
我正在加载xml文件,设置xpath,然后选择不会有孩子的orgunit节点:
$currentPath=Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path
[xml]$configFile = Get-Content "$currentPath\WindowsUpdateOMatic.xml"
foreach ($domain in $configFile.domains.domain) {
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"false`"][not (*)]/@name")
foreach($node in Select-Xml -Xpath $xpath $configFile){
# Find parent nodes
$node.Node.ParentNode
}
}
我的计划是遍历父组织单位节点,以便我可以创建OU的完整可分辨名称,例如&#34; OU =巴,OU = FOO,DC =子,DC =域,DC =内部&#34;
然后我可以查询活动目录中的OU并检索其中的主机。
麻烦的是,$ node.Node.ParentNode的值不会返回任何内容。尝试各种各样的事情,我确实让它返回&#34; InputStream&#34;但我现在无法复制。
我对Powershell来说相当新鲜,我很欣赏它看起来好像我可以在我走路之前跑步。
答案 0 :(得分:0)
我已经设法回答了我自己的问题。
我的示例中的xpath是错误的,因为它正在选择一个属性。改变:
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"false`"][not (*)]/@name")
要:
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"false`"][not (*)]")
表示如果父元素是组织单位,$node.Node.ParentNode.ToString()
将返回orgunit
。
现在我需要做的就是弄清楚如何在我得到父母之前递归树!=&#39; orgunit&#39;。
我认为这将是do while
或do until
循环。
答案 1 :(得分:0)
这有帮助吗?
function ConvertFrom-ADXmlToDN ($Element) {
$DNparent = ""
#Get parent DN - Recursion
if(($Element.ParentNode -ne $null) -and ($Element.ParentNode.LocalName -ne 'domains')) {
$DNparent = ",$(ConvertFrom-ADXmlToDN -Element $Element.ParentNode)"
}
#Convert to LDAP path
switch($Element.LocalName) {
"host" { "CN=$($Element.GetAttribute("name"))$DNparent" }
"orgunit" { "OU=$($Element.GetAttribute("name"))$DNparent" }
"domain" {
"DC=$($Element.GetAttribute("name") -split '\.' -join ',DC=')$DNparent"
}
}
}
#Sampledata
$ou = $xml.domains.domain[1].orgunit[0]
$machine = $xml.domains.domain[1].orgunit[0].orgunit.orgunit.host
ConvertFrom-ADXmlToDN -Element $ou
ConvertFrom-ADXmlToDN -Element $machine
OU=OU6,DC=SUB,DC=DOMAIN,DC=INTERNAL
CN=HOST4,OU=OU8,OU=OU7,OU=OU6,DC=SUB,DC=DOMAIN,DC=INTERNAL
用法:
ConvertFrom-ADXmlToDN -Element $node.Node
小建议。首先遍历xml文件以查找域,然后再循环遍历它以查找xpath(指定域名)。
作为Select-XML
的替代方案,您可以使用$domain.SelectNodes($xpath)
。但是你必须重写xpath以匹配你从domain-element而不是root xml-element开始的事实。像:
foreach ($domain in $xml.domains.domain) {
$xpath = ".//orgunit[@exclude='false'][not (*)]"
foreach($node in $domain.SelectNodes($xpath)) {
# Get DN
ConvertFrom-ADXmlToDN -Element $node
}
}
OU=OU1,DC=DOMAIN,DC=INTERNAL
OU=OU3,OU=OU2,DC=DOMAIN,DC=INTERNAL
OU=OU4,OU=OU2,DC=DOMAIN,DC=INTERNAL
答案 2 :(得分:0)
仅供参考,这是我想出来的,虽然我很欣赏它并不像Frode那么干净。 F的回答:
clear-host
Import-Module ActiveDirectory
Import-Module D:\Code\infrastructure\Scripts\PowershellModules\PSWindowsUpdate
function FDQNtoDN {
param([string]$FDQN)
[string]$dn = $null
[int]$index = 0
foreach($part in $FDQN.Split(".")) {
$dn = $dn + "DC=$part"
$index++
if( $index -ne $FDQN.Split(".").Count) {
$dn = $dn + ","
}
}
return $dn
}
$currentPath=Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path
[xml]$configFile = Get-Content "$currentPath\WindowsUpdateOMatic.xml"
# Process each domain specified in the configuration file
foreach ($domain in $configFile.domains.domain) {
# Retrieve excluded hosts from configuration file
$excludedHosts = @()
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//host[@exclude=`"true`"]/@name")
foreach($node in Select-Xml -Xpath $xpath $configFile){
$excludedHosts += ,@($node.ToString())
}
# Retrieve excluded org units from the configuration file
$excludedOrgUnits = @()
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"true`"]/@name")
foreach($node in Select-Xml -Xpath $xpath $configFile){
$excludedOrgUnits += ,@($node.ToString())
}
$hostsToUpdate = @()
# Retrieve org units within the current domain in the
# configuration file, ignoring org units with child
# elements
# Process childless org units
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"false`"][not (*)]")
foreach($orgUnit in (Select-Xml -Xpath $xpath $configFile)){
$distinguishedName = "OU=" + $orgUnit.Node.name + "," + $distinguishedName
# Ignore excluded org units
if(-not ($excludedOrgUnits -contains $orgUnit.Node.name)) {
# Get parent org units ready to interrogate AD
$parent = $orgUnit.Node.ParentNode
while($parent.localname -eq "orgunit") {
$distinguishedName = $distinguishedName + "OU=" + $parent.name + ","
if(-not ($parent.ParentNode -eq $null)) {
$parent = $parent.ParentNode
}
else {
break
} #ENDIF
} #ENDWHILE
$distinguishedName = $distinguishedName + (FDQNtoDN($domain.name).ToString())
$hostsToUpdate += (Get-ADComputer -server $domain.name -Filter 'ObjectClass -eq "Computer"' -SearchBase "$distinguishedName" -SearchScope OneLevel | Select -expand DNSHostName)
} #ENDIF
Remove-Variable distinguishedName
} #ENDFOREACH $orgUnit
# Retrieve individually specified hosts
$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//host[@exclude=`"false`"]")
foreach($hostToUpdate in (Select-Xml -Xpath $xpath $configFile)) {
# Ignore excluded hosts
if(-not ($excludedHosts -contains $hostToUpdate.Node.name)) {
$hostsToUpdate += ($hostToUpdate.Node.name) + (".") + ($domain.name)
}
} #ENDFOREACH $host
# Apply updates and reboot each host
foreach($hostToUpdate in $hostsToUpdate) {
# Attempt to find host in Nagios. If exists, put host into downtime
# If IIS box, drain stop from Apache2 Load Balancer
# Apply Updates
# Reboot & Wait a short period of time
# Check whether host is alive
# If IIS box: (N.B. NAnt scripts exist for some of this)
# start IIS gracefully
# warm up
# run rudimentary checks # apache readd probably does a calc
# re-add to Apache2 Load Balancer
# If applicable, Remove Nagios Downtime
}
$hostsToUpdate
Remove-Variable hostsToUpdate
}#