Need a little help with Powershell and XPath please

Keith VP 21 Reputation points
2022-12-05T14:46:28.31+00:00

I am a dinosaur and I have been able to do all my SCCM and remote administration stuff with batch files. I have been recently tasked with finding a value in an XML file from a vendor. I used to be pretty good at figuring things out, but I had a brain tumor and my cognitive ability just doesn't seem to be there like it was, so I'm reaching out for help.

Here is part of my XML, I hope it's enough I can't provide the whole thing

  <DEFAULT DESC="The default timeout values">  
     <PARAMS>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="LONG">  
              <PARAM NAME="LENGTH">60</PARAM>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="MULTIPLE_AMT_ENTRY">  
              <PARAM NAME="LENGTH">75</PARAM>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="MSDISPLAY">  
              <PARAM NAME="LENGTH">120</PARAM>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="TIMERHOST">  
              <PARAM NAME="LENGTH">60</PARAM>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="OPERATOR">  
              <PARAM NAME="LENGTH">2400</PARAM>  
           </PARAMGROUP>  
           <PARAMGROUP NAME="OPERATOR_LONG">  
              <PARAM NAME="LENGTH">2400</PARAM>  

I need to pull the OPERATOR value that's currently at 2400 and read what's there.

Here is my PS code so far

$test=0  
$xmlFile = "C:\whatever\Legit.xml"  
$xml = [xml](Get-Content -Path $xmlFile)  
$NAMES_PARAMS = $xml | Select-Xml -XPath '/BEHAVIOUR/SECTION/DEFAULT/PARAMS/PARAMLIST[@NAME="TIMEOUTS"]//PARAMGROUP' | Select -ExpandProperty NODE  
$NAMES_PARAMS | Select-Object –ExpandProperty ChildNodes   
$Values = $NAMES_PARAMS | Select NAME  
$Values  

This gives me results with the values I need, but not organized in a way I can seem to manipulate.

NAME #text
---- -----
LENGTH 75
LENGTH 60
LENGTH 300
LOOKUP \TC\CURTRANS\LOGIC\ADDSUFFIXCHAIN_END_STD
LENGTH 5
LENGTH 20
LENGTH 45
LOOKUP \TC\CURTRANS\LOGIC\ADDSUFFIXCHAIN_ERR_SCREEN
LENGTH 5
LENGTH 45
LOOKUP \TC\CURTRANS\LOGIC\ADDNOCARDSUFFIX_CARD_EJECT
LENGTH 30
LENGTH 10
LENGTH 2
LENGTH 2
LENGTH 5
LENGTH 10
LENGTH 15
LENGTH 5
LENGTH 14
LENGTH 30
LENGTH 45
LENGTH 120
LENGTH 45
LENGTH 60
LENGTH 75
LENGTH 120
LENGTH 60
LENGTH 2400
LENGTH 2400
LENGTH 600
CONFIGURABLE Y
LENGTH 1800
CONFIGURABLE Y
LENGTH 45
CONFIGURABLE Y
LENGTH 1200
LENGTH 130
LENGTH 400
LENGTH 1
LENGTH 30
LENGTH 3
LENGTH 300
LENGTH 8
LENGTH 30
LENGTH 60
LOOKUP \TC\CURTRANS\LOGIC\WDOVERRIDE_TIMEOUT
LENGTH 60
LENGTH 60
LENGTH 40
LENGTH 5
LENGTH 45
claimAssistRequestTimer
processAssistRequestTimer
DYNAMIC_END
END_STD_NOCHAIN
END_STD_NOCHAIN_LONG
END_STD_CHAIN
DYNAMIC_ERROR
ERR_SCREEN_NOCHAIN
ERR_SCREEN_CHAIN
DYNAMIC_CARD_EJECT_TIMEOUT
THANKS_SHORT
OPERATOR_OMP
SHORT
TIMEOUTSCREENTIMER
MEDIA_CAPTURE
CP_PROCESS_TIMEOUT
MEDIUM
TIMERDEFAULT
ENV_PREPARE_TIMEOUT
LONG
MULTIPLE_AMT_ENTRY
MSDISPLAY
TIMERHOST
OPERATOR
OPERATOR_LONG
OPERATOR_MEDIUM
OPERATOR_LOGS
OPERATOR_TIMEOUT
REPLACE_MEDIA_TIMEOUT
OVERRIDE
DISPLAY_CHAIN
ONSITEHELP
REMOVEID
RTDEFAULT
RTINTERRUPTED
ONSITEHELP_CONNECTED
ONSITEHELP_ACCEPTED
DYNAMIC_WDOVERRIDE_TIMEOUT
WDOVERRIDE_CONNECTED
WDOVERRIDE_ACCEPTED
ORIENTATION_TIMEOUT
MCA
DCC_SCREEN_TIMEOUT

