Src/Private/Get-AbrPurviewInsiderRisk.ps1
|
function Get-AbrPurviewInsiderRisk { <# .SYNOPSIS Used by As Built Report to retrieve Microsoft Purview Insider Risk Management information. .DESCRIPTION Collects and reports on Insider Risk Management policies configured in Microsoft Purview, using the Microsoft Graph API. .NOTES Version: 0.1.0 Author: Pai Wei Sing .EXAMPLE .LINK #> [CmdletBinding()] param ( [Parameter ( Position = 0, Mandatory)] [string] $TenantId ) begin { Write-PScriboMessage -Message "Collecting Microsoft Purview Insider Risk Management information for tenant $TenantId." | Out-Null Show-AbrDebugExecutionTime -Start -TitleMessage 'Insider Risk' } process { # Check Graph is connected before attempting API calls if (-not (Get-MgContext -ErrorAction SilentlyContinue)) { Write-PScriboMessage -IsWarning -Message "Skipping Insider Risk section: No active Microsoft Graph session." | Out-Null return } try { # Insider Risk policies via Security & Compliance PowerShell $InsiderRiskPolicies = @(Get-InsiderRiskPolicy -ErrorAction SilentlyContinue) if ($InsiderRiskPolicies) { Section -Style Heading2 'Insider Risk Management Policies' { #region Coverage flags pre-scan # InsiderRiskScenario real enum values: # IntellectualPropertyTheft, DepartingEmployeeSPV, LeakOfInformation, # DisgruntledEmployeeDataLeak, HighValueEmployeeDataLeak, SecurityPolicyViolation, # WorkplaceThreat, RiskyAIUsage etc. $HasDataTheftPolicy = $InsiderRiskPolicies | Where-Object { $_.InsiderRiskScenario -match 'Theft|DepartingEmployeeSPV|HighValueEmployee' } $HasDataLeakPolicy = $InsiderRiskPolicies | Where-Object { $_.InsiderRiskScenario -match 'LeakOfInformation|DataLeak|UnacceptableUsage' } # TenantSettings contains anonymization config as a JSON string $HasAnonymization = $InsiderRiskPolicies | Where-Object { $_.TenantSettings -match 'Anonymization' } $CovObj = [System.Collections.ArrayList]::new() $_pre_PoliciesConfigured_52 = if ($InsiderRiskPolicies.Count -gt 0) { 'Yes' } else { 'No' } $_pre_DataTheftPolicy_53 = if ($null -ne $HasDataTheftPolicy) { 'Yes' } else { 'No' } $_pre_DataLeakPolicy_54 = if ($null -ne $HasDataLeakPolicy) { 'Yes' } else { 'No' } $_pre_AnonymizationEnabled_55 = if ($null -ne $HasAnonymization) { 'Yes' } else { 'No' } $covInObj = [ordered] @{ 'Policies Configured' = $_pre_PoliciesConfigured_52 'Data Theft Policy' = $_pre_DataTheftPolicy_53 'Data Leak Policy' = $_pre_DataLeakPolicy_54 'Anonymization Enabled' = $_pre_AnonymizationEnabled_55 } $CovObj.Add([pscustomobject]$covInObj) | Out-Null if ($Healthcheck -and $script:HealthCheck.Purview.InsiderRisk) { $CovObj | Where-Object { $_.'Policies Configured' -eq 'No' } | Set-Style -Style Critical | Out-Null $CovObj | Where-Object { $_.'Anonymization Enabled' -eq 'No' } | Set-Style -Style Warning | Out-Null } $CovTableParams = @{ Name = "Insider Risk Coverage - $TenantId"; List = $true; ColumnWidths = 55, 45 } if ($script:Report.ShowTableCaptions) { $CovTableParams['Caption'] = "- $($CovTableParams.Name)" } $CovObj | Table @CovTableParams #endregion $OutObj = [System.Collections.ArrayList]::new() # Filter out internal TenantSetting objects - only show real policies $ActualPolicies = $InsiderRiskPolicies | Where-Object { $_.InsiderRiskScenario -ne 'TenantSetting' -and $_.Type -ne 'TenantSetting' } foreach ($Policy in $ActualPolicies) { try { $irmCreated = if ($Policy.WhenCreatedUTC) { $Policy.WhenCreatedUTC.ToString('yyyy-MM-dd') } else { 'N/A' } $irmModified = if ($Policy.WhenChangedUTC) { $Policy.WhenChangedUTC.ToString('yyyy-MM-dd') } else { 'N/A' } $_pre_Anonymized_83 = if ($Policy.TenantSettings -match 'Anonymization.*true') { 'Yes' } else { 'No' } $inObj = [ordered] @{ 'Policy Name' = $Policy.Name 'Scenario' = $Policy.InsiderRiskScenario 'Status' = if ($Policy.Enabled) { 'Enabled' } else { 'Disabled' } 'Mode' = $Policy.Mode 'Anonymized' = $_pre_Anonymized_83 'Created' = $irmCreated } $OutObj.Add([pscustomobject]$inObj) | Out-Null } catch { Write-PScriboMessage -IsWarning -Message "Insider Risk Policy '$($Policy.Name)': $($_.Exception.Message)" | Out-Null } } if ($Healthcheck -and $script:HealthCheck.Purview.InsiderRisk) { $OutObj | Where-Object { $_.'Status' -ne 'Enabled' } | Set-Style -Style Warning | Out-Null } $TableParams = @{ Name = "Insider Risk Policies - $TenantId" List = $false ColumnWidths = 24, 24, 10, 12, 12, 18 } if ($script:Report.ShowTableCaptions) { $TableParams['Caption'] = "- $($TableParams.Name)" } $OutObj | Sort-Object -Property 'Policy Name' | Table @TableParams #region ACSC Inline Check — Insider Risk Policies if ($script:InfoLevel.InsiderRisk -ge 3) { Write-AbrPurviewACSCCheck -TenantId $TenantId -SectionName 'Insider Risk Policies' -Checks @( [pscustomobject]@{ ControlId = 'ISM-1228' E8 = 'E8 ML2, ML3' Description = 'Cyber security events analysed to identify incidents' Check = 'Insider Risk Management policies configured to detect anomalous behaviour' Status = if ($InsiderRiskPolicies.Count -gt 0) { 'Pass' } else { 'Fail' } } ) } #endregion } } else { Write-PScriboMessage -Message "No Insider Risk Policy information found for $TenantId. Disabling section." | Out-Null } } catch { Write-PScriboMessage -IsWarning -Message "Insider Risk Policy Section: $($_.Exception.Message)" | Out-Null } # Insider Risk Global Settings have no public PowerShell cmdlet. # Settings are only configurable via the Microsoft Purview portal. } end { Show-AbrDebugExecutionTime -End -TitleMessage 'Insider Risk' } } |