Вывод PowerShell в формате XML

у меня возникли проблемы с получением желаемых результатов в правильном формате с этим PowerShell запрос при запуске с XML-файлом, экспортированным из Планировщик Задач. В конце концов, я буду работать против всех Планировщик Задач экспортированные задания сбрасываются в один и тот же XML-файл, но я начинаю только с одного.

PowerShell Logic (не работает)

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

возможно, есть лучше или более явный способ сделать это с PowerShell в цикле или встраивании некоторых C# код и выполнение этого с помощью PowerShell и т. д. Я решил, что спрошу других здесь, так как я не могу понять это после тонны тестирования и исследований, но я открыт для всех идей, чтобы помочь мне получить желаемый результат или что-то подобное (см. ниже). Если мне нужен результат SQL Server Я хотел бы использовать FOR XML PATH.


Текущий Формат Результата (не нужные)

URI     : _TestTest
Command : 

URI     : 
Command : C:Folderprocess1.exe

URI     : 
Command : C:Folderprocess2.exe

Желаемый Формат Результата (или похожие)

URI     : _TestTest
Command : C:Folderprocess1.exe
Command : C:Folderprocess2.exe

пример 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-PC1User</Author>
    <URI>_TestTest</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:Folderprocess1.exe</Command>
    </Exec>
    <Exec>
      <Command>C:Folderprocess2.exe</Command>
    </Exec>
  </Actions>
</Task>

Технические Характеристики Системы (должен работать)

  • Windows 7
  • PowerShell V 4.0

2 ответов


поскольку вы выбираете оба объекта вместе, применяя условие where, поэтому для поддержания равенства в качестве одного объекта он отображается так .

в вашем случае вы можете сохранить результат в arraylist и делать манипуляции там для всех команды что вы получаете, как :

$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

выход:

Result

надеюсь, что это помогает.


$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

таким образом, вы перемещаете логику выбора в Xpath. Вещи, чтобы отметить:

  • //* выбирает все узлы
  • текст [] является критерием фильтра XPath.
  • используя local-name() функции XPath-это трюк, чтобы избежать возни с пространствами имен

обратите внимание, что сравнения XPath чувствительны к регистру. К сожалению XPath 1.0 не имеет lower-case() или как функция. Чтобы сделать сравнение без учета регистра (как PowerShell ли) использовать translate() функция:

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

если вы предпочитаете чистый Powershell над XPath, вот альтернативное решение:

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

еще одно задачи. Вы не должны dump них. Они изначально находятся как xml уже вC:\Windows\Tasks или C:\Windows\System32\Tasks папки в зависимости от ОС. Для Win7 это C:\Windows\System32\Tasks. Вам понадобится доступ администратора, чтобы прочитать их.

Edit: и ровно то же вывод:

$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

настраиваемого объекта:

$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}