public/maester/intune/Test-MtIntuneManagedInstallerRules.ps1
|
function Test-MtIntuneManagedInstallerRules { <# .SYNOPSIS Ensure at least one Intune App Control for Business policy has Managed Installer enabled. .DESCRIPTION Checks Intune Endpoint Security Application Control policies (configurationPolicies API) for the "Trust apps from managed installer" setting. When Managed Installer is enabled in an App Control for Business policy, applications deployed through Intune (or SCCM) are automatically trusted and allowed to run without needing explicit allow rules. This simplifies App Control deployment by ensuring IT-managed software isn't blocked. Without Managed Installer: - Every application must have an explicit allow rule in the policy - LOB apps deployed via Intune may be blocked unexpectedly - Help desk tickets increase due to false positives With Managed Installer: - Apps deployed through Intune are automatically whitelisted - Only user-installed or sideloaded apps are subject to policy restrictions - Reduces false positives while maintaining security The test passes if at least one App Control policy is in **enforce mode** (audit mode disabled) AND has the "Trust apps from managed installer" setting enabled AND has an **active control** (built-in controls selected OR a non-empty uploaded XML payload). Managed Installer enabled on an audit-only policy, or on an enforce-mode upload policy with an empty XML payload, does not actively trust deployed apps because the underlying App Control policy is not blocking anything. This mirrors the active-control gate used by MT.1179. .EXAMPLE Test-MtIntuneManagedInstallerRules Returns true if at least one enforcing App Control policy has Managed Installer enabled and an active control. .LINK https://maester.dev/docs/commands/Test-MtIntuneManagedInstallerRules #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'Managed Installer Rules is the official Microsoft product name')] [CmdletBinding()] [OutputType([bool])] param() if (!(Test-MtConnection Graph)) { Add-MtTestResultDetail -SkippedBecause NotConnectedGraph return $null } if (-not (Get-MtLicenseInformation -Product Intune)) { Add-MtTestResultDetail -SkippedBecause NotLicensedIntune return $null } try { Write-Verbose "Querying Intune App Control for Business policies for Managed Installer setting..." $appControlPolicies = @(Invoke-MtGraphRequest -RelativeUri "deviceManagement/configurationPolicies?`$filter=templateReference/templateFamily eq 'endpointSecurityApplicationControl'&`$select=id,name,description,templateReference" -ApiVersion beta) Write-Verbose "Found $($appControlPolicies.Count) App Control policies." if ($appControlPolicies.Count -eq 0) { $testResultMarkdown = "No Endpoint Security App Control for Business policies found in Intune.`n`n" $testResultMarkdown += "Create an App Control policy under **Endpoint Security > Application Control** with " $testResultMarkdown += "**Trust apps from managed installer** enabled to automatically trust Intune-deployed apps." Add-MtTestResultDetail -Result $testResultMarkdown return $false } $managedInstallerId = 'device_vendor_msft_policy_config_applicationcontrolv2_trustappsfrommanagedinstaller' $buildOptionsId = 'device_vendor_msft_policy_config_applicationcontrolv2_buildoptions' $auditModeId = 'device_vendor_msft_policy_config_applicationcontrolv2_auditmode' # When 'Custom policy upload' is selected, the XML payload is delivered in a simpleSettingValue child setting. $policyXmlId = 'device_vendor_msft_policy_config_applicationcontrolv2_policy' $policyResults = [System.Collections.Generic.List[hashtable]]::new() foreach ($policy in $appControlPolicies) { Write-Verbose "Checking App Control policy: $($policy.name) ($($policy.id))" $settingsUri = "deviceManagement/configurationPolicies('$($policy.id)')/settings?`$expand=settingDefinitions&`$top=1000" $settingsResponse = @(Invoke-MtGraphRequest -RelativeUri $settingsUri -ApiVersion beta) $policyDetail = @{ Name = $policy.name BuildOptions = 'Not configured' PolicyXml = 'N/A' ManagedInstaller = 'Not configured' AuditMode = 'Not configured' MIEnabled = $false Enforcing = $false HasActiveControl = $false } foreach ($setting in $settingsResponse) { $defId = $setting.settingInstance.settingDefinitionId if ($defId -eq $buildOptionsId) { $val = $setting.settingInstance.choiceSettingValue.value $isBuiltIn = $val -like '*built_in_controls_selected' $isUpload = $val -like '*upload_policy_selected' if ($isBuiltIn) { $policyDetail.BuildOptions = 'Built-in controls' $policyDetail.HasActiveControl = $true } elseif ($isUpload) { $policyDetail.BuildOptions = 'Custom policy upload' # HasActiveControl is set later only if a non-empty XML payload is present. } Write-Verbose " BuildOptions: $($policyDetail.BuildOptions)" foreach ($child in $setting.settingInstance.choiceSettingValue.children) { switch ($child.settingDefinitionId) { $managedInstallerId { $childVal = $child.choiceSettingValue.value if ($childVal -like '*_enabled') { $policyDetail.ManagedInstaller = 'Enabled' $policyDetail.MIEnabled = $true } else { $policyDetail.ManagedInstaller = 'Disabled' } Write-Verbose " ManagedInstaller: $($policyDetail.ManagedInstaller)" } $auditModeId { $childVal = $child.choiceSettingValue.value if ($childVal -like '*_enabled') { $policyDetail.AuditMode = 'Audit' $policyDetail.Enforcing = $false } else { $policyDetail.AuditMode = 'Enforce' $policyDetail.Enforcing = $true } Write-Verbose " AuditMode: $($policyDetail.AuditMode)" } $policyXmlId { $xmlVal = $child.simpleSettingValue.value if (-not [string]::IsNullOrWhiteSpace($xmlVal)) { $policyDetail.PolicyXml = "Present ($($xmlVal.Length) chars)" if ($isUpload) { $policyDetail.HasActiveControl = $true } } else { $policyDetail.PolicyXml = 'Empty' } Write-Verbose " PolicyXml: $($policyDetail.PolicyXml)" } } } } } $policyResults.Add($policyDetail) } # Pass: at least one enforcing App Control policy with Managed Installer enabled AND an active control # (built-in controls selected OR a non-empty uploaded XML payload). An enforce-mode policy with an empty # XML payload is not actively blocking anything, so Managed Installer on it does not represent real # trust enforcement. This mirrors the active-control gate used by MT.1179. $enforcingMI = @($policyResults | Where-Object { $_.MIEnabled -and $_.Enforcing -and $_.HasActiveControl }) $hasEnforcingMI = $enforcingMI.Count -gt 0 # Build result markdown $testResultMarkdown = "Found $($appControlPolicies.Count) App Control for Business policy/policies in Intune.`n`n" $testResultMarkdown += "**Pass criteria:** At least one App Control policy must be in **Enforce** mode AND have **Managed Installer** enabled AND have an active control (built-in controls selected OR a non-empty uploaded XML payload).`n`n" $testResultMarkdown += "| Policy | Build Options | Policy XML | Managed Installer | Enforcement Mode |`n" $testResultMarkdown += "| --- | --- | --- | --- | --- |`n" foreach ($p in $policyResults) { $testResultMarkdown += "| $($p.Name) | $($p.BuildOptions) | $($p.PolicyXml) | $($p.ManagedInstaller) | $($p.AuditMode) |`n" } if ($hasEnforcingMI) { $testResultMarkdown += "`n**Result:** Well done. $($enforcingMI.Count) App Control policy/policies are in **Enforce** mode with **Managed Installer** enabled and an active control." $testResultMarkdown += " Applications deployed through Intune/SCCM will be automatically trusted." Add-MtTestResultDetail -Result $testResultMarkdown return $true } else { $auditMI = @($policyResults | Where-Object { $_.MIEnabled -and -not $_.Enforcing }) $emptyXmlMI = @($policyResults | Where-Object { $_.MIEnabled -and $_.Enforcing -and -not $_.HasActiveControl }) $testResultMarkdown += "`n**Result:** No App Control policies have **Managed Installer** enabled in **Enforce** mode with an active control.`n`n" if ($auditMI.Count -gt 0) { $testResultMarkdown += "$($auditMI.Count) policy/policies have Managed Installer enabled but the underlying App Control policy is in **Audit** mode, so deployed apps are not actively trusted.`n`n" } if ($emptyXmlMI.Count -gt 0) { $testResultMarkdown += "$($emptyXmlMI.Count) policy/policies are in **Enforce** mode with Managed Installer enabled, but the uploaded XML payload is empty so the App Control policy is not actively blocking anything.`n`n" } $testResultMarkdown += "> **Risk:** Without Managed Installer on an enforcing App Control policy that has an active control, applications deployed via Intune may be blocked once App Control transitions to active enforcement. " $testResultMarkdown += "This leads to false positives and help desk tickets. Enable 'Trust apps from managed installer' on an enforcing policy with built-in controls or a non-empty uploaded XML to automatically trust IT-deployed software." Add-MtTestResultDetail -Result $testResultMarkdown return $false } } catch { if ($_.Exception.Response -and $_.Exception.Response.StatusCode -in @(401, 403)) { Add-MtTestResultDetail -SkippedBecause NotAuthorized } else { Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_ } return $null } } |