103 lines
5.3 KiB
PowerShell
103 lines
5.3 KiB
PowerShell
# Copyright (c) 2026 Comitari. Read-only wrapper for HardeningKitty.
|
|
# Run ONLY Invoke-HardeningKitty -Mode Audit. Never invoke HailMary, GPO or Config.
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory=$true)][string]$InstallRoot,
|
|
[Parameter(Mandatory=$true)][string]$CsvFile,
|
|
[Parameter(Mandatory=$true)][string]$MetadataFile,
|
|
[Parameter(Mandatory=$true)][ValidateSet('GPO','Intune')][string]$Source,
|
|
[Parameter(Mandatory=$true)][string]$Profile
|
|
)
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Get-MachineFindingList {
|
|
param([string]$ProfileName, [string]$AuditSource)
|
|
if ($ProfileName -ne 'auto') {
|
|
if ($ProfileName -eq 'community') {
|
|
return 'finding_list_0x6d69636b_machine.csv'
|
|
}
|
|
if ($ProfileName -match '_user\.csv$') {
|
|
throw 'A machine audit running as SYSTEM cannot assess an interactive user baseline.'
|
|
}
|
|
if ($ProfileName -notmatch '^finding_list_[A-Za-z0-9_.-]+\.csv$' -or $ProfileName.Contains('..')) {
|
|
throw 'Invalid finding list override. Only a basename starting finding_list_ is allowed.'
|
|
}
|
|
return $ProfileName
|
|
}
|
|
|
|
# Get-CimInstance is supported, unlike the deprecated wmic.exe command.
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem
|
|
$cv = Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
|
|
$build = [int]$cv.CurrentBuildNumber
|
|
$display = if ($cv.PSObject.Properties['DisplayVersion']) { [string]$cv.DisplayVersion } else { '' }
|
|
$version = $display.ToLowerInvariant()
|
|
|
|
if ([int]$os.ProductType -eq 1) {
|
|
if ($build -ge 22000) {
|
|
if ($version -notin @('21h2','22h2','23h2','24h2','25h2','26h2')) {
|
|
throw "Unsupported Windows 11 DisplayVersion '$display' (build $build); set profile explicitly."
|
|
}
|
|
return ('finding_list_msft_security_baseline_windows_11_' + $version + '_machine.csv')
|
|
}
|
|
if ($version -eq '20h2' -or $version -eq '21h1') {
|
|
return 'finding_list_msft_security_baseline_windows_10_20h2_21h1_machine.csv'
|
|
}
|
|
if ($version -notin @('21h2','22h2')) {
|
|
throw "Unsupported Windows 10 DisplayVersion '$display' (build $build); set profile explicitly."
|
|
}
|
|
return ('finding_list_msft_security_baseline_windows_10_' + $version + '_machine.csv')
|
|
}
|
|
|
|
# Domain controllers and member servers use distinct security baselines.
|
|
$role = if ([int]$os.ProductType -eq 2) { 'dc' } else { 'member' }
|
|
switch ($build) {
|
|
9600 { return 'finding_list_cis_microsoft_windows_server_2012_r2_3.0.0_machine.csv' }
|
|
14393 { return 'finding_list_cis_microsoft_windows_server_2016_1607_3.0.0_machine.csv' }
|
|
17763 { return 'finding_list_cis_microsoft_windows_server_2019_1809_3.0.0_machine.csv' }
|
|
20348 { return ('finding_list_msft_security_baseline_windows_server_2022_21h2_' + $role + '_machine.csv') }
|
|
26100 { return ('finding_list_msft_security_baseline_windows_server_2025_24h2_' + $role + '_machine.csv') }
|
|
default { throw "Unsupported Windows Server build $build; set profile explicitly." }
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (-not (Test-Path -LiteralPath $InstallRoot -PathType Container)) { throw 'Installed package data missing.' }
|
|
$listName = Get-MachineFindingList -ProfileName $Profile -AuditSource $Source
|
|
$listPath = Join-Path (Join-Path $InstallRoot 'lists') $listName
|
|
if (-not (Test-Path -LiteralPath $listPath -PathType Leaf)) {
|
|
throw "Required finding list not bundled: $listName"
|
|
}
|
|
$module = Join-Path $InstallRoot 'HardeningKitty.psm1'
|
|
if (-not (Test-Path -LiteralPath $module -PathType Leaf)) { throw 'HardeningKitty module not bundled.' }
|
|
|
|
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
|
|
$cvInfo = Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
|
|
$metaDisplay = if ($cvInfo.PSObject.Properties['DisplayVersion']) { [string]$cvInfo.DisplayVersion } else { '' }
|
|
$metadata = [ordered]@{
|
|
hostname = [Environment]::MachineName
|
|
os_caption = [string]$osInfo.Caption
|
|
product_type = [int]$osInfo.ProductType
|
|
build = [string]$cvInfo.CurrentBuildNumber
|
|
display_version = $metaDisplay
|
|
benchmark = $listName
|
|
source = $Source
|
|
execution_identity = [Security.Principal.WindowsIdentity]::GetCurrent().Name
|
|
}
|
|
$json = $metadata | ConvertTo-Json -Depth 5
|
|
[System.IO.File]::WriteAllText($MetadataFile, $json, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
# HardeningKitty supports write modes, but this wrapper never exposes them.
|
|
Import-Module -Name $module -Force -ErrorAction Stop
|
|
# Upstream may emit non-terminating errors for unsupported individual tests.
|
|
# We detect skipped checks by comparing CSV rows to the input finding list.
|
|
$ErrorActionPreference = 'Continue'
|
|
Invoke-HardeningKitty -Mode Audit -Source $Source -FileFindingList $listPath -Report -ReportFile $CsvFile -SkipUserInformation -SkipMachineInformation | Out-Null
|
|
if ((-not (Test-Path -LiteralPath $CsvFile -PathType Leaf)) -or ((Get-Item -LiteralPath $CsvFile).Length -lt 40)) {
|
|
throw 'Audit did not produce a valid CSV report.'
|
|
}
|
|
exit 0
|
|
} catch {
|
|
[Console]::Error.WriteLine('HardeningKitty audit failed: ' + $_.Exception.Message)
|
|
exit 1
|
|
}
|