Src/Private/Get-AbrIntuneEndpointSecurity.ps1
|
function Get-AbrIntuneEndpointSecurity { <# .SYNOPSIS Documents Intune Endpoint Security policies (Antivirus, Firewall, Disk Encryption, EDR, ASR). .DESCRIPTION Collects and reports on: - Antivirus policies - Disk Encryption policies - Firewall policies - Endpoint Detection and Response (EDR) policies - Attack Surface Reduction (ASR) policies - Account Protection policies .NOTES Version: 0.1.0 Author: Pai Wei Sing #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string]$TenantId ) begin { Write-PScriboMessage -Message "Collecting Intune Endpoint Security policies for $TenantId." Show-AbrDebugExecutionTime -Start -TitleMessage 'Endpoint Security' } process { Section -Style Heading2 'Endpoint Security' { Paragraph "The following section documents Endpoint Security policies configured in tenant $TenantId." BlankLine try { Write-Host " - Retrieving Endpoint Security policies..." # Endpoint Security policies use the configurationPolicies endpoint with specific templateFamilies # /beta required -- v1.0 configurationPolicies does not support $filter on templateReference # Also $filter on templateFamily not supported server-side in v1.0; filter client-side instead $ESPoliciesResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/configurationPolicies?`$expand=assignments" ` -ErrorAction SilentlyContinue $AllConfigPolicies = $ESPoliciesResp.value # Page through all results while ($ESPoliciesResp -and $ESPoliciesResp.'@odata.nextLink') { $ESPoliciesResp = Invoke-MgGraphRequest -Method GET -Uri $ESPoliciesResp.'@odata.nextLink' -ErrorAction SilentlyContinue if ($ESPoliciesResp.value) { $AllConfigPolicies += $ESPoliciesResp.value } } # Filter client-side: keep only endpoint security policies (non-'none' templateFamily) $ESPolicies = $AllConfigPolicies | Where-Object { $_.templateReference -and $_.templateReference.templateFamily -and $_.templateReference.templateFamily -ne 'none' -and $_.templateReference.templateFamily -ne '' } if ($ESPolicies -and @($ESPolicies).Count -gt 0) { # Group by templateFamily $PolicyGroups = $ESPolicies | Group-Object { $_.templateReference.templateFamily } foreach ($Group in ($PolicyGroups | Sort-Object Name)) { $GroupLabel = switch -Wildcard ($Group.Name) { '*antivirus*' { 'Antivirus' } '*diskEncryption*' { 'Disk Encryption' } '*firewall*' { 'Firewall' } '*endpointDetection*' { 'Endpoint Detection & Response (EDR)' } '*attackSurface*' { 'Attack Surface Reduction (ASR)' } '*accountProtection*' { 'Account Protection' } default { $Group.Name } } Section -Style Heading3 "$GroupLabel Policies" { BlankLine $EPObj = [System.Collections.ArrayList]::new() foreach ($ESPolicy in ($Group.Group | Sort-Object name)) { $Platform = switch ($ESPolicy.platforms) { 'windows10' { 'Windows 10/11' } 'macOS' { 'macOS' } 'linux' { 'Linux' } default { if ($ESPolicy.platforms) { $ESPolicy.platforms } else { '--' } } } $assignResolved = Resolve-IntuneAssignments -Assignments $ESPolicy.assignments -CheckMemberCount:$script:CheckEmptyGroups $AssignedTo = $assignResolved.AssignmentSummary $epInObj = [ordered] @{ 'Policy Name' = $ESPolicy.name 'Platform' = $Platform 'Assignments' = $AssignedTo 'Last Modified' = if ($ESPolicy.lastModifiedDateTime) { ([datetime]$ESPolicy.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } } $EPObj.Add([pscustomobject]$epInObj) | Out-Null } $null = (& { if ($HealthCheck.Intune.EndpointSecurity) { $null = ($EPObj | Where-Object { $_.'Assignments' -eq 'Not assigned' } | Set-Style -Style Warning | Out-Null) } }) $EPTableParams = @{ Name = "$GroupLabel - $TenantId"; ColumnWidths = 35, 20, 28, 17 } if ($Report.ShowTableCaptions) { $EPTableParams['Caption'] = "- $($EPTableParams.Name)" } $EPObj | Table @EPTableParams } } # Excel export (flattened) if (Get-IntuneBackupSectionEnabled -SectionKey 'EndpointSecurity') { $script:BackupData['EndpointSecurity'] = $ESPolicies } #region InfoLevel 2 -- per-policy detail + settings if ($InfoLevel.EndpointSecurity -ge 2) { foreach ($ESPolicy in ($ESPolicies | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $ESPolicy.assignments $templateFamily = if ($ESPolicy.templateReference.templateFamily) { $ESPolicy.templateReference.templateFamily } else { '--' } Section -Style Heading3 $ESPolicy.displayName { BlankLine $ovObj = [System.Collections.ArrayList]::new() $ovObj.Add([pscustomobject]@{ Setting = 'Policy Name'; Value = $ESPolicy.displayName }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Description'; Value = if ($ESPolicy.description) { $ESPolicy.description } else { '--' } }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Platform'; Value = if ($ESPolicy.platforms) { $ESPolicy.platforms } else { '--' } }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Template Family'; Value = $templateFamily }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Included Groups'; Value = $assignResolved.IncludedGroups }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Excluded Groups'; Value = $assignResolved.ExcludedGroups }) | Out-Null $ovObj.Add([pscustomobject]@{ Setting = 'Last Modified'; Value = if ($ESPolicy.lastModifiedDateTime) { ([datetime]$ESPolicy.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null $OvParams = @{ Name = "Policy Detail - $($ESPolicy.displayName)"; ColumnWidths = 30, 70 } if ($Report.ShowTableCaptions) { $OvParams['Caption'] = "- $($OvParams.Name)" } $ovObj | Table @OvParams # Fetch settings try { $EsSetResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/configurationPolicies/$($ESPolicy.id)/settings?`$expand=settingDefinitions" ` -ErrorAction SilentlyContinue $EsSettings = $EsSetResp.value if ($EsSettings -and @($EsSettings).Count -gt 0) { $esSetRows = [System.Collections.ArrayList]::new() foreach ($setting in $EsSettings) { $instance = $setting.settingInstance if (-not $instance) { continue } $defName = if ($instance.settingDefinitionId) { ($instance.settingDefinitionId -split '_' | Select-Object -Last 1) -creplace '([A-Z])', ' $1' -replace '^\s+','' } else { '--' } $val = switch -Wildcard ($instance.'@odata.type') { '*choiceSettingInstance' { if ($instance.choiceSettingValue.value) { $instance.choiceSettingValue.value -replace '^.*_','' } else { '--' } } '*simpleSettingInstance' { if ($null -ne $instance.simpleSettingValue.value) { "$($instance.simpleSettingValue.value)" } else { '--' } } '*simpleSettingCollectionInstance' { if ($instance.simpleSettingCollectionValue) { ($instance.simpleSettingCollectionValue | ForEach-Object { $_.value }) -join ', ' } else { '--' } } default { '--' } } if ($val -in @('--','notConfigured','notSet')) { continue } if ($val.Length -gt 80) { $val = "$($val.Substring(0,80))..." } $esSetRows.Add([pscustomobject]([ordered]@{ 'Setting' = $defName 'Value' = $val })) | Out-Null } if ($esSetRows.Count -gt 0) { BlankLine Paragraph "Configured Settings ($($esSetRows.Count) setting(s)):" BlankLine $EsSetParams = @{ Name = "Settings - $($ESPolicy.displayName)"; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $EsSetParams['Caption'] = "- $($EsSetParams.Name)" } $esSetRows | Table @EsSetParams } } } catch { Paragraph "Could not retrieve settings: $($_.Exception.Message)" } } } } #endregion if (Get-IntuneExcelSheetEnabled -SheetKey 'EndpointSecurity') { $ESExcelObj = $ESPolicies | ForEach-Object { [pscustomobject]@{ 'Policy Name' = $_.name 'Platform' = $_.platforms 'Template Family' = $_.templateReference.templateFamily 'Assignments' = if ($_.assignments) { @($_.assignments).Count } else { 0 } 'Last Modified' = if ($_.lastModifiedDateTime) { ([datetime]$_.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } } } $script:ExcelSheets['Endpoint Security'] = $ESExcelObj } } else { Paragraph "No Endpoint Security policies found in tenant $TenantId." } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Endpoint Security' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'Endpoint Security' -Message "$($_.Exception.Message)" } } #region ACSC E8 Assessment if ($script:IncludeACSCe8) { BlankLine Paragraph "ACSC Essential Eight Maturity Level Assessment -- Endpoint Security:" BlankLine try { # Count policies by category from already-collected $ESPolicies $TotalAntivirusPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*antivirus*' }).Count } else { 0 } $TotalFirewallPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*firewall*' }).Count } else { 0 } $TotalDiskEncryptionPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*diskEncryption*' }).Count } else { 0 } $TotalASRPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*attackSurface*' }).Count } else { 0 } $TotalEDRPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*endpointDetection*' }).Count } else { 0 } # Store for other sections $null = ($script:TotalAntivirusPolicies = $TotalAntivirusPolicies) $null = ($script:TotalFirewallPolicies = $TotalFirewallPolicies) $null = ($script:TotalDiskEncryptionPolicies = $TotalDiskEncryptionPolicies) $null = ($script:TotalASRPolicies = $TotalASRPolicies) $null = ($script:TotalEDRPolicies = $TotalEDRPolicies) $_v = @{ TotalAntivirusPolicies = $TotalAntivirusPolicies TotalFirewallPolicies = $TotalFirewallPolicies TotalDiskEncryptionPolicies = $TotalDiskEncryptionPolicies TotalASRPolicies = $TotalASRPolicies TotalEDRPolicies = $TotalEDRPolicies } $E8Checks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneE8Checks -Section 'EndpointSecurity') -Framework E8 -CallerVariables $_v New-AbrIntuneE8AssessmentTable -Checks $E8Checks -Name 'Endpoint Security' -TenantId $TenantId if ($E8Checks) { $null = $script:E8AllChecks.AddRange([object[]](@($E8Checks | Select-Object @{N='Section';E={'EndpointSecurity'}}, ML, Control, Status, Detail))) } } catch { Write-AbrSectionError -Section 'E8 Endpoint Security Assessment' -Message "$($_.Exception.Message)" } } #endregion #region CIS Assessment if ($script:IncludeCISBaseline) { BlankLine Paragraph "CIS Microsoft 365 Foundations Benchmark Assessment -- Endpoint Security:" BlankLine try { $TotalAntivirusPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*antivirus*' }).Count } else { 0 } $TotalFirewallPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*firewall*' }).Count } else { 0 } $TotalDiskEncryptionPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*diskEncryption*' }).Count } else { 0 } $TotalASRPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*attackSurface*' }).Count } else { 0 } $TotalEDRPolicies = if ($ESPolicies) { @($ESPolicies | Where-Object { $_.templateReference.templateFamily -like '*endpointDetection*' }).Count } else { 0 } $_v = @{ TotalAntivirusPolicies = $TotalAntivirusPolicies TotalFirewallPolicies = $TotalFirewallPolicies TotalDiskEncryptionPolicies = $TotalDiskEncryptionPolicies TotalASRPolicies = $TotalASRPolicies TotalEDRPolicies = $TotalEDRPolicies } $CISChecks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneCISChecks -Section 'EndpointSecurity') -Framework CIS -CallerVariables $_v New-AbrIntuneCISAssessmentTable -Checks $CISChecks -Name 'Endpoint Security' -TenantId $TenantId if ($CISChecks) { $null = $script:CISAllChecks.AddRange([object[]](@($CISChecks | Select-Object @{N='Section';E={'EndpointSecurity'}}, CISControl, Level, Status, Detail))) } } catch { Write-AbrSectionError -Section 'CIS Endpoint Security Assessment' -Message "$($_.Exception.Message)" } } #endregion } } end { Show-AbrDebugExecutionTime -End -TitleMessage 'Endpoint Security' } } |