2014-10-16 67 views
0

我寫一個PowerShell腳本,其詢問基於XML配置文件的Active Directory,看起來是這樣的:PowerShell的XML - 遍歷,父節點

<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和然後選擇不生孩子的組織單元節點:

$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,例如完全可分辨名稱「OU =巴,OU = FOO,DC =子,DC =域,DC =內部」。

然後我可以查詢活動目錄中的OU並檢索其中的主機。

問題是,$ node.Node.ParentNode的值不會返回任何內容。嘗試各種各樣的東西,我得到它返回「InputStream」,但我不能現在再現。

我對Powershell相當陌生,我很欣賞它,看起來好像我可能在走路前試圖跑步。

回答

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如果父元素是組織單位。

現在我需要做的就是弄清楚如何對樹進行遞歸,直到我得到一個父=!'orgunit'。

我認爲這將是一個do whiledo until循環。

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而不是根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 
+0

感謝。這與我迄今爲止所取得的結果沒有什麼不同 - 除了我遍歷父元素併爲每個組織單元構建一個「FDQN」,然後將其轉換爲函數將FDQN轉換爲DN。你的方式看起來更乾淨。 – biscuitNinja 2014-10-17 13:39:02

0

只是作爲參考,這是我想出了,雖然我感謝它不像弗羅德干淨。 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 

}#