This is part 6 of our mini-series covering PowerShell script block logging, and it’s time to address a final thing: when you execute very large PowerShell scripts, they are logged in chunks (parts). What’s missing is some logic that defragments the code parts:
function Get-LoggedCode { # to speed up SID-to-user translation, # we use a hash table with already translated SIDs # it is empty at first $translateTable = @{} # read all raw events $logInfo = @{ ProviderName="Microsoft-Windows-PowerShell" Id = 4104 } Get-WinEvent -FilterHashtable $logInfo | # take each raw set of data... ForEach-Object { # store the code in this entry # if this is the first part, take it if ($_.Properties[0].Value -eq 1) { $code = $_.Properties[2].Value } # else, add it to the $code variable else { $code += $_.Properties[2].Value } # return the object when all parts have been processed if ($_.Properties[0].Value -eq $_.Properties[1].Value) { # turn SID into user $userSID = $_.UserId # if the cache does not contain the user SID yet... if (!$translateTable.ContainsKey($userSid)) { try { # ...try and turn it into a real name, and add it # to the cache $identifier = New-Object System.Security.Principal.SecurityIdentifier($userSID) $result = $identifier.Translate( [System.Security.Principal.NTAccount]).Value $translateTable[$userSid] = $result } catch { # if this fails, use the SID instead of a real name $translateTable[$userSid] = $userSID } } else { } # create a new object and extract the interesting # parts from the raw data to compose a "cooked" # object with useful data [PSCustomObject]@{ # when this was logged Time = $_.TimeCreated # script code that was logged Code = $code # path of script file (this is empty for interactive # commands) Path = $_.Properties[4].Value # log level # by default, only level "Warning" will be logged Level = $_.LevelDisplayName # user who executed the code # take the real user name from the cache of translated # user names User = $translateTable[$userSID] } } } }
Essentially, this function checks whether the script consists of more than one part. If so, it adds the code to $code until the current part equals the final part. That’s it.