Search code examples
jsonpowershellpowershell-3.0

Powershell Foreach with squarebracket list


I've been trying to do a foreach loop through an square bracket list that results after running an executable with powershell.

Example: $json= .\chainsaw_windows.exe search C:\Windows\System32\winevt\Logs -e "test3.com" --json -q

The output of $json is:

[{"Event":{"EventData":{"CommandLine":"ping  test5.com","Company":"Microsoft Corporation","CurrentDirectory":"c:\\Users\\Administrator\\Downloads\\chainsaw\\","Description":"TCP/IP Ping Command","FileVersion":"10.0.19041.1 (WinBuild.160101.0800)","Hashes":"MD5=2F46799D79D22AC72C241EC0322B011D,SHA256=7AF50FA112932EA3284F7821B2EEA2B7582F558DBA897231BB82182003C29F8B,IMPHASH=8C3BE1286CDAD6AC1136D0BB6C83FF41","Image":"C:\\Windows\\System32\\PING.EXE","IntegrityLevel":"High","LogonGuid":"A7F7F064-C5F3-6321-E049-590100000000","LogonId":"0x15949e0","OriginalFileName":"ping.exe","ParentCommandLine":"\"C:\\Windows\\system32\\cmd.exe\" ","ParentImage":"C:\\Windows\\System32\\cmd.exe","ParentProcessGuid":"A7F7F064-378F-6344-C907-390000001A00","ParentProcessId":18128,"ParentUser":"DESKTOP-GI1ELAK\\Administrator","ProcessGuid":"A7F7F064-80A6-6344-010C-390000001A00","ProcessId":21596,"Product":"Microsoft® Windows® Operating System","RuleName":"-","TerminalSessionId":1,"User":"DESKTOP-GI1ELAK\\Administrator","UtcTime":"2022-10-10 20:29:26.108"},"System":{"Channel":"Microsoft-Windows-Sysmon/Operational","Computer":"DESKTOP-GI1ELAK","Correlation":null,"EventID":1,"EventRecordID":3504194,"Execution_attributes":{"ProcessID":3920,"ThreadID":6660},"Keywords":"0x8000000000000000","Level":4,"Opcode":0,"Provider_attributes":{"Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9","Name":"Microsoft-Windows-Sysmon"},"Security_attributes":{"UserID":"S-1-5-18"},"Task":1,"TimeCreated_attributes":{"SystemTime":"2022-10-10T20:29:26.111941Z"},"Version":5}},"Event_attributes":{"xmlns":"http://schemas.microsoft.com/win/2004/08/events/event"}},{"Event":{"EventData":{"Image":"<unknown process>","ProcessGuid":"00000000-0000-0000-0000-000000000000","ProcessId":21596,"QueryName":"test5.com","QueryResults":"::ffff:104.200.22.130;::ffff:104.200.23.95;","QueryStatus":"0","RuleName":"-","User":"DESKTOP-GI1ELAK\\Administrator","UtcTime":"2022-10-10 20:28:51.351"},"System":{"Channel":"Microsoft-Windows-Sysmon/Operational","Computer":"DESKTOP-GI1ELAK","Correlation":null,"EventID":22,"EventRecordID":3504195,"Execution_attributes":{"ProcessID":3920,"ThreadID":6680},"Keywords":"0x8000000000000000","Level":4,"Opcode":0,"Provider_attributes":{"Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9","Name":"Microsoft-Windows-Sysmon"},"Security_attributes":{"UserID":"S-1-5-18"},"Task":22,"TimeCreated_attributes":{"SystemTime":"2022-10-10T20:29:28.147643Z"},"Version":5}},"Event_attributes":{"xmlns":"http://schemas.microsoft.com/win/2004/08/events/event"}}]

I have tried this, but it doesn't work:

foreach ($result in $json)
{
  write-out $result
}

What should I do?


