Home > Back-end >  Amend XML object using PowerShell
Amend XML object using PowerShell

Time:02-05

I'm trying to edit a xml object in PowerShell but the xml object is quite hard to get to. I've read quite a few posts and articles and they all show easy xml objects or files. And they all work as long as the xml tree is simple and no tags with ':' inside them show up. In my case the xml object is obtained from an Active Directory GPO, through this command:

[xml]$report = Get-GPOReport -Guid 'BEE66288-DF38-4E32-A6F6-9DF13BABFDDF' -ReportType XML -Server "fqdn"

The xml that generates is quite long and full of sensitive data, so I had to trim it and sanitize it quite a lot, but it gives the idea:

<?xml version="1.0" encoding="utf-16"?>
<GPO xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.microsoft.com/GroupPolicy/Settings">
  <Computer>
    <VersionDirectory>51</VersionDirectory>
    <VersionSysvol>51</VersionSysvol>
    <Enabled>true</Enabled>
    <ExtensionData>
      <Extension xmlns:q1="http://www.microsoft.com/GroupPolicy/Settings/Files" xsi:type="q1:FilesSettings">
        <q1:FilesSettings clsid="{215B2E53-57CE-475c-80FE-9EEC14635851}">
        </q1:FilesSettings>
      </Extension>
      <Name>Files</Name>
    </ExtensionData>
    <ExtensionData>
      <Extension xmlns:q2="http://www.microsoft.com/GroupPolicy/Settings/ScheduledTasks" xsi:type="q2:ScheduledTasksSettings">
        <q2:ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}">
          <q2:TaskV2 clsid="{D8896631-B747-47a7-84A6-C155337F3BC8}" name="VBS" image="1" changed="2022-12-01 09:28:19" uid="{6128F739-7B10-4D53-B8B2-4F7D8D518B39}">
            <q2:GPOSettingOrder>1</q2:GPOSettingOrder>
            <q2:Properties action="R" name="VBS" runAs="NT AUTHORITY\System" logonType="S4U">
              <q2:Task version="1.2">
                <q2:RegistrationInfo>
                  <q2:Description>VBS script installs windows update without rebooting</q2:Description>
                </q2:RegistrationInfo>
                <q2:Triggers>
                  <q2:CalendarTrigger>
                    <q2:Enabled>true</q2:Enabled>
                    <q2:StartBoundary>2022-03-27T14:30:00</q2:StartBoundary>
                    <q2:ExecutionTimeLimit>PT4H</q2:ExecutionTimeLimit>
                  </q2:CalendarTrigger>
                </q2:Triggers>
              </q2:Task>
            </q2:Properties>
            <q2:Filters />
          </q2:TaskV2>
          <q2:TaskV2 clsid="{D8896631-B747-47a7-84A6-C155337F3BC8}" name="PS" image="1" changed="2022-12-01 09:28:05" uid="{27A6954B-DC81-42CE-ACA3-FB70CD1DDC98}">
            <q2:GPOSettingOrder>2</q2:GPOSettingOrder>
            <q2:Properties action="R" name="PS" runAs="NT AUTHORITY\System" logonType="S4U">
              <q2:Task version="1.2">
                <q2:RegistrationInfo>
                  <q2:Description>PS script to schedule reboot</q2:Description>
                </q2:RegistrationInfo>
                <q2:Triggers>
                  <q2:CalendarTrigger>
                    <q2:Enabled>true</q2:Enabled>
                    <q2:StartBoundary>2022-03-27T14:30:05</q2:StartBoundary>
                    <q2:ExecutionTimeLimit>PT4H</q2:ExecutionTimeLimit>
                  </q2:CalendarTrigger>
                </q2:Triggers>
              </q2:Task>
            </q2:Properties>
            <q2:Filters />
          </q2:TaskV2>
        </q2:ScheduledTasks>
      </Extension>
      <Name>Scheduled Tasks</Name>
    </ExtensionData>
  </Computer>
</GPO>

my goal is to 'select' the lines <q2:StartBoundary>2022-03-27T14:30:05</q2:StartBoundary> for each node, then edit them and put them back in the object. Basically I need to change the date/time and save it back in the GPO. I can do the saving back in the GPO by myself. My objective here is to be able to select those lines. I've tried with:

$nodes = $report.GPO.ChildNodes.Item(0)

but I can only get as far as the ExtensionData tag. After that the content gets empty, and I have nothing to manipulate. I've also tried

$nodes = $report.GPO.Computer.ExtensionData.Extension | Where-Object {$_.type -eq 'q2:ScheduledTasksSettings'}

but same thing. Also this:

$xpath = "/GPO/Computer/ExtensionData/Extension/q2:ScheduledTasks/q2:TaskV2"
$nodesX = Select-Xml -Xml $report -XPath $xpath

but I get an error: Select-Xml : Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function

Any hint?

CodePudding user response:

Try xml linq

using assembly System 
using assembly System.Linq
using assembly System.Xml.Linq 

$inputFilename = "c:\temp\test.xml"
$outputFilename = "c:\temp\test1.xml"

$reader = [System.IO.StreamReader]::new($inputFilename)
# skip first line with utf-16
$reader.ReadLine()
$xDoc = [System.Xml.Linq.XDocument]::Load($reader)
$today = [DateTime]::Now
$tasksV2 = $records = $xDoc.Descendants().Where( {$_.Name.LocalName -eq "TaskV2"})
foreach($taskV2 in $tasksV2)
{
   $name = $taskV2.Attribute("name").Value

   $startBoundary = $taskV2 = $xDoc.Descendants().Where( {$_.Name.LocalName -eq "StartBoundary"})
   $oldDate = $startBoundary[0].Value
   $todayStr = $today.ToString("yyyy-MM-ddTHH:mm:ss")
   Write-Host "Task Name = " $name ",Old Date = " $oldDate ",Today Date = " $todayStr
   $startBoundary.SetValue($todayStr)
}
$xDoc.Save($outputFilename)
  • Related