Home > Blockchain >  how to list in an object two elements from a complicated xml in Powershell
how to list in an object two elements from a complicated xml in Powershell

Time:11-01

  • I'm trying to create an object the will hold computer name with it's relevant ip address
  • I have the following XML that maps all my computers with their ips:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<hq>
    <dbs>
        <db>
            <ip>153.77.162.62</ip>
            <cn>SRRAALABJHQDB</cn>
        </db>
    </dbs>
    <mbs>
        <mb>
            <ip>153.77.162.63</ip>
            <cn>SRRAALABJHQRBT</cn>
        </mb>
    </mbs>
    <apps>
        <app>
            <ip>153.77.162.61</ip>
            <cn>SRRAALABJHQIIS</cn>
        </app>
    </apps>
    <sts>
        <st>
            <dbs>
                <db>
                    <ip>153.77.162.64</ip>
                    <cn>SRRAALABJST1</cn>
                </db>
            </dbs>
            <mbs>
                <mb>
                    <ip>153.77.162.64</ip>
                    <cn>SRRAALABJST1</cn>
                </mb>
            </mbs>
            <apps>
                <app>
                    <ip>153.77.162.64</ip>
                    <cn>SRRAALABJST1</cn>
                </app>
            </apps>
            <poss>
                <pos>
                    <dbs>
                        <db>
                            <cn>DTRAALABJPOS1</cn>
                        </db>
                    </dbs>
                    <apps>
                        <app>
                            <ip>153.77.162.66</ip>
                            <cn>DTRAALABJPOS1</cn>
                        </app>
                    </apps>
                </pos>
                <pos>
                    <dbs>
                        <db>
                            <cn>DTRAALABJPOS2</cn>
                        </db>
                    </dbs>
                    <apps>
                        <app>
                            <ip>153.77.162.67</ip>
                            <cn>DTRAALABJPOS2</cn>
                        </app>
                    </apps>
                </pos>
            </poss>
        </st>
        <st>
            <buid>100</buid>
            <dbs>
                <db>
                    <ip>153.77.162.65</ip>
                    <cn>SRRAALABJST2</cn>
                </db>
            </dbs>
            <mbs>
                <mb>
                    <ip>153.77.162.65</ip>
                    <cn>SRRAALABJST2</cn>
                </mb>
            </mbs>
            <apps>
                <app>
                    <ip>153.77.162.65</ip>
                    <cn>SRRAALABJST2</cn>
                </app>
            </apps>
            <poss>
                <pos>
                    <dbs>
                        <db>
                            <cn>DTRAALABJPOS3</cn>
                        </db>
                    </dbs>
                    <apps>
                        <app>
                            <ip>153.77.162.68</ip>
                            <cn>DTRAALABJPOS3</cn>
                        </app>
                    </apps>
                </pos>
            </poss>
        </st>
    </sts> 
</hq>
  • I need to create an Object that hold value along side to value (cn is short of Computer Name)

  • I tried the following script to create such an object:

$path = "C:\lab_j.xml"
[xml] $lab = Get-Content -Path $Path 


$vms = $lab | Select-Xml "//cn" | ForEach-Object { $_.Node.InnerText } | Select-Object -Unique
$ips = $lab | Select-Xml "//ip" | ForEach-Object { $_.Node.InnerText } | Select-Object -Unique

$vmObject = New-Object PSObject


Foreach ($vm in $vms) {

    if ([bool]($vmObject.psobject.Properties | where { $_.Name -eq "name"})) {
        $vmObject.name = $vm
    }
    else
    {
        $vmObject | Add-Member -MemberType NoteProperty -Name 'name' -Value $vm -Force
    }
}

Foreach ($ip in $ips) {
    
    if ([bool]($vmObject.psobject.Properties | where { $_.Name -eq "ip"})) {
        $vmObject.ip = $ip
    }
    else
    {
        $vmObject | Add-Member -MemberType NoteProperty -Name 'ip' -Value $ip -Force
    }
}
  • the output of $vmObject give only one "entry":
PS C:\Users\hiddai> $vmObject

name          ip           
----          --           
DTRAALABJPOS3 153.77.162.68

instead of:

PS C:\Users\hiddai> $vmObject

name           ip           
----           --           
SRRAALABJHQDB  153.77.162.62
SRRAALABJHQRBT 153.77.162.63
SRRAALABJHQIIS 153.77.162.61
SRRAALABJST1   153.77.162.64
DTRAALABJPOS1  153.77.162.66
DTRAALABJPOS2  153.77.162.67
SRRAALABJST2   153.77.162.65
DTRAALABJPOS3  153.77.162.68
  • Is there a short and simple way to create such an object?

CodePudding user response:

the output of $vmObject give only one "entry":

That's because you only ever create 1 object, then keep overwriting it's values.

Is there a short and simple way to create such an object?

Yes, you can use a single XPath query to find any XML element that has a <cn> and an <ip> child node, then create the resulting objects using Select-Object:

$lab.SelectNodes('//*[./cn and ./ip]') |Select-Object @{Name='Name';Expression='cn'},@{Name='IP';Expression='ip'}
  • Related