Windows for business Windows Server User experience PowerShell
Windows for business Windows Server User experience Other
0 comments No comments
{count} votes

Accepted answer
  1. Rich Matheisen 47,901 Reputation points
    2022-12-05T22:41:00.527+00:00

    If you prefer to use XPATH to how I did it in my last answer, this should work:

    $xp = '//PARAMLIST[@NAME="TIMEOUTS"]/PARAMGROUP[@NAME="OPERATOR"]/PARAM[@NAME="LENGTH"]/text()'  
      
    $c = [int]($xml | Select-Xml -XPath $xp).ToString()  
    

2 additional answers

Sort by: Most helpful
  1. Rich Matheisen 47,901 Reputation points
    2022-12-05T16:19:54.4+00:00

    It might be considered cheating, but if XPATH isn't your cup of tea, try something like this:

    $p = $xml.behavior.section.default.params.paramlist.paramgroup | Where-Object {$_.Name -eq 'operator'}  
    if ($p.param.NAME -eq 'LENGTH'){  
        $v = [int]$p.param.'#text'  
    }  
    

    FYI, the XML you posted doesn't match the XPATH query! The XML is missing the "PARAMLIST" and its associated name attribute. I didn't bother adding the NAME of the paramlist to the code, but it should be easy enough to figure out.


  2. Rich Matheisen 47,901 Reputation points
    2022-12-05T20:18:00.28+00:00

    Again, sticking with the ability of directly addressing nodes and attributes in an XML document (instead of using XPATH), here's an expanded version (including the XML input). The result is that the value "2400" is placed in the variable named "$p":

    [xml]$xml = @"  
    <?xml version="1.0" encoding="utf-8"?>  
    <BEHAVIOR>  
        <SECTION>  
            <DEFAULT DESC="The default timeout values">  
                <PARAMS>  
                    <PARAMLIST NAME="TIMEOUTS">  
                            <PARAMGROUP NAME="LONG">  
                                <PARAM NAME="LENGTH">60</PARAM>  
                            </PARAMGROUP>  
                            <PARAMGROUP NAME="MULTIPLE_AMT_ENTRY">  
                                <PARAM NAME="LENGTH">75</PARAM>  
                            </PARAMGROUP>  
                            <PARAMGROUP NAME="MSDISPLAY">  
                                <PARAM NAME="LENGTH">120</PARAM>  
                            </PARAMGROUP>  
                            <PARAMGROUP NAME="TIMERHOST">  
                                <PARAM NAME="LENGTH">60</PARAM>  
                            </PARAMGROUP>  
                            <PARAMGROUP NAME="OPERATOR">  
                                <PARAM NAME="LENGTH">2400</PARAM>  
                            </PARAMGROUP>  
                            <PARAMGROUP NAME="OPERATOR_LONG">  
                                <PARAM NAME="LENGTH">2400</PARAM>  
                            </PARAMGROUP>  
                    </PARAMLIST>  
                    <PARAMLIST NAME="SOMEOTHERLIST">  
                        <!-- Some other list of parameters goes here -->  
                    </PARAMLIST>  
                </PARAMS>  
            </DEFAULT>  
        </SECTION>  
    </BEHAVIOR>  
    "@  
      
    $p = $xml.behavior.section.default.params.paramlist |           # find all the 'PARAMLIST" nodes  
            Where-Object {$_.NAME -eq "TIMEOUTS"} |                 # only interested in the ones name named "TIMEOUTS"  
                ForEach-Object{  
                    $_.PARAMGROUP |                                 # get all the PARAMGROUP nodes in the TIMEOUTS node  
                        ForEach-Object{  
                            if ($_.NAME -eq "OPERATOR"){            # and find the one named "OPERATOR"  
                                if ($_.PARAM.NAME -eq "LENGTH"){    # in this node, get the PARAM named "LENGTH" (if there is one)  
                                    [int]$_.PARAM.'#text'           # get the PARAM named "#text" and convert its value to an integer  
                                }  
                            }  
                        }  
                    }  
      
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.