Remediate-SecureBootCA2023SCCM.ps1
|
<#PSScriptInfo
.VERSION 1.1.0 .GUID 8c5d0c1b-4f2c-4e8f-9f3a-7b2d9f0c2023 .AUTHOR Mert Efe Kanlikilic .COMPANYNAME mertefekanlikilic.com .COPYRIGHT (c) 2026 Mert Efe Kanlikilic. All rights reserved. .TAGS SecureBoot UEFI ConfigMgr SCCM Compliance Remediation PCA2023 RestartNotification .LICENSEURI https://github.com/kanlikilicmertefe .PROJECTURI https://mertefekanlikilic.com .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Initial release of Secure Boot CA 2023 remediation script for Configuration Manager. #> <# .SYNOPSIS SCCM / Configuration Manager remediation script for Secure Boot CA 2023 certificate update. .DESCRIPTION This remediation script performs the following actions: - Ensures AvailableUpdates includes 0x5944 (Secure Boot CA 2023). - Triggers the Windows Secure Boot update scheduled task when available. - Writes remediation metadata to registry. - Displays a restart notification popup in the active user session. - Allows SCCM to re-run remediation while the device is PendingRestart. .NOTES Run as: SYSTEM PowerShell: 64-bit Log path: C:\Windows\CCM\Logs\SecureBootCA2023-Remediation.log #> param( [string]$NonCompliantValue ) $LOG_PATH = "$env:WinDir\CCM\Logs\SecureBootCA2023-Remediation.log" $EVENTLOG_SOURCE = "SecureBootCA2023" $EVENTLOG_LOG = "Application" $SECUREBOOT_KEY = "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" $SERVICING_KEY = "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" $AVAILABLE_UPDATES = 0x5944 $TASK_PATH = "\Microsoft\Windows\PI\" $TASK_NAME = "Secure-Boot-Update" $NOTIFICATION_COOLDOWN_HOURS = 0 function Write-Log { param([string]$Message, [ValidateSet("INFO","WARN","ERROR")]$Level = "INFO") $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss" try { Add-Content -Path $LOG_PATH -Value "[$ts][$Level] $Message" -Encoding UTF8 } catch {} } function Write-EventEntry { param([string]$Message, [int]$EventId, [string]$EntryType = "Information") try { if (-not [System.Diagnostics.EventLog]::SourceExists($EVENTLOG_SOURCE)) { New-EventLog -LogName $EVENTLOG_LOG -Source $EVENTLOG_SOURCE -ErrorAction Stop } Write-EventLog -LogName $EVENTLOG_LOG -Source $EVENTLOG_SOURCE -EventId $EventId -EntryType $EntryType -Message $Message } catch { Write-Log "Event log write failed: $($_.Exception.Message)" "WARN" } } function Get-RemediationMetadata { $meta = [PSCustomObject]@{ FirstRunDate = $null AttemptCount = 0 LastNotificationTime = $null } try { $sb = Get-ItemProperty -Path $SECUREBOOT_KEY -ErrorAction SilentlyContinue if ($sb.RemediationTimestamp) { $meta.FirstRunDate = [datetime]$sb.RemediationTimestamp } if ($null -ne $sb.RemediationAttemptCount) { $meta.AttemptCount = [int]$sb.RemediationAttemptCount } if ($sb.LastRestartNotificationTime) { $meta.LastNotificationTime = [datetime]$sb.LastRestartNotificationTime } } catch {} return $meta } function Set-RemediationMetadata { param([datetime]$FirstRunDate, [int]$AttemptCount, [datetime]$LastNotificationTime) try { if (-not (Test-Path $SECUREBOOT_KEY)) { New-Item -Path $SECUREBOOT_KEY -Force | Out-Null } $existingTimestamp = (Get-ItemProperty -Path $SECUREBOOT_KEY -ErrorAction SilentlyContinue).RemediationTimestamp if (-not $existingTimestamp) { Set-ItemProperty -Path $SECUREBOOT_KEY -Name "RemediationTimestamp" -Value $FirstRunDate.ToString("o") -Type String -Force } Set-ItemProperty -Path $SECUREBOOT_KEY -Name "RemediationAttemptCount" -Value $AttemptCount -Type DWord -Force if ($LastNotificationTime) { Set-ItemProperty -Path $SECUREBOOT_KEY -Name "LastRestartNotificationTime" -Value $LastNotificationTime.ToString("o") -Type String -Force } } catch { Write-Log "Metadata write failed: $($_.Exception.Message)" "WARN" } } function Set-AvailableUpdates { try { if (-not (Test-Path $SECUREBOOT_KEY)) { New-Item -Path $SECUREBOOT_KEY -Force | Out-Null } $current = (Get-ItemProperty -Path $SECUREBOOT_KEY -Name "AvailableUpdates" -ErrorAction SilentlyContinue).AvailableUpdates if ($current -and (($current -band $AVAILABLE_UPDATES) -eq $AVAILABLE_UPDATES)) { Write-Log "AvailableUpdates already contains 0x5944. Current value: 0x$('{0:X}' -f $current)." return $true } $newValue = if ($current) { $current -bor $AVAILABLE_UPDATES } else { $AVAILABLE_UPDATES } Set-ItemProperty -Path $SECUREBOOT_KEY -Name "AvailableUpdates" -Value $newValue -Type DWord -Force $verify = (Get-ItemProperty -Path $SECUREBOOT_KEY -Name "AvailableUpdates").AvailableUpdates if (($verify -band $AVAILABLE_UPDATES) -eq $AVAILABLE_UPDATES) { Write-Log "AvailableUpdates set successfully. Value: 0x$('{0:X}' -f $verify)." return $true } Write-Log "AvailableUpdates verification failed. Value: 0x$('{0:X}' -f $verify)." "ERROR" return $false } catch { Write-Log "AvailableUpdates set failed: $($_.Exception.Message)" "ERROR" return $false } } function Start-SecureBootUpdateTask { try { $task = Get-ScheduledTask -TaskPath $TASK_PATH -TaskName $TASK_NAME -ErrorAction SilentlyContinue if ($null -eq $task) { Write-Log "Scheduled task not found: ${TASK_PATH}${TASK_NAME}. Windows may still process it automatically." "WARN" return $false } Start-ScheduledTask -TaskPath $TASK_PATH -TaskName $TASK_NAME -ErrorAction Stop Write-Log "Scheduled task triggered: ${TASK_PATH}${TASK_NAME}." return $true } catch { Write-Log "Scheduled task trigger failed: $($_.Exception.Message)" "WARN" return $false } } function Test-NotificationCooldown { param([datetime]$LastNotificationTime) if ($NOTIFICATION_COOLDOWN_HOURS -le 0) { return $true } if (-not $LastNotificationTime) { return $true } return (((Get-Date) - $LastNotificationTime).TotalHours -ge $NOTIFICATION_COOLDOWN_HOURS) } function Register-RestartNotificationHelper { param([datetime]$LastNotificationTime) if (-not (Test-NotificationCooldown -LastNotificationTime $LastNotificationTime)) { Write-Log "Restart notification helper skipped due to cooldown. LastNotificationTime=$LastNotificationTime." return $false } try { $HelperRoot = "C:\ProgramData\SecureBootCA2023" $PopupScript = Join-Path $HelperRoot "RestartNotification.ps1" $UserLogPath = Join-Path $HelperRoot "RestartPopup-UserSession.log" $TaskName = "SecureBoot_Remediation_Notice" $TaskPath = "\SecureBootCA2023\" $HelperRegPath = "HKLM:\SOFTWARE\WPN\SecureBootCA2023" if (-not (Test-Path $HelperRoot)) { New-Item -Path $HelperRoot -ItemType Directory -Force | Out-Null } if (-not (Test-Path $HelperRegPath)) { New-Item -Path $HelperRegPath -Force | Out-Null } New-ItemProperty -Path $HelperRegPath -Name "RestartRequired" -PropertyType DWord -Value 1 -Force | Out-Null New-ItemProperty -Path $HelperRegPath -Name "Reason" -PropertyType String -Value "Secure Boot CA 2023 migration requires a restart." -Force | Out-Null New-ItemProperty -Path $HelperRegPath -Name "LastRemediationTime" -PropertyType String -Value (Get-Date).ToString("o") -Force | Out-Null $PopupContent = @' <--- popup script content unchanged ---> '@ Set-Content -Path $PopupScript -Value $PopupContent -Encoding UTF8 -Force try { $acl = Get-Acl $HelperRoot $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Users", "Modify", "ContainerInherit,ObjectInherit", "None", "Allow") $acl.SetAccessRule($accessRule) Set-Acl -Path $HelperRoot -AclObject $acl } catch { Write-Log "Failed to set helper folder ACL: $($_.Exception.Message)" "WARN" } Unregister-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -Confirm:$false -ErrorAction SilentlyContinue $Action = New-ScheduledTaskAction ` -Execute "$env:WINDIR\System32\WindowsPowerShell\v1.0\powershell.exe" ` -Argument "-NoProfile -ExecutionPolicy Bypass -Sta -File `"$PopupScript`"" $TriggerTime = (Get-Date).AddSeconds(15) $Trigger = New-ScheduledTaskTrigger -Once -At $TriggerTime $UsersGroup = ([System.Security.Principal.SecurityIdentifier]"S-1-5-32-545").Translate([System.Security.Principal.NTAccount]).Value $Principal = New-ScheduledTaskPrincipal -GroupId $UsersGroup Register-ScheduledTask ` -TaskName $TaskName ` -TaskPath $TaskPath ` -Action $Action ` -Trigger $Trigger ` -Principal $Principal ` -Force | Out-Null Write-Log "Restart notification task registered successfully." return $true } catch { Write-Log "Failed to register restart notification task. Error: $($_.Exception.Message)" "WARN" return $false } } # Main Write-Log "Remediation starting on $env:COMPUTERNAME. NonCompliantValue='$NonCompliantValue'." if (-not [Environment]::Is64BitProcess) { Write-Log "64-bit PowerShell is required. Script ran in 32-bit process." "ERROR" Write-EventEntry -Message "Secure Boot CA 2023 remediation failed: 64-bit PowerShell required on $env:COMPUTERNAME." -EventId 2023 -EntryType "Error" exit 1 } try { $secureBootEnabled = Confirm-SecureBootUEFI -ErrorAction Stop } catch { $secureBootEnabled = $false } Write-Log "Secure Boot enabled: $secureBootEnabled." if (-not $secureBootEnabled) { Write-Log "Secure Boot is disabled or UEFI unavailable. Skipping remediation." Write-EventEntry -Message "Secure Boot CA 2023 remediation skipped: Secure Boot disabled or UEFI unavailable on $env:COMPUTERNAME." -EventId 2024 -EntryType "Warning" exit 0 } $meta = Get-RemediationMetadata Write-Log "Metadata before remediation: FirstRun=$($meta.FirstRunDate); Attempts=$($meta.AttemptCount); LastNotificationTime=$($meta.LastNotificationTime)." $registryUpdated = Set-AvailableUpdates if (-not $registryUpdated) { Write-Log "Registry update failed. Aborting remediation." "ERROR" Write-EventEntry -Message "Secure Boot CA 2023 remediation failed: could not set AvailableUpdates on $env:COMPUTERNAME." -EventId 2026 -EntryType "Error" exit 1 } $taskTriggered = Start-SecureBootUpdateTask $newAttemptCount = $meta.AttemptCount + 1 $firstRunDate = if ($meta.FirstRunDate) { $meta.FirstRunDate } else { Get-Date } $notificationSent = Register-RestartNotificationHelper -LastNotificationTime $meta.LastNotificationTime $lastNotificationTime = if ($notificationSent) { Get-Date } else { $meta.LastNotificationTime } Set-RemediationMetadata -FirstRunDate $firstRunDate -AttemptCount $newAttemptCount -LastNotificationTime $lastNotificationTime $message = "Secure Boot CA 2023 remediation completed. Attempts=$newAttemptCount; TaskTriggered=$taskTriggered; RestartNotificationSent=$notificationSent; Restart may be required on $env:COMPUTERNAME." Write-Log $message Write-EventEntry -Message $message -EventId 2027 -EntryType "Information" Write-Output "RemediationCompleted" exit 0 |