Reading a String full of Curly Braces

Graham Pullen (UK) 41 Reputation points
2022-05-23T13:27:36.217+00:00

I have a script that grabs records from the Unified Audit log and finds when a file has its AIP Sensitivity Label Downgraded.
the returned object looks like this

RunspaceId : 1ed71237-60d3-47d9-b7ee-b99bf5c01db2
RecordType : AipSensitivityLabelAction
CreationDate : 11/04/2022 14:30:39
UserIds : firstname.surname@keyman .com
Operations : SensitivityLabelUpdated
AuditData : {"SensitiveInfoTypeData":[],"ProtectionEventData":{"IsProtected":false,"IsProtectedBefore":false},"Commo
n":{"ApplicationId":"c00e9d32-3c8d-4a7d-832b-029040e7db99","ApplicationName":"Microsoft Azure
Information Protection Word Add-In","ProcessName":"WINWORD","Platform":1,"DeviceName":"D99999999.domain.com
","Location":"On-premises file shares","ProductVersion":"2.13.49.0"},"DataState":"Use","Se
nsitivityLabelEventData":{"SensitivityLabelId":"9999999-d514-4220-b58f-525b27a4a097","OldSensitivityLab
elId":"9999999-0f6f-492f-b899-82535fbd2b4b","LabelEventType":2,"ActionSource":3,"JustificationText":"Pr
evious label was incorrect"},"ObjectId":"C:\Users\userid\folder\Public Word file - Copy.docx","UserI
d":"firstname.lastname@keyman .com","ClientIP":"999.99.999.99","Id":"99999999-9d93-9d22-9fcd-886ef6f92a
6b","RecordType":94,"CreationTime":"2022-04-11T14:30:39","Operation":"SensitivityLabelUpdated","Organiza
tionId":"99999999-2b82-4a00-bcdb-f1f6782a0f6e","UserType":0,"UserKey":"firstname.lastname@keyman .com",
"Workload":"Aip","Version":1,"Scope":1}
ResultIndex : 1
ResultCount : 23
Identity : a64b14e5-9d93-9d22-9fcd-886ef6f92a6b
IsValid : True
ObjectState : Unchanged

I want to report on the audit data. Currently I am reading values by splitting on the comma separator and discarding the braces like this

#    **** initialize and parse the logs ****  
$out=@{}  
$ii=0  
foreach ($log in $logs){  
       $audit = $log.auditdata -split ',(?=(?:[^"]|"[^"]*")*$)' #splits on comma ignoring any in double quotes (in case used in justification text)  
       #$audit = $audit.replace('"','')  
       $audit = $audit.replace('{','')  
       $audit = $audit.replace('}','')  
       $detail=@{}  
       foreach ($row in $audit){  
              $temp = $row -split ':(?=(?:[^"]|"[^"]*")*$)'  
  
              if($temp.count -eq 2){  
                     $tempclean = $temp[0].replace('"','')  
                     If ($tempclean -in $details) {  
                         $detail.add($tempclean,$temp[1])  
                     }  
              } else {  
                     $tempclean = $temp[1].replace('"','')  
                     if ($tempclean -in $details) {  
                         $detail.add($tempclean,$temp[2])  
                     }  
              }  
       }  
       $ii++  
       $out.add($ii,$detail)  
}  

Whilst it works ok, it feels pretty inefficient and doesn't manage nested braces very well.
Is there any easier way of taking the AuditData object and breaking into key value pairs?

When I pipe $logs[0].AuditData | Get-Member it returns TypeName: System.String
$logs[0].Auditdata.GetType() returns IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object

Azure Information Protection
Azure Information Protection
An Azure service that is used to control and help secure email, documents, and sensitive data that are shared outside the company.
520 questions
Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,390 questions
0 comments No comments
{count} votes

Accepted answer
  1. Vasil Michev 96,161 Reputation points MVP
    2022-05-23T13:44:04.857+00:00

    The AuditData field is basically a JSON blob. Easiest thing to do is "convert" it, which allows you to directly reference properties therein. Here's an example:

    $audit = $log.AuditData | ConvertFrom-Json
    $audit.ProcessName
    

    Keep in mind that some of the properties themselves are also in JSON format, rinse and repeat as needed.


1 additional answer

