Link to home
Start Free TrialLog in
Avatar of Alan Varga
Alan VargaFlag for United States of America

asked on

Create PowerShell 2-Dimensional Array From XML Configuration File

How do I convert the child nodes for a specific computer in this configuration file to a 2-dimensional table?  Here is the XML:
<PsProjects>
    <metadata>
        <revdate>2017-04-14</revdate>
    </metadata>


    <computers>

        <computer id="livingroom02">
            <item type="folder">C:\Computer-livingroom02 SYS 033</item>
            <item type="folder">C:\Computer-livingroom02 SYS 033\Hardware\Network Adapters</item>
            <item type="folder">C:\Computer-livingroom02 SYS 033\Software</item>
            <item type="folder">C:\Program2\Powershell</item>
            <item type="folder">C:\Program2\Varga\Network Mapping</item>
            <item type="folder">D:\Programming Languages\PowerShell</item>
            <item type="textfile">PsProjects.xml</item>
        </computer>

        <computer id="work">
            <item type="folder">C:\Computer</item>
            <item type="folder">C:\AlansDownloads\Alan\_AlansBriefcase</item>
            <item type="folder">C:\Computer\Hardware\Network Adapters</item>
            <item type="folder">C:\Computer\Software</item>
            <item type="folder">C:\Program2\Varga\Network Mapping</item>
            <item type="folder">C:\Workshop\PowerShell-work</item>
            <item type="textfile">PsProjects.xml</item>
        </computer>

    </computers>
</PsProjects>

Open in new window


This code doesn't seem to allow accessing individual elements of a specific item:
ForEach ( $computer in $ProjectsConfigFile.SelectNodes( "//PsProjects/computers/computer" ) ) {
    $PsComputerName = $computer.Attributes['id'].Value
    If ( $PsComputerName -eq $ThisComputerId ) {
        $MatchingComputer = $computer

        [array]$ProjectItems = $MatchingComputer.item

        break
    }
}

Open in new window


The results I want are like this:

$Result = $ProjectItems | Out-GridView -Passthru -Title "Select an item and click OK or press <Enter>, or press <Esc> to quit"
$Selection = [array]::IndexOf( $ProjectItems, $Result )

$SelectedItemText = $ProjectItems[$Selection].'#text'
$SelectedItemType = $ProjectItems[$Selection].type

#or

$SelectedItem = $ProjectItems[$Selection]
$SelectedItemText = $SelectedItem.'#text'
$SelectedItemType = $SelectedItem.type

Open in new window


I have a Switch statement further on that will do something different with $SelectedItemText, depending on whether $SelectedItemType is a folder or a textfile.

My problem is that $Result returns the type and text together.  Also, GridView lists the type column first and the #text column second.  What I want returned is the #text# for the row I select.
ASKER CERTIFIED SOLUTION
Avatar of oBdA
oBdA

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Alan Varga

ASKER

That looks much more efficient, and I understand it, but when I evaluate $Result in debug mode (breakpoint at line 6) I get an object, but not one with properties I can use:

Hit Line breakpoint on 'C:\Computer\Untitled1.ps1:6'
[DBG]: PS C:\Computer>> $result
@{Type=folder; Text=C:\Computer}

Open in new window


However, typing $Result. (note the period to prompt for properties), Intellisense only offers Length, Clone, etc.
Avatar of oBdA
oBdA

Can't reproduce, works just fine here. Are you using the xml you attached, and the exact script I posted? Does it display correctly in the GridView?
$ThisComputerId = 'work'
$ProjectsConfigFile = [xml](Get-Content -Path D:\Temp\PsProjects.xml)
$ComputerNode = $ProjectsConfigFile.SelectSingleNode("//PsProjects/computers/computer[@id='$($ThisComputerId)']")
$ProjectItems = $ComputerNode.SelectNodes('item') | Select-Object -Property @{n='Type'; e={$_.GetAttribute('type')}}, @{n='Text'; e={$_.InnerText}}
If ($Result = ($ProjectItems | Out-GridView -Title "Select an item and click OK or press <Enter>, or press <Esc> to quit" -OutputMode Single)) {
	$SelectedItemType = $Result.Type
	$SelectedItemText = $Result.Text
} Else {
	Exit 1
}
"Selected Type: $($SelectedItemType)" | Write-Host
"Selected Text: $($SelectedItemText)" | Write-Host

Open in new window

This is strange: I saved your most recent (re-)post on my computer at home, adjusted the computer id and the path for the configuration file and it worked without a hitch.

I will have to do some more troubleshooting at work on Monday.  Thanks for your patience and guidance.
I figured it out!  Near the beginning of my script (which was not shown here) I was initializing some variables (a habit of VBA option explicit).  My problem was
[string]$Result = ""

Open in new window

After I commented that out, $Result was allowed to be whatever it wanted to be (object? array?), everything worked as expected.  Thanks for your help.
This was understandable, short and to the point.  Kudos for a well-written solution that worked as advertised.