Files
WELA/tests/DomainNtlmAuditOutput.Tests.ps1

74 lines
4.8 KiB
PowerShell

# Exercise the real audit renderer/CSV exports with injected observations and rules.
# Only a temporary directory is written; no Windows policy is read or changed.
$ErrorActionPreference = 'Stop'
Import-Module (Join-Path $PSScriptRoot '../modules/RuleEligibility.psm1') -Force
$tokens = $null; $parseErrors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile((Join-Path $PSScriptRoot '../WELA.ps1'), [ref]$tokens, [ref]$parseErrors)
if ($parseErrors.Count) { throw ($parseErrors | Out-String) }
$class = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.TypeDefinitionAst] -and $node.Name -eq 'WELA' }, $true)
. ([scriptblock]::Create($class.Extent.Text))
$definition = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq 'AuditLogSetting' }, $true)
. ([scriptblock]::Create($definition.Extent.Text))
$script:assertions = 0
function Assert-Equal($Actual, $Expected, [string]$Message) {
if ($Actual -cne $Expected) { throw "$Message. Expected '$Expected', got '$Actual'." }
$script:assertions++
}
function TestAdministrator { return $true }
function CollectAuditpol { param([switch]$UseCached) return $true }
function GetAuditpol { return @{} }
function Get-WelaOutgoingNtlmState {
return [pscustomobject]@{ Description = 'Audit all (1)'; PolicySource = 'Mocked policy source' }
}
function Get-WelaDomainNtlmState { return [pscustomobject]@{ Description = $script:description } }
function Export-MitreHeatmap { param($sigmaRules, $OutputPath, $UseIdealCount) }
function BuildAuditResult {
param($all_rules, $Baseline, $enabledguid)
$all_rules[0].applicable = $true
@(
[WELA]::new('Fixture rules', 'Available', 'Success', @($all_rules[0]))
[WELA]::new('Fixture rules', 'Unavailable', 'No Auditing', @($all_rules[1]))
)
}
$script:ScriptRoot = Join-Path ([IO.Path]::GetTempPath()) ('wela-domain-output-' + [guid]::NewGuid().ToString('N'))
$null = New-Item -ItemType Directory -Path $script:ScriptRoot
$script:SecurityRulesPath = Join-Path $script:ScriptRoot 'rules.json'
try {
@(
@{ id = 'available-rule'; title = 'Available fixture'; level = 'high'; subcategory_guids = @() }
@{ id = 'unavailable-rule'; title = 'Unavailable fixture'; level = 'medium'; subcategory_guids = @() }
) | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $script:SecurityRulesPath -Encoding UTF8
foreach ($observed in @(
'Enable all (7)',
'Disabled (0)',
'Not configured',
'Value 2 (not interpreted as Enable all)',
'Not applicable (Windows client)',
'Not applicable (member or standalone server, including non-DC AD CS)',
'Unknown (computer role could not be determined)',
'Unknown (domain NTLM registry read failed: Access denied)'
)) {
$script:description = $observed
$output = (AuditLogSetting -outType std -Baseline YamatoSecurity 6>&1 | Out-String)
$expectedHeading = 'NTLM Authentication: Audit all (1); ' + $observed
Assert-Equal ($output -match ('(?m)^' + [regex]::Escape($expectedHeading) + '\r?$')) $true "Console heading retains '$observed'"
Assert-Equal ($output -match 'NTLM Authentication: Partially Enabled') $false 'An empty rule array does not imply partial enablement'
Assert-Equal ($output -match 'Fixture rules: Partially Enabled') $true 'Ordinary rule coverage aggregation is preserved'
$row = @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'WELA-Audit-Result.csv') | Where-Object SubCategory -eq 'Domain NTLM auditing')
Assert-Equal $row.Count 1 'CSV contains one domain NTLM setting row'
Assert-Equal $row[0].CurrentSetting $observed 'CSV retains the observed configuration state'
Assert-Equal $row[0].RuleCount '0' 'Configuration row claims no detection rules'
$outgoingRow = @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'WELA-Audit-Result.csv') | Where-Object SubCategory -eq 'Outgoing NTLM policy')
Assert-Equal $outgoingRow.Count 1 'CSV contains one outgoing NTLM setting row'
Assert-Equal $outgoingRow[0].CurrentSetting 'Audit all (1)' 'CSV retains the independent outgoing NTLM state'
Assert-Equal $outgoingRow[0].RuleCount '0' 'Outgoing configuration row claims no detection rules'
Assert-Equal @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'UsableRules.csv')).Count 0 'Configuration rows do not supply missing detection evidence'
Assert-Equal @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'UnusableRules.csv')).Count 2 'Both rules retain their missing-evidence gap'
}
Write-Host "PASS: $script:assertions domain NTLM output assertions (mocked observations; temporary CSV files only)."
} finally {
Remove-Item -LiteralPath $script:ScriptRoot -Recurse -Force
}