Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell XML Output

I'm having trouble getting the desired results in the correct format with this PowerShell query when run against an XML file exported from Task Scheduler. I will eventually have this run against all Task Scheduler exported jobs dumped to the same one XML file but I'm starting with just one for now.

PowerShell Logic (not working)

$file = "C:\folder\test.xml"
$Xml  = [xml](Get-Content $file)
$Xml.SelectNodes("//*").ChildNodes | Select URI,Command | 
Where-Object { ($_.URI -ne $null) -or ($_.Command -ne $null) } | FL 

Perhaps there's a better or more explicit way of doing this with PowerShell in a loop or embedding some C# code and executing that with PowerShell, etc. I figured I'd ask others here since I cannot get this figured out after a ton of testing and research but I'm open to all ideas to help me get the desired result or something similar (see below). If I needed the result from SQL Server I'd use FOR XML PATH.


Current Result Format (not desired)

URI     : \_Test\Test
Command : 

URI     : 
Command : C:\Folder\process1.exe

URI     : 
Command : C:\Folder\process2.exe

Desired Result Format (or similar)

URI     : \_Test\Test
Command : C:\Folder\process1.exe
Command : C:\Folder\process2.exe

Sample XML

   <?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2017-03-09T09:36:56.2658334</Date>
    <Author>FBI-PC1\User</Author>
    <URI>\_Test\Test</URI>
  </RegistrationInfo>
  <Triggers />
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-21-3517161704-4063526634-2635523359-1001</UserId>
      <LogonType>InteractiveToken</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>C:\Folder\process1.exe</Command>
    </Exec>
    <Exec>
      <Command>C:\Folder\process2.exe</Command>
    </Exec>
  </Actions>
</Task>

System Specs (needs to work with)

  • Windows 7
  • PowerShell V 4.0
like image 882
Bitcoin Murderous Maniac Avatar asked Mar 10 '17 04:03

Bitcoin Murderous Maniac


People also ask

How to read the XML file in PowerShell?

Reading the XML file in PowerShell is easy. We have the below XML file for our example, Suppose this file is saved as Animals.xml to our current path and to read this XML file we will first get the content of the file using Get-Content command and then we will perform type conversion into XML. For example,

How to convert output to XML using PowerShell?

To convert any possible output to the XML, you can use the convertTo-XML command. To expand further, we can use any of the methods (Xpath or Dot method). For example,

Is it possible to parse XML in PowerShell?

Despite its annoying use of angle brackets, XML format is still widely used. Configuration files, RSS feeds, Office files (the ‘x’ in the .docx) are just a partial list. Using PowerShell to parse XML files is an essential step in your PowerShell journey.

What is the difference between export-clixml and import-clixml in PowerShell?

IMPORTANT: It is very important to remember that XML file exported with Export-Clixml can be imported with counterpart Import-Clixml CmdLet while the initial sample XML file cannot be imported. Both xml files are well-formated XML files but only first one is readable by PowerShell using Import-Clixml CmdLet .


2 Answers

Since you are selecting both the objects together applying the where condition, so for maintaining the equality as a single object, it is showing like that .

In your case what you can do is to store the resultant in arraylist and do the manipulation there for all the Commands what you are getting like :

$file = "C:\folder\test.xml"
$Xml  = [xml](Get-Content $file)
$URI= $Xml.SelectNodes("//*").ChildNodes | Select URI| Where-Object { $_.URI -ne $null}
$Command= $Xml.SelectNodes("//*").ChildNodes | Select Command| Where-Object { $_.Command -ne $null}

$arraylisttable = New-Object System.Collections.ArrayList
$arraylisttable.Add($URI)  | Out-Null

foreach($cmd in $Command)
{
$arraylisttable.Add($Cmd) | Out-Null
}
$arraylisttable | fl

OUTPUT:

Result

Hope it helps.

like image 200
Ranadip Dutta Avatar answered Oct 26 '22 22:10

Ranadip Dutta


$Xml.SelectNodes("//*[local-name()='Command' or local-name()='URI']") | select Name, "#text"

Name    #text
----    -----
URI     \_Test\Test
Command C:\Folder\process1.exe
Command C:\Folder\process2.exe

This way you move selection logic to Xpath. Things to note:

  • //* selects all nodes
  • text inside [] is an XPath filter criteria.
  • using local-name() XPath function is a trick to avoid messing with namespaces

Note that XPath comparisons are case sensitive. Unfortunately XPath 1.0 does not have lower-case() or the like function. To make case-insensitive comparison (as Powershell does) use translate() function:

$Xml.SelectNodes("//*[translate(local-name(), 'COMAND', 'comand')='command' or translate(local-name(), 'uri', 'URI')='URI']") | select Name, "#text"

If you prefer pure Powershell over XPath here is alternate solution:

$xml.SelectNodes('//*') | ? {$_.Name -in ('command', 'uri')} | select Name, "#text"

One more thing about tasks. You do not have to dump them. They natively reside as xml already in theC:\Windows\Tasks or C:\Windows\System32\Tasks folders depending on the OS. For Win7 it is C:\Windows\System32\Tasks. You would need admin access to read them.

Edit: To get exactly the same output:

$xml.SelectNodes('//*') | ? { $_.Name -in ('command', 'uri') } |
 select Name, @{Name = 'Value'; Expression = {": $($_.'#text')" } } |
 ft -HideTableHeaders

URI     : \_Test\Test
Command : C:\Folder\process1.exe
Command : C:\Folder\process2.exe

Custom object:

$customObject = [pscustomObject]@{
    URI = ($xml.SelectNodes("//*[local-name()='URI']")).'#text'
    Command = ($xml.SelectNodes("//*[local-name()='Command']")).'#text'
}
$customObject | fl

URI     : \_Test\Test
Command : {C:\Folder\process1.exe, C:\Folder\process2.exe}
like image 28
Anton Krouglov Avatar answered Oct 27 '22 00:10

Anton Krouglov