Private/Logic/Get-AsrRules.ps1
|
# Copyright (c) 2026 Sandy Zeng. All rights reserved. # Source-available. All rights reserved. See LICENSE file. <# Get-AsrRules.ps1 — ASR (Attack Surface Reduction) rule display name resolution helpers. Author: Sandy Zeng Project: IntuneDiff Version History: 1.0.0 Initial release. #> function Get-AsrRuleDisplayName { <# .SYNOPSIS Returns the friendly display name for an ASR rule setting definition ID. .DESCRIPTION First tries to resolve the name from the settingDefinitions lookup returned by Graph. Falls back to a built-in substring map for cases where Graph returns a null or missing displayName. .PARAMETER SettingDefinitionId The raw setting definition ID from Graph. .PARAMETER DefinitionsLookup Optional hashtable of settingDefinitionId -> definition object from Graph. #> [CmdletBinding()] [OutputType([string])] param( [string]$SettingDefinitionId, [hashtable]$DefinitionsLookup ) # Primary: use displayName from the settingDefinitions array returned by Graph. # Graph includes child ASR definitions inline, so this works most of the time. if ($DefinitionsLookup -and $DefinitionsLookup.ContainsKey($SettingDefinitionId)) { $def = $DefinitionsLookup[$SettingDefinitionId] if ($def.displayName) { return [string]$def.displayName } } # Fallback: Graph can return null/missing displayName for ASR child settings depending # on the API version or policy type (observed with some Settings Catalog responses). # Match on the setting definition ID substring instead — identical approach to v2 backend. $id = $SettingDefinitionId.ToLowerInvariant() if ($id.Contains('blockexecutionofpotentiallyobfuscatedscripts')) { return 'Block execution of potentially obfuscated scripts' } if ($id.Contains('blockwin32apicallsfromofficemacros')) { return 'Block Win32 API calls from Office macros' } if ($id.Contains('blockadobereaderfromcreatingchildprocesses')) { return 'Block Adobe Reader from creating child processes' } if ($id.Contains('blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem')) { return 'Block credential stealing from the Windows local security authority subsystem' } if ($id.Contains('blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion')) { return 'Block executable files from running unless they meet a prevalence, age, or trusted list criterion' } if ($id.Contains('blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent')) { return 'Block JavaScript or VBScript from launching downloaded executable content' } if ($id.Contains('blockofficecommunicationappfromcreatingchildprocesses')) { return 'Block Office communication application from creating child processes' } if ($id.Contains('blockabuseofexploitedvulnerablesigneddrivers')) { return 'Block abuse of exploited vulnerable signed drivers (Device)' } if ($id.Contains('blockuntrustedunsignedprocessesthatrunfromusb')) { return 'Block untrusted and unsigned processes that run from USB' } if ($id.Contains('blockpersistencethroughwmieventsubscription')) { return 'Block persistence through WMI event subscription' } if ($id.Contains('blockofficeapplicationsfrominjectingcodeintootherprocesses')) { return 'Block Office applications from injecting code into other processes' } if ($id.Contains('blockofficeapplicationsfromcreatingexecutablecontent')) { return 'Block Office applications from creating executable content' } return $SettingDefinitionId } function Get-AsrConfigDisplayName { [CmdletBinding()] [OutputType([string])] param( [string]$SettingDefinitionId, [string]$RawConfigValue, [hashtable]$DefinitionsLookup ) if ($DefinitionsLookup -and $DefinitionsLookup.ContainsKey($SettingDefinitionId)) { $def = $DefinitionsLookup[$SettingDefinitionId] if ($def.options) { $opt = @($def.options) | Where-Object { $_.itemId -and ($_.itemId.ToString().ToLowerInvariant() -eq $RawConfigValue.ToLowerInvariant()) } | Select-Object -First 1 if ($opt) { if ($opt.displayName) { return [string]$opt.displayName } if ($opt.name) { return [string]$opt.name } return $RawConfigValue } } } # Fallback: if no matching option is found in the definition (e.g. definition missing), # derive the friendly name from the standard suffix of the raw option ID value. $v = $RawConfigValue.ToLowerInvariant() if ($v.EndsWith('_block')) { return 'Block' } if ($v.EndsWith('_audit')) { return 'Audit' } if ($v.EndsWith('_off')) { return 'Off' } if ($v.EndsWith('_warn')) { return 'Warn' } return $RawConfigValue } function Get-AsrRulesFromGroupCollection { <# .SYNOPSIS Extracts ASR rules from a Settings Catalog groupSettingCollectionValue. #> [CmdletBinding()] [OutputType([System.Collections.IEnumerable])] param( [object[]]$GroupCollection, [object[]]$SettingDefinitions ) $rules = New-Object System.Collections.Generic.List[object] if (-not $GroupCollection) { return $rules } $lookup = @{} foreach ($def in @($SettingDefinitions)) { if ($def.id) { $lookup[[string]$def.id] = $def } } foreach ($group in $GroupCollection) { foreach ($child in @($group.children)) { $defId = [string]$child.settingDefinitionId if (-not $defId -or -not $child.choiceSettingValue) { continue } $name = Get-AsrRuleDisplayName -SettingDefinitionId $defId -DefinitionsLookup $lookup $raw = [string]$child.choiceSettingValue.value $val = Get-AsrConfigDisplayName -SettingDefinitionId $defId -RawConfigValue $raw -DefinitionsLookup $lookup $rules.Add([pscustomobject]@{ Id = $defId Name = "Defender > $name" Value = $val }) foreach ($rc in @($child.choiceSettingValue.children)) { $childDefId = [string]$rc.settingDefinitionId if (-not $childDefId -or -not $childDefId.ToLowerInvariant().Contains('perruleexclusions')) { continue } $paths = @($rc.simpleSettingCollectionValue) | ForEach-Object { $_.value } | Where-Object { $_ } if ($paths.Count -gt 0) { $rules.Add([pscustomobject]@{ Id = $childDefId Name = "Defender > $name > Asr Only Per Rule Exclusions" Value = ($paths -join ', ') }) } } } } return $rules } |