Sort by: Most helpful
  1. Krishnaswamy 1 Reputation point Microsoft Employee
    2022-09-02T20:28:02.44+00:00

    To extend @Vasil Michev response. I was working on similar scenario and sharing the full script. Traversing through Nested JSON was challenging - so included the additional piece of the code below.

    You an approach this in 2 ways using PowerShell.

    Powershell:-

    $auditLogSearchResults = Search-UnifiedAuditLog -StartDate $start -EndDate $end -RecordType $recordType -SessionId $sessionID -SessionCommand ReturnLargeSet -ResultSize $resultSize

        $log_analytics_array = @()              
        foreach($i in $auditLogSearchResults) {  
            $auditData = $i.AuditData | ConvertFrom-Json  
            $newitem = [PSCustomObject]@{      
                RunspaceId               = $i.RunspaceId  
                ApplicationName          = $auditData.Common.ApplicationName  
                Common_ProcessName       = $auditData.Common.ProcessName   
                Common_DeviceName        = $auditData.Common.DeviceName  
                Common_Location          = $auditData.Common.Location  
                Common_ProductVersion    = $auditData.Common.ProductVersion  
                RecordType               = $auditData.RecordType  
                Workload                 = $auditData.workload  
                UserId                   = $auditData.UserId  
                UserKey                  = $auditData.UserKey  
                ClientIP                 = $auditData.ClientIP  
                CreationTime             = $auditData.CreationTime  
                Operation                = $auditData.Operation  
                OrganizationId           = $auditData.OrganizationId  
            }  
    
            #$value = [System.Web.HttpUtility]::UrlEncode($auditData.objectId)  
            $value = $auditData.objectId  
            $newitem | Add-Member -MemberType NoteProperty -Name ObjectId -Value $value  
    
            $value= if($auditData.SensitivityLabelEventData.LabelEventType -eq $null)  { "" } else { $auditData.SensitivityLabelEventData.LabelEventType }  
            $newitem | Add-Member -MemberType NoteProperty -Name LabelEventType -Value $value  
    
            $value = if($auditData.SensitivityLabelEventData.ActionSource -eq $null)   { "" } else { $auditData.SensitivityLabelEventData.ActionSource }  
            $newitem | Add-Member -MemberType NoteProperty -Name ActionSource -Value $value  
    
            $value = if($auditData.SensitivityLabelEventData.SensitivityLabelId -eq $null) { "" } else { $auditData.SensitivityLabelEventData.SensitivityLabelId }  
            $newitem | Add-Member -MemberType NoteProperty -Name SensitivityLabelEventData_SensitivityLabelId -Value $value  
    
            $value = if($auditData.ProtectionEventData.ProtectionEventType -eq $null)      { "" } else { $auditData.ProtectionEventData.ProtectionEventType }  
            $newitem | Add-Member -MemberType NoteProperty -Name ProtectionEventType -Value $value  
    
            $value = if($auditData.ProtectionEventData.PreviousProtectionOwner -eq $null)  { "" } else { $auditData.ProtectionEventData.PreviousProtectionOwner }  
            $newitem | Add-Member -MemberType NoteProperty -Name PreviousProtectionOwner -Value $value  
    
            $log_analytics_array += $newitem  
    

    ADX:-
    Export the data into JSON and import into ADX and then use ADX to extract Json Fields.

    $sessionID = [Guid]::NewGuid().ToString() + "_" + "ExtractLogs" + (Get-Date).ToString("yyyyMMddHHmmssfff")
    [DateTime]$start = [DateTime]::UtcNow.Adddays(-22)
    [DateTime]$end = [DateTime]::UtcNow
    $resultSize = 5000

    import exchange online management module

    Import-Module ExchangeOnlineManagement

    connect to exchangeonline

    Connect-ExchangeOnline

    $record = "AipSensitivityLabelAction"
    $file = "AipSensitivityLabelAction"

    $auditLogSearchResults = Search-UnifiedAuditLog -StartDate $start -EndDate $end -RecordType $record -SessionId $sessionID -SessionCommand ReturnLargeSet -ResultSize $resultSize | ConvertTo-Json | out-file C:\log\$file.json -Append  
    

    Please note - the json file in this example is loaded into AllAIPData (Name the table as appropriate). AuditData is the Json Object.

    AllAIPData
    | extend AuditData=todynamic(AuditData)
    | extend applicationid=AuditData.Common.ApplicationId, Userid=AuditData.UserId , ApplicationName=AuditData.Common.ApplicationName
    | extend SensitivityLabelId=AuditData.SensitivityLabelEventData.SensitivityLabelId
    | extend ObjectId=AuditData.ObjectId
    | project ObjectId,ApplicationName,applicationid

    0 comments No comments