noid-privacy/Tools/Parse-EdgeBaseline.ps1
Nexus d4dfe39e4f
Some checks failed
CI - PowerShell Quality Checks / PSScriptAnalyzer (push) Has been cancelled
CI - PowerShell Quality Checks / Test on PowerShell 5.1 (push) Has been cancelled
CI - PowerShell Quality Checks / Test on PowerShell 7.4 (push) Has been cancelled
CI - PowerShell Quality Checks / Validate Project Structure (push) Has been cancelled
Pester Tests / test (push) Has been cancelled
chore: bump version to 2.2.4, update CHANGELOG and README
Version bump across 62 files (2.2.3 → 2.2.4).
CHANGELOG.md: New [2.2.4] section with EDR/XDR detection and version tooling.
README.md: Updated release highlights, AV detection example output synced with code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:22:12 +01:00

307 lines
10 KiB
PowerShell

<#
.SYNOPSIS
Parse Microsoft Edge Security Baseline GPO files to JSON (DEVELOPER TOOL ONLY)
.DESCRIPTION
**NOTE: This is a DEVELOPER/MAINTENANCE tool - NOT needed for production use!**
Parses GPO backups from Microsoft Edge Security Baseline:
- Registry.pol (Computer policies for Microsoft Edge)
Outputs structured JSON files for Edge hardening settings.
.PARAMETER BaselinePath
Path to Microsoft Edge Security Baseline folder
.PARAMETER OutputPath
Path where JSON output files will be saved
.NOTES
Author: NexusOne23
Version: 2.2.4
Requires: PowerShell 5.1+
.EXAMPLE
.\Parse-EdgeBaseline.ps1 -BaselinePath "C:\Edge Baseline" -OutputPath ".\Modules\EdgeHardening\ParsedSettings"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$BaselinePath,
[Parameter(Mandatory = $false)]
[string]$OutputPath = (Join-Path $PSScriptRoot "..\Modules\EdgeHardening\ParsedSettings")
)
#region Helper Functions
function Read-PolFile {
<#
.SYNOPSIS
Parse binary Registry.pol file
.DESCRIPTION
Based on Microsoft GPRegistryPolicyParser format
Registry.pol binary format:
- Signature: PReg (4 bytes)
- Version: 1 (4 bytes)
- Entries: [KeyName;ValueName;Type;Size;Data]
#>
param(
[Parameter(Mandatory = $true)]
[string]$Path
)
if (-not (Test-Path $Path)) {
Write-Warning "Registry.pol not found: $Path"
return @()
}
try {
$entries = @()
$bytes = [System.IO.File]::ReadAllBytes($Path)
# Check signature (PReg)
$signature = [System.Text.Encoding]::ASCII.GetString($bytes[0..3])
if ($signature -ne 'PReg') {
Write-Warning "Invalid Registry.pol signature: $signature"
return @()
}
# Check version
$version = [BitConverter]::ToInt32($bytes, 4)
if ($version -ne 1) {
Write-Warning "Unsupported Registry.pol version: $version"
return @()
}
$index = 8 # Start after signature and version
while ($index -lt $bytes.Length) {
# Read entry: [KeyName;ValueName;Type;Size;Data]
# Read KeyName (Unicode null-terminated string)
$keyNameBytes = @()
while ($index -lt ($bytes.Length - 1)) {
$b1 = $bytes[$index]
$b2 = $bytes[$index + 1]
$index += 2
if ($b1 -eq 0 -and $b2 -eq 0) {
break
}
$keyNameBytes += $b1, $b2
}
$keyName = [System.Text.Encoding]::Unicode.GetString($keyNameBytes)
# Skip semicolon
$index += 2
# Read ValueName (Unicode null-terminated string)
$valueNameBytes = @()
while ($index -lt ($bytes.Length - 1)) {
$b1 = $bytes[$index]
$b2 = $bytes[$index + 1]
$index += 2
if ($b1 -eq 0 -and $b2 -eq 0) {
break
}
$valueNameBytes += $b1, $b2
}
$valueName = [System.Text.Encoding]::Unicode.GetString($valueNameBytes)
# Skip semicolon
$index += 2
# Read Type (DWORD - 4 bytes)
if ($index + 4 -gt $bytes.Length) { break }
$type = [BitConverter]::ToInt32($bytes, $index)
$index += 4
# Skip semicolon
$index += 2
# Read Size (DWORD - 4 bytes)
if ($index + 4 -gt $bytes.Length) { break }
$size = [BitConverter]::ToInt32($bytes, $index)
$index += 4
# Skip semicolon
$index += 2
# Read Data
$data = $null
if ($size -gt 0 -and ($index + $size) -le $bytes.Length) {
$dataBytes = $bytes[$index..($index + $size - 1)]
# Parse based on type
switch ($type) {
1 {
# REG_SZ (String)
$data = [System.Text.Encoding]::Unicode.GetString($dataBytes).TrimEnd([char]0)
}
2 {
# REG_EXPAND_SZ
$data = [System.Text.Encoding]::Unicode.GetString($dataBytes).TrimEnd([char]0)
}
3 {
# REG_BINARY
$data = $dataBytes
}
4 {
# REG_DWORD
if ($dataBytes.Length -ge 4) {
$data = [BitConverter]::ToInt32($dataBytes, 0)
}
}
7 {
# REG_MULTI_SZ
$data = [System.Text.Encoding]::Unicode.GetString($dataBytes).TrimEnd([char]0) -split '\x00'
}
default {
$data = $dataBytes
}
}
$index += $size
}
# Skip closing bracket
$index += 2
# Add entry
$entries += [PSCustomObject]@{
KeyName = $keyName
ValueName = $valueName
Type = switch ($type) {
1 { "REG_SZ" }
2 { "REG_EXPAND_SZ" }
3 { "REG_BINARY" }
4 { "REG_DWORD" }
7 { "REG_MULTI_SZ" }
11 { "REG_QWORD" }
default { "Unknown($type)" }
}
Data = $data
}
}
return $entries
}
catch {
Write-Error "Failed to parse Registry.pol: $Path - $_"
return @()
}
}
#endregion
#region Main Parsing Logic
Write-Host ""
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " Microsoft Edge Security Baseline Parser" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
Write-Host ""
# Validate baseline path
if (-not (Test-Path $BaselinePath)) {
Write-Error "Baseline path not found: $BaselinePath"
exit 1
}
# Ensure output directory exists
if (-not (Test-Path $OutputPath)) {
New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
Write-Host "Created output directory: $OutputPath" -ForegroundColor Green
}
# Find GPO folder (should be only one GPO in Edge Baseline)
$gpoFolders = Get-ChildItem -Path (Join-Path $BaselinePath "GPOs") -Directory
if ($gpoFolders.Count -eq 0) {
Write-Error "No GPO folders found in $BaselinePath\GPOs"
exit 1
}
Write-Host "Found $($gpoFolders.Count) GPO folder(s)" -ForegroundColor Cyan
Write-Host ""
$allComputerPolicies = @()
foreach ($gpoFolder in $gpoFolders) {
$gpoName = $gpoFolder.Name
Write-Host "Processing GPO: $gpoName" -ForegroundColor Yellow
# Parse Computer Registry policies
$computerPolPath = Join-Path $gpoFolder.FullName "DomainSysvol\GPO\Machine\registry.pol"
if (Test-Path $computerPolPath) {
Write-Host " Parsing Computer registry policies..." -ForegroundColor Gray
$computerPolicies = Read-PolFile -Path $computerPolPath
if ($computerPolicies.Count -gt 0) {
$allComputerPolicies += $computerPolicies
Write-Host " Found $($computerPolicies.Count) Computer registry policies" -ForegroundColor Green
}
else {
Write-Warning " No Computer registry policies found"
}
}
else {
Write-Warning " Computer registry.pol not found"
}
# Check for User policies (Edge baseline typically doesn't have user policies)
$userPolPath = Join-Path $gpoFolder.FullName "DomainSysvol\GPO\User\registry.pol"
if (Test-Path $userPolPath) {
Write-Host " User registry.pol found (unexpected for Edge baseline)" -ForegroundColor Yellow
}
Write-Host ""
}
# Save Computer Registry Policies
if ($allComputerPolicies.Count -gt 0) {
$computerPoliciesFile = Join-Path $OutputPath "EdgePolicies.json"
$allComputerPolicies | ConvertTo-Json -Depth 10 | Out-File -FilePath $computerPoliciesFile -Encoding UTF8 -Force
Write-Host "Saved $($allComputerPolicies.Count) policies to: EdgePolicies.json" -ForegroundColor Green
}
# Create summary
$summary = [PSCustomObject]@{
TotalEdgePolicies = $allComputerPolicies.Count
ParsedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
BaselineVersion = "Edge v139"
RegistryPaths = ($allComputerPolicies | Select-Object -ExpandProperty KeyName -Unique | Sort-Object)
}
$summaryFile = Join-Path $OutputPath "Summary.json"
$summary | ConvertTo-Json -Depth 10 | Out-File -FilePath $summaryFile -Encoding UTF8 -Force
Write-Host ""
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " Parsing Complete" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Total Edge Policies: $($allComputerPolicies.Count)" -ForegroundColor White
Write-Host ""
Write-Host "Output files:" -ForegroundColor White
Write-Host " - EdgePolicies.json" -ForegroundColor Gray
Write-Host " - Summary.json" -ForegroundColor Gray
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host " 1. Review parsed policies in EdgePolicies.json" -ForegroundColor Gray
Write-Host " 2. Implement Set-EdgePolicies.ps1 (native PowerShell)" -ForegroundColor Gray
Write-Host " 3. Implement Test-EdgePolicies.ps1 (compliance check)" -ForegroundColor Gray
Write-Host " 4. Implement Invoke-EdgeHardening.ps1 (main entry point)" -ForegroundColor Gray
Write-Host ""
#endregion