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)