Src/Private/Get-AbrIntuneDefender.ps1
|
function Get-AbrIntuneDefender { <# .SYNOPSIS Documents Microsoft Defender for Endpoint (MDE) integration and configuration in Intune. .DESCRIPTION Collects and reports on: - MDE connector state (Intune <-> Defender integration) - Mobile Threat Defence (MTD) connectors - Defender for Endpoint compliance policy settings per platform - Defender Antivirus policy summary (from Endpoint Security) - BitLocker / Disk Encryption policy summary - Windows Defender Firewall policy summary - Attack Surface Reduction (ASR) policy summary - MDE onboarding status summary .NOTES Version: 0.1.0 Author: Pai Wei Sing #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string]$TenantId ) begin { Write-PScriboMessage -Message "Collecting Microsoft Defender for Endpoint configuration for $TenantId." Show-AbrDebugExecutionTime -Start -TitleMessage 'Defender for Endpoint' } process { # ── MDE Connector (Intune <-> Defender integration) ──────────────────── try { Write-Host " - Retrieving Microsoft Defender for Endpoint connector settings..." $MDEConnResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/mobileThreatDefenseConnectors" ` -ErrorAction SilentlyContinue $MDEConnectors = if ($MDEConnResp.value) { $MDEConnResp.value } else { @() } # MDE Intune connector settings $MDEIntuneConnResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/advancedThreatProtectionOnboardingStateSummary" ` -ErrorAction SilentlyContinue BlankLine Section -Style Heading2 'Microsoft Defender for Endpoint Connector' { Paragraph "The following documents the Microsoft Defender for Endpoint (MDE) integration with Intune for tenant $TenantId. This integration enables device risk-based compliance enforcement and conditional access." BlankLine # The real MDE connector settings are embedded in the MTD connector for 'MicrosoftDefenderATP' $MDEConnector = $MDEConnectors | Where-Object { $_.partnerAppId -like '*MicrosoftDefenderATP*' -or $_.partnerFriendlyName -like '*Defender*' -or $_.partnerFriendlyName -like '*ATP*' } | Select-Object -First 1 $ConnRows = [System.Collections.ArrayList]::new() # Endpoint Security Profile Settings $ConnRows.Add([pscustomobject]@{ Setting = 'Endpoint Security Profile Settings'; Value = '' }) | Out-Null if ($MDEConnector) { $connState = switch ($MDEConnector.partnerState) { 'available' { 'Connected' } 'notSetUp' { 'Not Set Up' } 'error' { 'Error' } 'unresponsive' { 'Unresponsive' } default { if ($MDEConnector.partnerState) { $MDEConnector.partnerState } else { 'Not Connected' } } } $ConnRows.Add([pscustomobject]@{ Setting = 'Connector Status'; Value = $connState }) | Out-Null # Allow MDE to enforce endpoint security configurations — correct field is microsoftDefenderForEndpointMobileNetworkDefenseEnabled # The previous mapping to allowPartnerToCollectIOSApplicationMetadata was incorrect if ($null -ne $MDEConnector.microsoftDefenderForEndpointAttachEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Allow Microsoft Defender for Endpoint to Enforce Endpoint Security Configurations'; Value = if ($MDEConnector.microsoftDefenderForEndpointAttachEnabled) { 'On' } else { 'Off' } }) | Out-Null } # Compliance Policy Evaluation $ConnRows.Add([pscustomobject]@{ Setting = 'Compliance Policy Evaluation'; Value = '' }) | Out-Null if ($null -ne $MDEConnector.androidEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect Android Devices to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.androidEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.iosEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect iOS/iPadOS Devices to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.iosEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.windowsEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect Windows Devices (10.0.15063+) to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.windowsEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.macEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect macOS Devices to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.macEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.linuxEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect Linux Devices to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.linuxEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.androidDeviceAdministratorEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect Android Device Administrator to Microsoft Defender for Endpoint'; Value = if ($MDEConnector.androidDeviceAdministratorEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.allowPartnerToCollectIOSApplicationMetadata) { $ConnRows.Add([pscustomobject]@{ Setting = 'Enable App Sync (iOS/iPadOS Application Inventory)'; Value = if ($MDEConnector.allowPartnerToCollectIOSApplicationMetadata) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.allowPartnerToCollectPersonalIOSApplicationMetadata) { $ConnRows.Add([pscustomobject]@{ Setting = 'Send Full Application Inventory (Personal iOS/iPadOS)'; Value = if ($MDEConnector.allowPartnerToCollectPersonalIOSApplicationMetadata) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.iosTunnelEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Enable Certificate Sync for iOS/iPadOS'; Value = if ($MDEConnector.iosTunnelEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.windowsDeviceBlockedOnMissingPartnerData) { $ConnRows.Add([pscustomobject]@{ Setting = 'Block Unsupported OS Versions'; Value = if ($MDEConnector.windowsDeviceBlockedOnMissingPartnerData) { 'On' } else { 'Off' } }) | Out-Null } # App protection policy evaluation $ConnRows.Add([pscustomobject]@{ Setting = 'App Protection Policy Evaluation'; Value = '' }) | Out-Null if ($null -ne $MDEConnector.androidMobileApplicationManagementEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect Android Devices to MDE (App Protection)'; Value = if ($MDEConnector.androidMobileApplicationManagementEnabled) { 'On' } else { 'Off' } }) | Out-Null } if ($null -ne $MDEConnector.iosMobileApplicationManagementEnabled) { $ConnRows.Add([pscustomobject]@{ Setting = 'Connect iOS/iPadOS Devices to MDE (App Protection)'; Value = if ($MDEConnector.iosMobileApplicationManagementEnabled) { 'On' } else { 'Off' } }) | Out-Null } # Shared Settings $ConnRows.Add([pscustomobject]@{ Setting = 'Shared Settings'; Value = '' }) | Out-Null if ($null -ne $MDEConnector.partnerUnresponsivenessThresholdInDays) { $ConnRows.Add([pscustomobject]@{ Setting = 'Number of Days Until Partner is Unresponsive'; Value = "$($MDEConnector.partnerUnresponsivenessThresholdInDays)" }) | Out-Null } # Last heartbeat if ($MDEConnector.lastHeartbeatDateTime) { $ConnRows.Add([pscustomobject]@{ Setting = 'Last Heartbeat'; Value = ([datetime]$MDEConnector.lastHeartbeatDateTime).ToString('yyyy-MM-dd HH:mm') }) | Out-Null } } else { $ConnRows.Add([pscustomobject]@{ Setting = 'Connector Status'; Value = 'Not Connected / Not Configured' }) | Out-Null } # Style section header rows $connHeaders = @('Endpoint Security Profile Settings', 'Compliance Policy Evaluation', 'App Protection Policy Evaluation', 'Shared Settings') $null = ($ConnRows | Where-Object { $_.Setting -in $connHeaders } | Set-Style -Style 'TableSectionHeader') $ConnParams = @{ Name = "MDE Connector Settings - $TenantId"; ColumnWidths = 62, 38 } if ($Report.ShowTableCaptions) { $ConnParams['Caption'] = "- $($ConnParams.Name)" } $ConnRows | Table @ConnParams # ── MDE Onboarding Status ─────────────────────────────────────── if ($MDEIntuneConnResp -and $null -ne $MDEIntuneConnResp.enrolledDeviceCount) { BlankLine Paragraph "Microsoft Defender for Endpoint Onboarding Status:" BlankLine $OnbRows = [System.Collections.ArrayList]::new() if ($null -ne $MDEIntuneConnResp.enrolledDeviceCount) { $OnbRows.Add([pscustomobject]@{ Setting = 'Enrolled / Onboarded Devices'; Value = "$($MDEIntuneConnResp.enrolledDeviceCount)" }) | Out-Null } if ($null -ne $MDEIntuneConnResp.notOnboardedDeviceCount) { $OnbRows.Add([pscustomobject]@{ Setting = 'Devices Not Onboarded'; Value = "$($MDEIntuneConnResp.notOnboardedDeviceCount)" }) | Out-Null } if ($null -ne $MDEIntuneConnResp.pendingDeviceCount) { $OnbRows.Add([pscustomobject]@{ Setting = 'Pending Onboarding'; Value = "$($MDEIntuneConnResp.pendingDeviceCount)" }) | Out-Null } if ($OnbRows.Count -gt 0) { $OnbParams = @{ Name = "MDE Onboarding Status - $TenantId"; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $OnbParams['Caption'] = "- $($OnbParams.Name)" } $OnbRows | Table @OnbParams } } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'MDE Connector' -RequiredRole 'DeviceManagementServiceConfig.Read.All' } else { Write-AbrSectionError -Section 'MDE Connector' -Message "$($_.Exception.Message)" } } # ── Mobile Threat Defence (MTD) Connectors ───────────────────────────── try { Write-Host " - Retrieving Mobile Threat Defence connectors..." $MTDResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/mobileThreatDefenseConnectors" ` -ErrorAction SilentlyContinue $MTDConnectors = if ($MTDResp.value) { $MTDResp.value } else { @() } if ($MTDConnectors -and @($MTDConnectors).Count -gt 0) { BlankLine Section -Style Heading2 'Mobile Threat Defence Connectors' { Paragraph "The following documents all Mobile Threat Defence (MTD) partner connectors configured in tenant $TenantId." BlankLine $MTDObj = [System.Collections.ArrayList]::new() foreach ($MTD in ($MTDConnectors | Sort-Object partnerFriendlyName)) { $state = switch ($MTD.partnerState) { 'available' { 'Connected' } 'notSetUp' { 'Not Set Up' } 'error' { 'Error' } 'unresponsive' { 'Unresponsive' } default { if ($MTD.partnerState) { $MTD.partnerState } else { '--' } } } $MTDObj.Add([pscustomobject]([ordered]@{ 'Partner' = if ($MTD.partnerFriendlyName) { $MTD.partnerFriendlyName } else { $MTD.partnerAppId } 'State' = $state 'Android Enabled' = if ($null -ne $MTD.androidEnabled) { if ($MTD.androidEnabled) { 'Yes' } else { 'No' } } else { '--' } 'iOS Enabled' = if ($null -ne $MTD.iosEnabled) { if ($MTD.iosEnabled) { 'Yes' } else { 'No' } } else { '--' } 'Windows Enabled' = if ($null -ne $MTD.windowsEnabled) { if ($MTD.windowsEnabled) { 'Yes' } else { 'No' } } else { '--' } 'Last Heartbeat' = if ($MTD.lastHeartbeatDateTime) { ([datetime]$MTD.lastHeartbeatDateTime).ToString('yyyy-MM-dd') } else { '--' } })) | Out-Null } $MTDParams = @{ Name = "MTD Connectors - $TenantId"; ColumnWidths = 25, 14, 14, 12, 14, 21 } if ($Report.ShowTableCaptions) { $MTDParams['Caption'] = "- $($MTDParams.Name)" } $MTDObj | Table @MTDParams } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'MTD Connectors' -RequiredRole 'DeviceManagementServiceConfig.Read.All' } else { Write-AbrSectionError -Section 'MTD Connectors' -Message "$($_.Exception.Message)" } } # ── Defender Endpoint Security Policies (Antivirus, Firewall, EDR, ASR, Encryption) ── try { Write-Host " - Retrieving Defender Endpoint Security policies..." $DefESResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/configurationPolicies?`$expand=assignments" ` -ErrorAction SilentlyContinue $AllDefPolicies = if ($DefESResp.value) { $DefESResp.value } else { @() } while ($DefESResp -and $DefESResp.'@odata.nextLink') { $DefESResp = Invoke-MgGraphRequest -Method GET -Uri $DefESResp.'@odata.nextLink' -ErrorAction SilentlyContinue if ($DefESResp.value) { $AllDefPolicies += $DefESResp.value } } # Filter to Defender-relevant endpoint security policy families $DefenderFamilies = @('*antivirus*', '*endpointDetection*', '*attackSurface*', '*diskEncryption*', '*firewall*', '*accountProtection*') $DefPolicies = $AllDefPolicies | Where-Object { $family = $_.templateReference.templateFamily $family -and $family -ne 'none' -and ($DefenderFamilies | Where-Object { $family -like $_ }) } if ($DefPolicies -and @($DefPolicies).Count -gt 0) { BlankLine Section -Style Heading2 'Defender Endpoint Security Policies' { Paragraph "The following documents all Microsoft Defender endpoint security policies configured in tenant $TenantId, grouped by policy type." BlankLine $PolicyGroups = $DefPolicies | Group-Object { $_.templateReference.templateFamily } foreach ($Group in ($PolicyGroups | Sort-Object Name)) { $GroupLabel = switch -Wildcard ($Group.Name) { '*antivirus*' { 'Antivirus' } '*diskEncryption*' { 'Disk Encryption (BitLocker)' } '*firewall*' { 'Firewall' } '*endpointDetection*' { 'Endpoint Detection & Response (EDR)' } '*attackSurface*' { 'Attack Surface Reduction (ASR)' } '*accountProtection*' { 'Account Protection' } default { $Group.Name } } BlankLine Paragraph "$GroupLabel ($(@($Group.Group).Count) policy/policies):" BlankLine $DefPolObj = [System.Collections.ArrayList]::new() foreach ($Pol in ($Group.Group | Sort-Object name)) { $assignResolved = Resolve-IntuneAssignments -Assignments $Pol.assignments -CheckMemberCount:$script:CheckEmptyGroups $Platform = switch ($Pol.platforms) { 'windows10' { 'Windows 10/11' } 'macOS' { 'macOS' } 'linux' { 'Linux' } default { if ($Pol.platforms) { $Pol.platforms } else { '--' } } } $DefPolObj.Add([pscustomobject]([ordered]@{ 'Policy Name' = $Pol.name 'Platform' = $Platform 'Assignments' = $assignResolved.AssignmentSummary 'Last Modified' = if ($Pol.lastModifiedDateTime) { ([datetime]$Pol.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } })) | Out-Null } $null = (& { if ($HealthCheck.Intune.EndpointSecurity) { $null = ($DefPolObj | Where-Object { $_.'Assignments' -eq 'Not assigned' } | Set-Style -Style Warning | Out-Null) } }) $DefPolParams = @{ Name = "$GroupLabel Policies - $TenantId"; ColumnWidths = 37, 18, 28, 17 } if ($Report.ShowTableCaptions) { $DefPolParams['Caption'] = "- $($DefPolParams.Name)" } $DefPolObj | Table @DefPolParams # Per-policy settings detail at InfoLevel 2 if ($InfoLevel.EndpointSecurity -ge 2) { foreach ($Pol in ($Group.Group | Sort-Object name)) { $assignResolved = Resolve-IntuneAssignments -Assignments $Pol.assignments Section -Style Heading3 $Pol.name { BlankLine $PolDetailObj = [System.Collections.ArrayList]::new() $PolDetailObj.Add([pscustomobject]@{ Setting = 'Policy Name'; Value = $Pol.name }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Description'; Value = if ($Pol.description) { $Pol.description } else { '--' } }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Platform'; Value = if ($Pol.platforms) { $Pol.platforms } else { '--' } }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Policy Type'; Value = $GroupLabel }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Included Groups'; Value = $assignResolved.IncludedGroups }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Excluded Groups'; Value = $assignResolved.ExcludedGroups }) | Out-Null $PolDetailObj.Add([pscustomobject]@{ Setting = 'Last Modified'; Value = if ($Pol.lastModifiedDateTime) { ([datetime]$Pol.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } }) | Out-Null $PolDetailParams = @{ Name = "Policy Detail - $($Pol.name)"; ColumnWidths = 30, 70 } if ($Report.ShowTableCaptions) { $PolDetailParams['Caption'] = "- $($PolDetailParams.Name)" } $PolDetailObj | Table @PolDetailParams # Fetch settings — full renderer with all 5 instance types $DefSetResp = $null try { $DefSetResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceManagement/configurationPolicies/$($Pol.id)/settings?`$expand=settingDefinitions" ` -ErrorAction Stop } catch { Write-AbrDebugLog "Defender settings unavailable for '$($Pol.name)': $($_.Exception.Message)" 'WARN' 'Defender' } if ($DefSetResp -and $DefSetResp.value -and @($DefSetResp.value).Count -gt 0) { $DefPolicySettings = $DefSetResp.value $DefResolveName = { param($defId, $defsColl) if ($defsColl) { $m = $defsColl | Where-Object { $_.id -eq $defId } | Select-Object -First 1; if ($m -and $m.displayName) { return $m.displayName } } $part = $defId -replace '^.*_policy_config_[^_]+_','' -replace '^.*_policy_','' -replace '^[^_]+_[^_]+_[^_]+_[^_]+_','' $s = $part -creplace '([a-z])([A-Z])','$1 $2' -replace '_',' ' return ($s.Substring(0,1).ToUpper() + $s.Substring(1)) } $DefResolveCategory = { param($defId, $defsColl) if ($defsColl) { $m = $defsColl | Where-Object { $_.id -eq $defId } | Select-Object -First 1 if ($m -and $m.categoryId) { $catId = $m.categoryId if ($catId -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') { if (-not $script:CatGuidNameCache) { $script:CatGuidNameCache = [System.Collections.Generic.Dictionary[string,string]]::new([System.StringComparer]::OrdinalIgnoreCase) } if ($script:CatGuidNameCache.ContainsKey($catId)) { return $script:CatGuidNameCache[$catId] } try { $catApiResp = $null try { $catApiResp = Invoke-MgGraphRequest -Method GET -Uri "$($script:GraphEndpoint)/beta/deviceManagement/configurationCategories/$catId`?`$select=displayName" -ErrorAction Stop } catch { } $catDn = if ($catApiResp -is [System.Collections.IDictionary]) { $catApiResp['displayName'] } else { $catApiResp.displayName } if ($catDn) { $script:CatGuidNameCache[$catId] = $catDn; return $catDn } } catch { } $script:CatGuidNameCache[$catId] = $catId; return $catId } $cat = $catId -replace '^.*_config_','' -replace '_',' '; $cat = $cat -creplace '([a-z])([A-Z])','$1 $2'; return ($cat.Substring(0,1).ToUpper() + $cat.Substring(1)) } } if ($defId -match '_policy_config_([^_]+)_') { $cat = $Matches[1] -creplace '([a-z])([A-Z])','$1 $2' -replace '_',' '; return ($cat.Substring(0,1).ToUpper() + $cat.Substring(1)) } return 'General' } $DefRenderChoice = { param($choiceVal, $defsColl) if (-not $choiceVal -or -not $choiceVal.value) { return '--' } $raw = $choiceVal.value -replace '^.*_','' $label = switch ($raw) { '0' { 'Disabled' } '1' { 'Enabled' } '2' { 'Audit Mode' } '3' { 'Block' } 'true' { 'Enabled' } 'false' { 'Disabled' } 'enabled' { 'Enabled' } 'disabled' { 'Disabled' } 'allowed' { 'Allowed' } 'blocked' { 'Blocked' } 'notConfigured' { 'Not Configured' } 'warn' { 'Warn' } 'auditMode' { 'Audit Mode' } 'blockMode' { 'Block' } 'userDefined' { 'User Defined' } default { $t = $raw -creplace '([a-z])([A-Z])','$1 $2'; $t.Substring(0,1).ToUpper() + $t.Substring(1) } } if ($choiceVal.children -and $choiceVal.children.Count -gt 0) { $parts = @(); foreach ($child in $choiceVal.children) { $cName = & $DefResolveName $child.settingDefinitionId $defsColl $cVal = if ($child.simpleSettingValue) { "$($child.simpleSettingValue.value)" } elseif ($child.simpleSettingCollectionValue) { ($child.simpleSettingCollectionValue | ForEach-Object { $_.value }) -join '; ' } else { '' } if ($cVal) { $parts += "$cName`: $cVal" } } if ($parts.Count -gt 0) { $label = "$label`n" + ($parts -join "`n") } } return $label } $DefRenderGroup = { param($groupVal, $defsColl) if (-not $groupVal) { return '--' } $parts = @() foreach ($grp in $groupVal) { if ($grp.children) { foreach ($child in $grp.children) { $cName = & $DefResolveName $child.settingDefinitionId $defsColl $cVal = if ($child.choiceSettingValue) { & $DefRenderChoice $child.choiceSettingValue $defsColl } elseif ($child.simpleSettingValue) { "$($child.simpleSettingValue.value)" } elseif ($child.simpleSettingCollectionValue) { ($child.simpleSettingCollectionValue | ForEach-Object { $_.value }) -join '; ' } else { '' } if ($cVal -and $cVal -ne 'Not Configured') { $parts += "$cName`: $cVal" } } } } $renderResult = if ($parts.Count -gt 0) { $parts -join "`n" } else { 'Configured' } return $renderResult } $defCatGroups = [ordered]@{} foreach ($setting in $DefPolicySettings) { $instance = $setting.settingInstance; if (-not $instance) { continue } $defs = $setting.settingDefinitions $defName = & $DefResolveName $instance.settingDefinitionId $defs $category = & $DefResolveCategory $instance.settingDefinitionId $defs $sv = switch -Wildcard ($instance.'@odata.type') { '*choiceSettingInstance' { & $DefRenderChoice $instance.choiceSettingValue $defs } '*simpleSettingInstance' { if ($instance.simpleSettingValue) { "$($instance.simpleSettingValue.value)" } else { '--' } } '*simpleSettingCollectionInstance' { if ($instance.simpleSettingCollectionValue) { ($instance.simpleSettingCollectionValue | ForEach-Object { $_.value }) -join ', ' } else { '--' } } '*groupSettingCollectionInstance' { & $DefRenderGroup $instance.groupSettingCollectionValue $defs } '*choiceSettingCollectionInstance' { if ($instance.choiceSettingCollectionValue) { ($instance.choiceSettingCollectionValue | ForEach-Object { ($_.value -replace '^.*_','') }) -join ', ' } else { '--' } } default { '--' } } if ($sv -eq '--' -or $sv -eq 'Not Configured' -or [string]::IsNullOrWhiteSpace($sv)) { continue } if (-not $defCatGroups.Contains($category)) { $defCatGroups[$category] = [System.Collections.ArrayList]::new() } $defCatGroups[$category].Add([pscustomobject]([ordered]@{ 'Setting' = $defName; 'Value' = $sv })) | Out-Null } if ($defCatGroups.Count -gt 0) { $allDefRows = [System.Collections.ArrayList]::new() foreach ($cat in $defCatGroups.Keys) { $allDefRows.Add([pscustomobject]([ordered]@{ 'Setting' = $cat; 'Value' = '' })) | Out-Null $allDefRows.AddRange($defCatGroups[$cat]) } BlankLine Paragraph "Configured Settings ($(@($allDefRows | Where-Object { $_.Value -ne '' }).Count) setting(s)):" BlankLine $null = ($allDefRows | Where-Object { $_.Value -eq '' } | Set-Style -Style 'TableSectionHeader') $DefSetParams = @{ Name = "Settings - $($Pol.name)"; ColumnWidths = 50, 50 } if ($Report.ShowTableCaptions) { $DefSetParams['Caption'] = "- $($DefSetParams.Name)" } $allDefRows | Table @DefSetParams } else { Paragraph "No explicitly configured settings found (all values are at template defaults)." } } } } } } # Excel export if (Get-IntuneExcelSheetEnabled -SheetKey 'EndpointSecurity') { $DefExcelObj = $DefPolicies | 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 { '--' } } } if (-not $script:ExcelSheets.Contains('Defender Policies')) { $script:ExcelSheets['Defender Policies'] = $DefExcelObj } } } } else { BlankLine Section -Style Heading2 'Defender Endpoint Security Policies' { Paragraph "No Defender Endpoint Security policies (Antivirus, Firewall, EDR, ASR, Disk Encryption) found in tenant $TenantId." } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Defender Endpoint Security Policies' -RequiredRole 'DeviceManagementConfiguration.Read.All' } else { Write-AbrSectionError -Section 'Defender Endpoint Security Policies' -Message "$($_.Exception.Message)" } } } end { Show-AbrDebugExecutionTime -End -TitleMessage 'Defender for Endpoint' } } |