noid-privacy/Modules/EdgeHardening/Private/Test-EdgePolicies.ps1

187 lines
7.4 KiB
PowerShell

<#
.SYNOPSIS
Test Microsoft Edge security policies compliance
.DESCRIPTION
Verifies that all Edge v139 Security Baseline policies are correctly applied.
Returns detailed compliance status for each policy.
NOTE: Supports optional policies that count as SUCCESS even if not applied:
- GPO deletion markers (**delvals) - infrastructure, not a real policy
- ExtensionInstallBlocklist - optional based on -AllowExtensions flag
.PARAMETER EdgePoliciesPath
Path to EdgePolicies.json (default: module ParsedSettings folder)
.OUTPUTS
PSCustomObject with compliance status and details
.NOTES
Checks registry values against expected baseline values
Treats optional policies as SUCCESS if not set (user choice)
#>
function Test-EdgePolicies {
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$EdgePoliciesPath
)
# Default path if not specified
if (-not $EdgePoliciesPath) {
$modulePath = Split-Path -Parent $PSScriptRoot
$EdgePoliciesPath = Join-Path $modulePath "Config\EdgePolicies.json"
}
if (-not (Test-Path $EdgePoliciesPath)) {
return [PSCustomObject]@{
Compliant = $false
Message = "EdgePolicies.json not found: $EdgePoliciesPath"
Details = @()
}
}
try {
$edgePolicies = Get-Content -Path $EdgePoliciesPath -Raw | ConvertFrom-Json
$compliantCount = 0
$nonCompliantCount = 0
$details = @()
foreach ($policy in $edgePolicies) {
# Parse key path first
$keyPath = $policy.KeyName -replace '^\[', '' -replace '\]$', ''
$fullPath = "HKLM:\$keyPath"
# Determine if this policy is optional
$isOptional = $false
# GPO deletion markers are optional (infrastructure, not real policies)
if ($policy.ValueName -like "**delvals.*") {
$compliantCount++
$details += [PSCustomObject]@{
Policy = $policy.ValueName
Expected = "GPO Marker"
Actual = "Skipped"
Status = "Compliant (Ignored)"
Compliant = $true
Optional = $true
}
continue
}
$isOptional = $false
# ExtensionInstallBlocklist is optional ONLY if key doesn't exist
# (meaning user chose -AllowExtensions, so it was skipped)
# If key exists, it MUST be compliant (user chose to block extensions)
if ($policy.ValueName -eq "1" -and $policy.KeyName -like "*ExtensionInstallBlocklist*") {
if (-not (Test-Path $fullPath)) {
$isOptional = $true # User chose -AllowExtensions
}
# else: Key exists, so it must be compliant (not optional)
}
$policyCompliant = $false
$actualValue = $null
$status = "Not Set"
try {
if (Test-Path $fullPath) {
$regValue = Get-ItemProperty -Path $fullPath -Name $policy.ValueName -ErrorAction Stop
$actualValue = $regValue.$($policy.ValueName)
# Compare values
if ($policy.Type -eq "REG_DWORD") {
$policyCompliant = ([int]$actualValue -eq [int]$policy.Data)
}
elseif ($policy.Type -eq "REG_MULTI_SZ") {
# Compare arrays
$expected = $policy.Data
$policyCompliant = ($null -eq (Compare-Object $actualValue $expected))
}
else {
$policyCompliant = ($actualValue -eq $policy.Data)
}
$status = if ($policyCompliant) { "Compliant" } else { "Non-Compliant (Wrong Value)" }
if (-not $policyCompliant) {
Write-Log -Level WARNING -Message "Policy Check Failed: $($policy.ValueName)" -Module "EdgeHardening"
Write-Log -Level WARNING -Message " - Key: $fullPath" -Module "EdgeHardening"
Write-Log -Level WARNING -Message " - Expected: $($policy.Data)" -Module "EdgeHardening"
Write-Log -Level WARNING -Message " - Actual: $actualValue" -Module "EdgeHardening"
}
}
else {
# Key doesn't exist
if ($isOptional) {
# Optional policy not set = SUCCESS (user choice)
$policyCompliant = $true
$status = "Compliant (Optional - Not Set)"
}
else {
$status = "Non-Compliant (Key Not Found)"
Write-Log -Level WARNING -Message "Policy Check Failed: $($policy.ValueName)" -Module "EdgeHardening"
Write-Log -Level WARNING -Message " - Key Not Found: $fullPath" -Module "EdgeHardening"
}
}
}
catch {
# Value doesn't exist in existing key
if ($isOptional) {
# Optional policy not set = SUCCESS (user choice)
$policyCompliant = $true
$status = "Compliant (Optional - Not Set)"
}
else {
$status = "Non-Compliant (Value Not Found)"
Write-Log -Level WARNING -Message "Policy Check Failed: $($policy.ValueName)" -Module "EdgeHardening"
Write-Log -Level WARNING -Message " - Key exists but Value missing: $fullPath\$($policy.ValueName)" -Module "EdgeHardening"
}
}
if ($policyCompliant) {
$compliantCount++
}
else {
$nonCompliantCount++
}
$details += [PSCustomObject]@{
Policy = $policy.ValueName
Expected = $policy.Data
Actual = $actualValue
Status = $status
Compliant = $policyCompliant
Optional = $isOptional
}
}
# Total policies = all 20 entries in JSON
$totalPolicies = $compliantCount + $nonCompliantCount
$compliancePercentage = if ($totalPolicies -gt 0) {
[math]::Round(($compliantCount / $totalPolicies) * 100, 1)
}
else {
0
}
return [PSCustomObject]@{
Compliant = ($nonCompliantCount -eq 0)
Message = "Edge Security: $compliantCount/$totalPolicies policies compliant ($compliancePercentage%)"
CompliantCount = $compliantCount
NonCompliantCount = $nonCompliantCount
CompliancePercentage = $compliancePercentage
Details = $details
}
}
catch {
return [PSCustomObject]@{
Compliant = $false
Message = "Edge policy compliance test failed: $($_.Exception.Message)"
Details = @()
}
}
}