Infrastructure-as-code framework for Active Directory objects and Group Policy. Sanitized from production deployment for public sharing.
182 lines
6.7 KiB
PowerShell
182 lines
6.7 KiB
PowerShell
# GPOWdac.ps1
|
|
# Lightweight WDAC (Windows Defender Application Control) policy deployment via GPO.
|
|
# Copies .p7b policy to SYSVOL and sets the registry pointer.
|
|
# Depends on: GPOCore.ps1 (Get-GPOSysvolPath)
|
|
|
|
function Set-GPOWdacPolicy {
|
|
<#
|
|
.SYNOPSIS
|
|
Deploys a WDAC policy file to a GPO.
|
|
If source is .xml, converts to .p7b with ConvertFrom-CIPolicy.
|
|
Copies .p7b to SYSVOL and sets the DeployConfigCIPolicy registry key.
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$GPOName,
|
|
|
|
[Parameter(Mandatory)]
|
|
[hashtable]$WDACPolicy,
|
|
|
|
[Parameter(Mandatory)]
|
|
[string]$SourceDir,
|
|
|
|
[string]$Domain = (Get-ADDomain).DNSRoot
|
|
)
|
|
|
|
Write-Host " Applying WDAC policy..." -ForegroundColor Yellow
|
|
|
|
$policyFile = $WDACPolicy.PolicyFile
|
|
$sourcePath = Join-Path $SourceDir $policyFile
|
|
|
|
if (-not (Test-Path $sourcePath)) {
|
|
throw "WDAC policy file not found: $sourcePath"
|
|
}
|
|
|
|
$sysvolPath = Get-GPOSysvolPath -GPOName $GPOName -Domain $Domain
|
|
$deviceGuardDir = Join-Path $sysvolPath 'Machine\Microsoft\Windows\DeviceGuard'
|
|
|
|
if (-not (Test-Path $deviceGuardDir)) {
|
|
New-Item -ItemType Directory -Path $deviceGuardDir -Force | Out-Null
|
|
}
|
|
|
|
$extension = [System.IO.Path]::GetExtension($sourcePath).ToLower()
|
|
|
|
if ($extension -eq '.xml') {
|
|
# Convert XML to .p7b
|
|
$destPath = Join-Path $deviceGuardDir 'SIPolicy.p7b'
|
|
ConvertFrom-CIPolicy -XmlFilePath $sourcePath -BinaryFilePath $destPath | Out-Null
|
|
Write-Host " Converted $policyFile -> SIPolicy.p7b" -ForegroundColor Green
|
|
} elseif ($extension -eq '.p7b') {
|
|
# Copy directly
|
|
$destPath = Join-Path $deviceGuardDir 'SIPolicy.p7b'
|
|
Copy-Item -Path $sourcePath -Destination $destPath -Force
|
|
Write-Host " Copied $policyFile -> SIPolicy.p7b" -ForegroundColor Green
|
|
} else {
|
|
throw "WDAC policy file must be .xml or .p7b, got: $extension"
|
|
}
|
|
|
|
# Set registry key to enable WDAC via GPO
|
|
$regKey = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceGuard'
|
|
Set-GPRegistryValue -Name $GPOName -Key $regKey -ValueName 'DeployConfigCIPolicy' `
|
|
-Type DWord -Value 1 -Domain $Domain | Out-Null
|
|
|
|
Write-Host " [OK] WDAC policy deployed to $GPOName" -ForegroundColor Green
|
|
}
|
|
|
|
function Compare-GPOWdacPolicy {
|
|
<#
|
|
.SYNOPSIS
|
|
Compares desired WDAC policy against current GPO state.
|
|
Checks registry key and .p7b file existence/hash.
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$GPOName,
|
|
|
|
[Parameter(Mandatory)]
|
|
[hashtable]$WDACPolicy,
|
|
|
|
[Parameter(Mandatory)]
|
|
[string]$SourceDir,
|
|
|
|
[string]$Domain = (Get-ADDomain).DNSRoot
|
|
)
|
|
|
|
$diffs = @()
|
|
|
|
Write-Host " Comparing WDAC policy..." -ForegroundColor Yellow
|
|
|
|
# Check registry key
|
|
$regKey = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceGuard'
|
|
$currentRegValue = $null
|
|
try {
|
|
$regResult = Get-GPRegistryValue -Name $GPOName -Key $regKey -ValueName 'DeployConfigCIPolicy' `
|
|
-Domain $Domain -ErrorAction Stop
|
|
$currentRegValue = $regResult.Value
|
|
} catch {
|
|
$currentRegValue = $null
|
|
}
|
|
|
|
if ($currentRegValue -ne 1) {
|
|
$display = if ($null -eq $currentRegValue) { '(not set)' } else { $currentRegValue }
|
|
Write-Host " [DRIFT] DeployConfigCIPolicy: $display -> 1" -ForegroundColor Red
|
|
$diffs += [PSCustomObject]@{
|
|
Type = 'WDAC'
|
|
Setting = 'DeployConfigCIPolicy'
|
|
Status = "Registry: $display -> 1"
|
|
}
|
|
} else {
|
|
Write-Host " [OK] DeployConfigCIPolicy = 1" -ForegroundColor Green
|
|
}
|
|
|
|
# Check .p7b file exists in SYSVOL
|
|
$sysvolPath = Get-GPOSysvolPath -GPOName $GPOName -Domain $Domain
|
|
$p7bPath = Join-Path $sysvolPath 'Machine\Microsoft\Windows\DeviceGuard\SIPolicy.p7b'
|
|
|
|
if (-not (Test-Path $p7bPath)) {
|
|
Write-Host " [DRIFT] Missing: SIPolicy.p7b" -ForegroundColor Red
|
|
$diffs += [PSCustomObject]@{
|
|
Type = 'WDAC'
|
|
Setting = 'SIPolicy.p7b'
|
|
Status = 'Missing'
|
|
}
|
|
} else {
|
|
# Compare file hashes if source exists
|
|
$policyFile = $WDACPolicy.PolicyFile
|
|
$sourcePath = Join-Path $SourceDir $policyFile
|
|
|
|
if (Test-Path $sourcePath) {
|
|
$sourceExt = [System.IO.Path]::GetExtension($sourcePath).ToLower()
|
|
|
|
if ($sourceExt -eq '.p7b') {
|
|
$sourceHash = (Get-FileHash -Path $sourcePath -Algorithm SHA256).Hash
|
|
$deployedHash = (Get-FileHash -Path $p7bPath -Algorithm SHA256).Hash
|
|
|
|
if ($sourceHash -ne $deployedHash) {
|
|
Write-Host " [DRIFT] SIPolicy.p7b hash mismatch (source updated)" -ForegroundColor Red
|
|
$diffs += [PSCustomObject]@{
|
|
Type = 'WDAC'
|
|
Setting = 'SIPolicy.p7b'
|
|
Status = 'Hash mismatch'
|
|
}
|
|
} else {
|
|
Write-Host " [OK] SIPolicy.p7b hash matches" -ForegroundColor Green
|
|
}
|
|
} else {
|
|
# Source is .xml -- convert to temp .p7b and compare
|
|
$tempP7b = [System.IO.Path]::GetTempFileName()
|
|
try {
|
|
ConvertFrom-CIPolicy -XmlFilePath $sourcePath -BinaryFilePath $tempP7b | Out-Null
|
|
$sourceHash = (Get-FileHash -Path $tempP7b -Algorithm SHA256).Hash
|
|
$deployedHash = (Get-FileHash -Path $p7bPath -Algorithm SHA256).Hash
|
|
|
|
if ($sourceHash -ne $deployedHash) {
|
|
Write-Host " [DRIFT] SIPolicy.p7b hash mismatch (source XML updated)" -ForegroundColor Red
|
|
$diffs += [PSCustomObject]@{
|
|
Type = 'WDAC'
|
|
Setting = 'SIPolicy.p7b'
|
|
Status = 'Hash mismatch'
|
|
}
|
|
} else {
|
|
Write-Host " [OK] SIPolicy.p7b matches source XML" -ForegroundColor Green
|
|
}
|
|
} catch {
|
|
Write-Host " [WARN] Cannot convert source XML for comparison: $($_.Exception.Message)" -ForegroundColor Yellow
|
|
} finally {
|
|
Remove-Item $tempP7b -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
} else {
|
|
Write-Host " [OK] SIPolicy.p7b exists (source file not found for hash comparison)" -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
if ($diffs.Count -eq 0) {
|
|
Write-Host " [OK] WDAC policy matches desired state" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " [DRIFT] $($diffs.Count) WDAC difference(s) found" -ForegroundColor Red
|
|
}
|
|
|
|
return $diffs
|
|
}
|