1

Thank you for all the help I've ever gotten here.

Scenario: Parsing XMLs Recursively into a neat CSV

Structure:

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Author>Microsoft Corporation</Author>
    <URI>\OneDrive Reporting Task-S-1-5-21-XXXXXXXXXX-XXXXXXX-683614252-544081760</URI>
  </RegistrationInfo>
  <Triggers>
    <TimeTrigger>
      <StartBoundary>2022-09-07T12:45:02</StartBoundary>
      <Enabled>true</Enabled>
      <Repetition>
        <Interval>P1D</Interval>
        <StopAtDurationEnd>false</StopAtDurationEnd>
      </Repetition>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-21-XXXXXXXX-XXXXXXX-683614252-544081760</UserId>
      <RunLevel>LeastPrivilege</RunLevel>
      <LogonType>InteractiveToken</LogonType>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
    <Priority>7</Priority>
    <RestartOnFailure>
      <Interval>PT30M</Interval>
      <Count>2</Count>
    </RestartOnFailure>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>%localappdata%\Microsoft\OneDrive\OneDriveStandaloneUpdater.exe</Command>
      <Arguments>/reporting</Arguments>
    </Exec>
  </Actions>
</Task>

I have managed to parse one XML into a CSV:

$xmlFile = [xml](get-content "OneDrive Reporting Task-S-1-5-21-xxxxxxxx-xxxxxxxx-683614252-544134134")
$Date = $xmlFile.ChildNodes.RegistrationInfo.Date
$Author = $xmlFile.ChildNodes.RegistrationInfo.Author
$Description = $xmlFile.ChildNodes.RegistrationInfo.Description
$URI = $xmlFile.ChildNodes.RegistrationInfo.URI
$Principals = $xmlFile.ChildNodes.Principals.Principal.UserId
$LogonType = $xmlFile.ChildNodes.Principals.Principal.LogonType
$Enabled = $xmlFile.ChildNodes.Triggers.CalendarTrigger.Enabled
$Action = $xmlFile.ChildNodes.Actions.Exec.Command
$Arguments = $xmlFile.ChildNodes.Actions.Exec.Arguments

$xmlFile.ChildNodes[1] | 
ForEach-Object{
         [PSCustomObject]@{
             Registration_Date = $Date
             Author = $Author
             Description = $Description
             URI = $URI
             Principals_UserContext = $Principals
             LogonType = $LogonType
             Enabled = $Enabled
             Action = $Action
             Arguments = $Arguments
         }
     } | Export-Csv .\01Parsed_Tasks_XML.csv -NoTypeInformation

The idea is to look for XMLs recursively in a Folder, and do all the above and keep appending the data. I'll keep trying but in the meanwhile, would appreciate some help too.

1 Answer 1

3
function Flatten-Xml ([System.Xml.XmlNode]$Xml, [Parameter(DontShow)]$ParentName) {
    if (!$ParentName) { $Properties = [Ordered]@{} }
    $Xml |Get-Member -MemberType 'Property' |ForEach-Object {
        $Name = if ($ParentName) { "$ParentName.$($_.Name)" } else { $_.Name }
        $Node = $Xml.$($_.Name)
        for ($i = 0; $i -lt @($Node).Count; $i++) {
            $Index = if ($Node.Count -le 1) { $Name } else { "$Name[$i]" }
            $Value = if ($Node.Count -le 1) { $Node } else { $Node[$i] }
            if ($Value -is [System.Xml.XmlElement]) { Flatten-Xml $Value $Index }
            elseif ($Value -is [String]) { $Properties[$Index] = $Value }
        }
    }
    if (!$ParentName) { [PSCustomObject]$Properties }
}
Flatten-Xml $Xml

Task.Actions.Context                                   : Author
Task.Actions.Exec.Arguments                            : /reporting
Task.Actions.Exec.Command                              : %localappdata%\Microsoft\OneDrive\OneDriveStandaloneUpdater.exe
Task.Principals.Principal.id                           : Author
Task.Principals.Principal.LogonType                    : InteractiveToken
Task.Principals.Principal.RunLevel                     : LeastPrivilege
Task.Principals.Principal.UserId                       : S-1-5-21-XXXXXXXX-XXXXXXX-683614252-544081760
Task.RegistrationInfo.Author                           : Microsoft Corporation
Task.RegistrationInfo.URI                              : \OneDrive Reporting Task-S-1-5-21-XXXXXXXXXX-XXXXXXX-683614252-544081760
Task.Settings.AllowHardTerminate                       : true
Task.Settings.AllowStartOnDemand                       : true
Task.Settings.DisallowStartIfOnBatteries               : false
Task.Settings.Enabled                                  : true
Task.Settings.ExecutionTimeLimit                       : PT2H
Task.Settings.Hidden                                   : false
Task.Settings.MultipleInstancesPolicy                  : IgnoreNew
Task.Settings.Priority                                 : 7
Task.Settings.RestartOnFailure.Count                   : 2
Task.Settings.RestartOnFailure.Interval                : PT30M
Task.Settings.RunOnlyIfIdle                            : false
Task.Settings.RunOnlyIfNetworkAvailable                : true
Task.Settings.StartWhenAvailable                       : true
Task.Settings.StopIfGoingOnBatteries                   : true
Task.Settings.WakeToRun                                : false
Task.Triggers.TimeTrigger.Enabled                      : true
Task.Triggers.TimeTrigger.Repetition.Interval          : P1D
Task.Triggers.TimeTrigger.Repetition.StopAtDurationEnd : false
Task.Triggers.TimeTrigger.StartBoundary                : 2022-09-07T12:45:02
Task.version                                           : 1.2
Task.xmlns                                             : http://schemas.microsoft.com/windows/2004/02/mit/task
xml                                                    : version="1.0" encoding="UTF-16"
Sign up to request clarification or add additional context in comments.

3 Comments

Amazing! Thank you for the time spent.. However it's missing "Task.RegistrationInfo.Date" in one of the XML files if I export like this ``` $ListOfTasks = (Get-ChildItem -File -Path .\ -Recurse).fullname $Final = @() $ListOfTasks | foreach { $xml = [xml](get-content $_) $Final += Flatten-Xml $Xml } $Final | Export-Csv -Path .\Test.csv -NoTypeInformation ``` If I only use it to flatten one XML - it parsed out the fields! Unsure what's going wrong here.. Ummm.. I'd still like to only export a selective set of columns from the XMLs :(
@Origami, I guess you ran into this issue: Not all properties displayed, try : $Final |UnifyProperties |Export-Csv -Path .\Test.csv -NoTypeInformation
Oh I'm more than happy for the guidance here. Thank you thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.