Avatar of Alan Varga
Alan Varga
Flag 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.
PowershellXML

Avatar of undefined
Last Comment
Alan Varga

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
oBdA

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
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.
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

Alan Varga

ASKER
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.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Alan Varga

ASKER
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.
Alan Varga

ASKER
This was understandable, short and to the point.  Kudos for a well-written solution that worked as advertised.