Solution

    • $json contains text in JSON format.

    • In order to work with the objects that the JSON text represents you must first parse the text into objects (into a graph of [pscustomobject] instances), using the ConvertFrom-Json cmdlet.

    # The output from your .\chainsaw_windows.exe ... call.
    $json = '[{"Event":{"EventData":{"CommandLine":"ping  test5.com","Company":"Microsoft Corporation","CurrentDirectory":"c:\\Users\\Administrator\\Downloads\\chainsaw\\","Description":"TCP/IP Ping Command","FileVersion":"10.0.19041.1 (WinBuild.160101.0800)","Hashes":"MD5=2F46799D79D22AC72C241EC0322B011D,SHA256=7AF50FA112932EA3284F7821B2EEA2B7582F558DBA897231BB82182003C29F8B,IMPHASH=8C3BE1286CDAD6AC1136D0BB6C83FF41","Image":"C:\\Windows\\System32\\PING.EXE","IntegrityLevel":"High","LogonGuid":"A7F7F064-C5F3-6321-E049-590100000000","LogonId":"0x15949e0","OriginalFileName":"ping.exe","ParentCommandLine":"\"C:\\Windows\\system32\\cmd.exe\" ","ParentImage":"C:\\Windows\\System32\\cmd.exe","ParentProcessGuid":"A7F7F064-378F-6344-C907-390000001A00","ParentProcessId":18128,"ParentUser":"DESKTOP-GI1ELAK\\Administrator","ProcessGuid":"A7F7F064-80A6-6344-010C-390000001A00","ProcessId":21596,"Product":"Microsoft® Windows® Operating System","RuleName":"-","TerminalSessionId":1,"User":"DESKTOP-GI1ELAK\\Administrator","UtcTime":"2022-10-10 20:29:26.108"},"System":{"Channel":"Microsoft-Windows-Sysmon/Operational","Computer":"DESKTOP-GI1ELAK","Correlation":null,"EventID":1,"EventRecordID":3504194,"Execution_attributes":{"ProcessID":3920,"ThreadID":6660},"Keywords":"0x8000000000000000","Level":4,"Opcode":0,"Provider_attributes":{"Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9","Name":"Microsoft-Windows-Sysmon"},"Security_attributes":{"UserID":"S-1-5-18"},"Task":1,"TimeCreated_attributes":{"SystemTime":"2022-10-10T20:29:26.111941Z"},"Version":5}},"Event_attributes":{"xmlns":"http://schemas.microsoft.com/win/2004/08/events/event"}},{"Event":{"EventData":{"Image":"<unknown process>","ProcessGuid":"00000000-0000-0000-0000-000000000000","ProcessId":21596,"QueryName":"test5.com","QueryResults":"::ffff:104.200.22.130;::ffff:104.200.23.95;","QueryStatus":"0","RuleName":"-","User":"DESKTOP-GI1ELAK\\Administrator","UtcTime":"2022-10-10 20:28:51.351"},"System":{"Channel":"Microsoft-Windows-Sysmon/Operational","Computer":"DESKTOP-GI1ELAK","Correlation":null,"EventID":22,"EventRecordID":3504195,"Execution_attributes":{"ProcessID":3920,"ThreadID":6680},"Keywords":"0x8000000000000000","Level":4,"Opcode":0,"Provider_attributes":{"Guid":"5770385F-C22A-43E0-BF4C-06F5698FFBD9","Name":"Microsoft-Windows-Sysmon"},"Security_attributes":{"UserID":"S-1-5-18"},"Task":22,"TimeCreated_attributes":{"SystemTime":"2022-10-10T20:29:28.147643Z"},"Version":5}},"Event_attributes":{"xmlns":"http://schemas.microsoft.com/win/2004/08/events/event"}}]'
    
    # Convert the JSON text to objects (a [pscustomobject] object graph)
    # Here, given that the JSON text represents an *array* ([ ... ]),
    # an array of nested [pscustomobject]s is returned.
    $objectsFromJson = $json | ConvertFrom-Json
    
    # Process the array's elements.
    foreach ($object in $objectsFromJson) {
      $object
    }
    

    This prints the following to the display:

    Event                  Event_attributes
    -----                  ----------------
    @{EventData=; System=} @{xmlns=http://schemas.microsoft.com/win/2004/08/events/event}
    @{EventData=; System=} @{xmlns=http://schemas.microsoft.com/win/2004/08/events/event}
    

    While this representation isn't particularly helpful, it is to be expected, given that PowerShell's for-display formatting system isn't optimized for nested objects.

    • The tabular displays shows the two top-level properties that the array elements have.

    • The hashtable-like @{ ...; ... } representation is how nested [pscustomobject]s are represented by default.

    • That EventData and System appear to have no values is the manifestation of a long-standing bug, where calling .ToString() on [pscustomobject] instances unexpectedly yields the empty string - see GitHub issue #6163.

    However:

    • All the data is there, and you can work with it.

      • For instance, use the following to extract the nested UtcTime property value from the objects:

        # ->  '2022-10-10 20:29:26.108', '2022-10-10 20:28:51.351' 
        foreach ($object in $objectsFromJson) {
          $object.Event.EventData.UtcTime
        }
        
      • Using member-access enumeration you can even access the nested property on the array itself, and have the elements' property values extracted:

        $objectsFromJson.Event.EventData.UtcTime
        
    • if you need a quick visualization of a nested object, simply reconvert it to JSON with ConvertTo-Json (though note that you may need a -Depth argument to avoid truncation - see this post).