Public/Expand-NSPM365AuditRecord.ps1
|
function Expand-NSPM365AuditRecord { <# .SYNOPSIS Emits one row per nested item in a parsed Microsoft 365 audit record. .DESCRIPTION Expands MailItemsAccessed Folders/FolderItems, AttachmentAccess Messages/MessageItems, or AffectedItems from mail operations. The original record, container, and item remain nested to avoid property name collisions or loss of source detail. #> [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)][psobject]$InputObject, [ValidateSet('Auto', 'FolderItems', 'MessageItems', 'AffectedItems')][string]$ItemSource = 'Auto', [switch]$IncludeEmpty ) process { if (-not $InputObject.PSObject.Properties['AuditData'] -or -not $InputObject.PSObject.Properties['Operation']) { throw 'Each record must have AuditData and Operation properties.' } $source = $ItemSource if ($source -eq 'Auto') { switch ([string]$InputObject.Operation) { 'MailItemsAccessed' { $source = 'FolderItems'; break } 'AttachmentAccess' { $source = 'MessageItems'; break } { $_ -in 'HardDelete', 'SoftDelete', 'MoveToDeletedItems' } { $source = 'AffectedItems'; break } default { throw "No default item source for operation '$($InputObject.Operation)'. Specify -ItemSource." } } } $audit = $InputObject.AuditData if ($null -eq $audit) { throw 'AuditData is null.' } $containers = @() if ($source -in 'FolderItems', 'MessageItems') { $containerName = if ($source -eq 'FolderItems') { 'Folders' } else { 'Messages' } if ($audit.PSObject.Properties[$containerName] -and $null -ne $audit.$containerName) { $containers = @($audit.$containerName) } } else { if ($audit.PSObject.Properties['AffectedItems'] -and $null -ne $audit.AffectedItems) { $containers = @($audit.AffectedItems) } } $folderIndex = 0 foreach ($container in $containers) { if ($source -in 'FolderItems', 'MessageItems') { if ($null -eq $container) { throw "AuditData.$containerName contains a null entry." } $folder = if ($source -eq 'FolderItems') { $container } else { $null } $message = if ($source -eq 'MessageItems') { $container } else { $null } $items = @() $itemName = if ($source -eq 'FolderItems') { 'FolderItems' } else { 'MessageItems' } if ($container.PSObject.Properties[$itemName] -and $null -ne $container.$itemName) { $items = @($container.$itemName) } } else { $folder = $null $message = $null $items = @($container) } if ($items.Count -eq 0 -or ($items.Count -eq 1 -and $null -eq $items[0])) { if ($IncludeEmpty) { [pscustomobject]@{ RecordId = $InputObject.RecordId Operation = $InputObject.Operation CreationDate = $InputObject.CreationDate UserId = $InputObject.UserId FolderIndex = if ($source -eq 'FolderItems') { $folderIndex } else { $null } MessageIndex = if ($source -eq 'MessageItems') { $folderIndex } else { $null } ItemIndex = $null Folder = $folder Message = $message Item = $null _Record = $InputObject } } } else { for ($itemIndex = 0; $itemIndex -lt $items.Count; $itemIndex++) { [pscustomobject]@{ RecordId = $InputObject.RecordId Operation = $InputObject.Operation CreationDate = $InputObject.CreationDate UserId = $InputObject.UserId FolderIndex = if ($source -eq 'FolderItems') { $folderIndex } else { $null } MessageIndex = if ($source -eq 'MessageItems') { $folderIndex } else { $null } ItemIndex = $itemIndex Folder = $folder Message = $message Item = $items[$itemIndex] _Record = $InputObject } } } $folderIndex++ } if ($containers.Count -eq 0 -and $IncludeEmpty) { [pscustomobject]@{ RecordId = $InputObject.RecordId Operation = $InputObject.Operation CreationDate = $InputObject.CreationDate UserId = $InputObject.UserId FolderIndex = $null MessageIndex = $null ItemIndex = $null Folder = $null Message = $null Item = $null _Record = $InputObject } } } } |