Reject unsupported dry runs and preserve freshly observed NTLM restrictions

This commit is contained in:
Shirofune-Security committed 2026-09-18 22:10:17 +09:00
1 parent ebd8d14d04
commit fa5141755b
2 files changed
+31 -5

No files matched your search

+5
View File
@@ -1723,6 +1723,11 @@ Write-Host ""
Write-Host "WELA v$WELAVersion - $WELAReleaseName"
Write-Host ""
# Reject unsupported dry-run requests before reaching any command's mutation path.
if ($DryRun -and $Cmd -ne 'configure') {
throw "-DryRun is supported only by configure (including configure -Profile). No command was run."
}
if ($Profile -and $Cmd.ToLower() -in @('plan', 'audit', 'audit-settings', 'configure') -and -not $Help) {
Invoke-WelaProfileCommand -Command $Cmd.ToLower()
return
+26 -5
View File
@@ -36,14 +36,17 @@ function New-WelaConfigurationContext {
function Invoke-WelaConfigurationControl {
param($Context, [string]$Id, [string]$Kind, $Target, $Desired,
[scriptblock]$Read, [scriptblock]$Compliant, [scriptblock]$Apply,
[string]$Description = '')
[string]$Description = '', [scriptblock]$PreserveWhen)
$result = [pscustomobject][ordered]@{
Id = $Id; Kind = $Kind; Target = $Target; Desired = $Desired
Before = $null; After = $null; Status = 'Failed'; Diagnostic = ''
}
try {
$result.Before = & $Read
if (& $Compliant $result.Before) {
$preserveReason = if ($PreserveWhen) { & $PreserveWhen $result.Before } else { $null }
if ($preserveReason) {
$result.Status = 'Skipped'; $result.After = $result.Before; $result.Diagnostic = [string]$preserveReason
} elseif (& $Compliant $result.Before) {
$result.Status = 'AlreadyCompliant'
$result.After = $result.Before
} elseif ($Context.DryRun) {
@@ -175,16 +178,22 @@ function New-WelaRegistryKey {
}
function Set-WelaRegistryControl {
param($Context, [string]$Path, [string]$Name, $Value, [string]$Type = 'DWord')
param($Context, [string]$Path, [string]$Name, $Value, [string]$Type = 'DWord', [scriptblock]$PreserveWhen)
$read = { Get-WelaRegistryState -Path $Path -Name $Name }.GetNewClosure()
$test = { param($state) $state.ValueExists -and $state.Value -eq $Value -and $state.Type -eq $Type }.GetNewClosure()
$apply = {
New-WelaRegistryKey -Path $Path
if ($PreserveWhen) {
# Recheck after the prompt and journal, immediately before the value write.
$fresh = Get-WelaRegistryState -Path $Path -Name $Name
$preserveReason = & $PreserveWhen $fresh
if ($preserveReason) { throw "Refused registry write after state changed: $preserveReason" }
}
Set-ItemProperty -LiteralPath $Path -Name $Name -Value $Value -Type $Type -ErrorAction Stop
}.GetNewClosure()
Invoke-WelaConfigurationControl -Context $Context -Id "Registry/$Path/$Name" -Kind Registry `
-Target @{ Path = $Path; Name = $Name } -Desired @{ Value = $Value; Type = $Type } `
-Read $read -Compliant $test -Apply $apply
-Read $read -Compliant $test -Apply $apply -PreserveWhen $PreserveWhen
}
function Initialize-WelaConfigurationAuditApi {
@@ -361,7 +370,19 @@ function Set-WelaNtlmConfigurationControl {
} else {
# Shared runner owns prompts, dry-run suppression, exact registry
# before-state journal, type/value read-back and final drift check.
Set-WelaRegistryControl -Context $Context -Path $path -Name $name -Value $desired
$preserve = $null
if ($Scope -eq 'Outgoing' -and $Mode -eq 'PreserveOrAudit') {
$preserve = {
param($snapshot)
if ($snapshot.ValueExists -and $snapshot.Type -eq 'DWord' -and $snapshot.Value -eq 2) {
return 'Preserved newly observed Deny all enforcement (2); explicit Audit mode is required to replace it.'
}
if ($snapshot.ValueExists -and ($snapshot.Type -ne 'DWord' -or $snapshot.Value -notin @(0, 1, 2))) {
return "Preserved newly observed unknown outgoing NTLM value/type ($($snapshot.Value)/$($snapshot.Type))."
}
}
}
Set-WelaRegistryControl -Context $Context -Path $path -Name $name -Value $desired -PreserveWhen $preserve
return
}
}