noid-privacy/Modules/SecurityBaseline/Private/Set-RegistryPolicies.ps1

219 lines
9.4 KiB
PowerShell

<#
.SYNOPSIS
Apply registry policies from parsed Security Baseline JSON
.DESCRIPTION
Native PowerShell registry application without LGPO.exe dependency.
Applies Computer (HKLM) and User (HKCU) registry settings from JSON configs.
Supports all registry types:
- REG_DWORD, REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_MULTI_SZ
.PARAMETER ComputerPoliciesPath
Path to Computer-RegistryPolicies.json
.PARAMETER UserPoliciesPath
Path to User-RegistryPolicies.json
.PARAMETER DryRun
Preview changes without applying
.OUTPUTS
PSCustomObject with applied count and errors
.NOTES
This replaces LGPO.exe for registry policy application
Uses native PowerShell New-Item/Set-ItemProperty
#>
function Set-RegistryPolicies {
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$ComputerPoliciesPath,
[Parameter(Mandatory = $false)]
[string]$UserPoliciesPath,
[Parameter(Mandatory = $false)]
[switch]$DryRun
)
$result = [PSCustomObject]@{
Applied = 0
Skipped = 0
Errors = @()
Details = @{
Computer = 0
User = 0
}
}
try {
# Apply Computer policies (HKLM)
if ($ComputerPoliciesPath -and (Test-Path $ComputerPoliciesPath)) {
Write-Log -Level DEBUG -Message "Applying Computer registry policies..." -Module "SecurityBaseline"
$computerPolicies = Get-Content -Path $ComputerPoliciesPath -Raw | ConvertFrom-Json
foreach ($policy in $computerPolicies) {
try {
# Parse key path: [SOFTWARE\... -> HKLM:\SOFTWARE\...
$keyPath = $policy.KeyName -replace '^\[', '' -replace '\]$', ''
# Determine registry root
if ($keyPath -match '^(SOFTWARE|SYSTEM)\\') {
$fullPath = "HKLM:\$keyPath"
}
else {
Write-Log -Level DEBUG -Message "Unknown registry root for: $keyPath" -Module "SecurityBaseline"
$result.Skipped++
continue
}
if ($DryRun) {
Write-Log -Level DEBUG -Message "[DRYRUN] Would set: $fullPath\$($policy.ValueName) = $($policy.Data)" -Module "SecurityBaseline"
$result.Applied++
$result.Details.Computer++
continue
}
# Ensure parent key exists
if (-not (Test-Path $fullPath)) {
New-Item -Path $fullPath -Force -ErrorAction Stop | Out-Null
}
# Convert registry type
$regType = switch ($policy.Type) {
"REG_DWORD" { "DWord" }
"REG_SZ" { "String" }
"REG_EXPAND_SZ" { "ExpandString" }
"REG_BINARY" { "Binary" }
"REG_MULTI_SZ" { "MultiString" }
default {
Write-Log -Level DEBUG -Message "Unknown registry type: $($policy.Type) for $($policy.ValueName)" -Module "SecurityBaseline"
"String"
}
}
# Apply setting (create or update with correct type)
$existingValue = Get-ItemProperty -Path $fullPath -Name $policy.ValueName -ErrorAction SilentlyContinue
if ($null -ne $existingValue) {
# Value exists - update it (specify Type to ensure it's preserved/corrected)
Set-ItemProperty -Path $fullPath `
-Name $policy.ValueName `
-Value $policy.Data `
-Type $regType `
-Force `
-ErrorAction Stop | Out-Null
}
else {
# Value does not exist - create it with proper type
New-ItemProperty -Path $fullPath `
-Name $policy.ValueName `
-Value $policy.Data `
-PropertyType $regType `
-Force `
-ErrorAction Stop | Out-Null
}
$result.Applied++
$result.Details.Computer++
}
catch {
$result.Errors += "Failed to set $($policy.KeyName)\$($policy.ValueName): $($_.Exception.Message)"
Write-Log -Level DEBUG -Message "Failed to set $($policy.KeyName)\$($policy.ValueName): $_" -Module "SecurityBaseline"
}
}
Write-Log -Level DEBUG -Message "Applied $($result.Details.Computer) Computer registry policies" -Module "SecurityBaseline"
}
# Apply User policies (HKCU)
if ($UserPoliciesPath -and (Test-Path $UserPoliciesPath)) {
Write-Log -Level DEBUG -Message "Applying User registry policies..." -Module "SecurityBaseline"
$userPolicies = Get-Content -Path $UserPoliciesPath -Raw | ConvertFrom-Json
foreach ($policy in $userPolicies) {
try {
# Parse key path
$keyPath = $policy.KeyName -replace '^\[', '' -replace '\]$', ''
# User policies go to HKCU
if ($keyPath -match '^SOFTWARE\\') {
$fullPath = "HKCU:\$keyPath"
}
else {
Write-Log -Level DEBUG -Message "Unknown user registry root for: $keyPath" -Module "SecurityBaseline"
$result.Skipped++
continue
}
if ($DryRun) {
Write-Log -Level DEBUG -Message "[DRYRUN] Would set: $fullPath\$($policy.ValueName) = $($policy.Data)" -Module "SecurityBaseline"
$result.Applied++
$result.Details.User++
continue
}
# Ensure parent key exists
if (-not (Test-Path $fullPath)) {
New-Item -Path $fullPath -Force -ErrorAction Stop | Out-Null
}
# Convert registry type
$regType = switch ($policy.Type) {
"REG_DWORD" { "DWord" }
"REG_SZ" { "String" }
"REG_EXPAND_SZ" { "ExpandString" }
"REG_BINARY" { "Binary" }
"REG_MULTI_SZ" { "MultiString" }
default { "String" }
}
# Apply setting (create or update with correct type)
$existingValue = Get-ItemProperty -Path $fullPath -Name $policy.ValueName -ErrorAction SilentlyContinue
if ($null -ne $existingValue) {
# Value exists - update it (specify Type to ensure it's preserved/corrected)
Set-ItemProperty -Path $fullPath `
-Name $policy.ValueName `
-Value $policy.Data `
-Type $regType `
-Force `
-ErrorAction Stop | Out-Null
}
else {
# Value does not exist - create it with proper type
New-ItemProperty -Path $fullPath `
-Name $policy.ValueName `
-Value $policy.Data `
-PropertyType $regType `
-Force `
-ErrorAction Stop | Out-Null
}
$result.Applied++
$result.Details.User++
}
catch {
$result.Errors += "Failed to set User $($policy.KeyName)\$($policy.ValueName): $($_.Exception.Message)"
Write-Log -Level DEBUG -Message "Failed to set User $($policy.KeyName)\$($policy.ValueName): $_" -Module "SecurityBaseline"
}
}
Write-Log -Level DEBUG -Message "Applied $($result.Details.User) User registry policies" -Module "SecurityBaseline"
}
}
catch {
$result.Errors += "Registry policy application failed: $($_.Exception.Message)"
Write-Log -Level DEBUG -Message "Registry policy application failed: $_" -Module "SecurityBaseline"
}
return $result
}