Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell XML-遍历父节点_Xml_Powershell - Fatal编程技术网

Powershell XML-遍历父节点

Powershell XML-遍历父节点,xml,powershell,Xml,Powershell,我正在编写一个Powershell脚本,它根据XML配置文件查询Active Directory,该文件如下所示: <domains> <domain name="DOMAIN.INTERNAL" exclude="false"> <orgunit name="OU1" exclude="false"/> <orgunit name="OU2" exclude="false"> <

我正在编写一个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>
我的计划是迭代父组织单元节点,以便创建OU的完整可分辨名称,例如OU=bar、OU=foo、DC=sub、DC=domain、DC=internal

然后我可以在active directory中查询OU并检索其中的主机

问题是,$node.node.ParentNode的值不返回任何内容。尝试了各种各样的方法,我确实让它返回了InputStream,但我现在无法复制它


我对Powershell还不太熟悉,我很欣赏它看起来我可能在走路之前就想跑了。

在某种程度上,我已经设法回答了我自己的问题

我的示例中的xpath是错误的,因为它正在选择一个属性。更改:

$xpath = ("/domains/domain[@name=`"") + ($domain.name) + ("`"]//orgunit[@exclude=`"false`"][not (*)]/@name")
致:

如果父元素是组织单位,则表示$node.node.ParentNode.ToString返回orgunit

我现在需要做的就是找出如何在树上递归,直到得到一个组织单位'

我想这将是一个do-while或do-until循环。

这有帮助吗

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

作为选择XML的替代方法,可以使用$domain.SelectNodes$xpath。但是您必须重写xpath以匹配以下事实:您是从域元素而不是根xml元素开始的。比如:

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

仅供参考,以下是我的想法,虽然我知道它没有弗罗德那么干净。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

}

谢谢。这与我到目前为止的结论并没有什么不同,只是我在迭代父元素,为每个组织单元建立一个FDQN,然后将其放入一个函数中,将FDQN转换为DN。你的路看起来干净多了。
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
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