Note
IMPORTANT This article containing this sample script has been retired. Starting with the Windows updates released on and after May 12, 2026, the sample script is located in the %systemroot%\SecureBoot\ExampleRolloutScripts folder on your device.
Copy and paste this sample script and modify as needed for your environment:
Note
<#
.SYNOPSIS
Enables the Secure Boot Update scheduled task..DESCRIPTION
This script ensures the Windows Secure Boot Update scheduled task
(\Microsoft\Windows\PI\Secure-Boot-Update) is enabled. If disabled,
it enables it. If the task was deleted, it can recreate it..PARAMETER Action
The action to perform. Valid values: check, enable, create
- check: Only check the task status
- enable: (default) Enable the task if disabled. If task is missing, prompts to create.
- create: Create the task if it doesn't exist.PARAMETER ComputerName
Optional. Array of computer names to check/enable the task on.
If not specified, runs on the local machine..PARAMETER Credential
Optional. Credentials for remote computer access..PARAMETER Quiet
Suppresses prompts and automatically answers Yes. Useful for automation..EXAMPLE
.\Enable-SecureBootTask.ps1
# Enables the task status on local machine.EXAMPLE
.\Check-SecureBootScheduledTask.ps1 enable
# Enables the task if disabled. Prompts to create if missing..EXAMPLE
.\Check-SecureBootScheduledTask.ps1 create
# Creates the task if it was deleted, then checks its status.EXAMPLE
.\Check-SecureBootScheduledTask.ps1 check -ComputerName "PC1", "PC2"
# Checks the task on remote machines.NOTES
Requires administrator privileges to enable or create the task.
Task Path: \Microsoft\Windows\PI\Secure-Boot-Update
Task runs taskhostw.exe every 12 hours with elevated privileges.
#>[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Position=0)]
[ValidateSet('check', 'enable', 'create', '')]
[string]$Action = 'enable',[Parameter()]
[string[]]$ComputerName,[Parameter()]
[PSCredential]$Credential,[Parameter()]
[Alias('Force', 'Silent')]
[switch]$Quiet
)# Convert Action to switches for backward compatibility
$Enable = $Action -eq 'enable'
$Create = $Action -eq 'create'# Download URL: https://aka.ms/getsecureboot -> "Deployment and Monitoring Samples"
Note: This script runs on endpoints to enable the Secure Boot Update task.
$TaskPath = "\Microsoft\Windows\PI\"
$TaskName = "Secure-Boot-Update"function Get-SecureBootTaskStatus {
[CmdletBinding()]
param(
[string]$Computer = $env:COMPUTERNAME
)$result = [PSCustomObject]@{
ComputerName = $Computer
TaskExists = $false
TaskState = $null
IsEnabled = $false
LastRunTime = $null
NextRunTime = $null
Error = $null
}try {
if ($Computer -eq $env:COMPUTERNAME -or $Computer -eq "localhost" -or $Computer -eq ".") {
# Use schtasks.exe for more reliable task detection
$schtasksOutput = schtasks.exe /Query /TN "$TaskPath$TaskName" /FO CSV 2>&1
if ($LASTEXITCODE -ne 0) {
# Task not found is not an error - just means task doesn't exist
$result.TaskExists = $false
return $result
}
# Parse CSV output
$taskData = $schtasksOutput | ConvertFrom-Csv
if ($taskData) {
$result.TaskExists = $true
$result.TaskState = $taskData.Status
$result.IsEnabled = ($taskData.Status -eq 'Ready' -or $taskData.Status -eq 'Running')
# Try to get next run time from the data
if ($taskData.'Next Run Time' -and $taskData.'Next Run Time' -ne 'N/A') {
try {
$result.NextRunTime = [DateTime]::Parse($taskData.'Next Run Time')
} catch { }
}
}
}
else {
# Remote computer - use Invoke-Command with schtasks
$remoteResult = Invoke-Command -ComputerName $Computer -ScriptBlock {
param($fullTaskName)
$output = schtasks.exe /Query /TN $fullTaskName /FO CSV 2>&1
@{
ExitCode = $LASTEXITCODE
Output = $output
}
} -ArgumentList "$TaskPath$TaskName" -ErrorAction Stopif ($remoteResult.ExitCode -ne 0) {
# Task not found is not an error - just means task doesn't exist
$result.TaskExists = $false
return $result
}$taskData = $remoteResult.Output | ConvertFrom-Csv
if ($taskData) {
$result.TaskExists = $true
$result.TaskState = $taskData.Status
$result.IsEnabled = ($taskData.Status -eq 'Ready' -or $taskData.Status -eq 'Running')
}
}
}
catch {
$result.Error = $_.Exception.Message
}return $result
}function New-SecureBootTask {
[CmdletBinding(SupportsShouldProcess)]
param(
[string]$Computer = $env:COMPUTERNAME
)$success = $false
$errorMsg = $null# Task definition - matches the original Windows Secure Boot Update task
# Uses ComHandler with SBServicing class, runs as LocalSystem
$taskXml = @"
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.6" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2012-02-07T16:39:20</Date>
<SecurityDescriptor>O:BAG:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS)</SecurityDescriptor>
<Source>`$(@%SystemRoot%\system32\TpmTasks.dll,-601)</Source>
<Author>`$(@%SystemRoot%\system32\TpmTasks.dll,-600)</Author>
<Description>`$(@%SystemRoot%\system32\TpmTasks.dll,-604)</Description>
<URI>\Microsoft\Windows\PI\Secure-Boot-Update</URI>
</RegistrationInfo>
<Principals>
<Principal id="LocalSystem">
<UserId>S-1-5-18</UserId>
</Principal>
</Principals>
<Settings>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<StartWhenAvailable>true</StartWhenAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
</Settings>
<Triggers>
<BootTrigger>
<Delay>PT5M</Delay>
<Repetition>
<Interval>PT12H</Interval>
</Repetition>
</BootTrigger>
</Triggers>
<Actions Context="LocalSystem">
<ComHandler>
<ClassId>{5014B7C8-934E-4262-9816-887FA745A6C4}</ClassId>
<Data><![CDATA[SBServicing]]></Data>
</ComHandler>
</Actions>
</Task>
"@try {
if ($Computer -eq $env:COMPUTERNAME -or $Computer -eq "localhost" -or $Computer -eq ".") {
if ($PSCmdlet.ShouldProcess("$TaskPath$TaskName", "Create scheduled task")) {
# Save XML to temp file and import
$tempFile = [System.IO.Path]::GetTempFileName()
$taskXml | Out-File -FilePath $tempFile -Encoding Unicode -Force
$output = schtasks.exe /Create /TN "$TaskPath$TaskName" /XML $tempFile /F 2>&1
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
if ($LASTEXITCODE -eq 0) {
$success = $true
} else {
$errorMsg = $output -join " "
}
}
}
else {
if ($PSCmdlet.ShouldProcess("$Computer\$TaskPath$TaskName", "Create scheduled task")) {
$result = Invoke-Command -ComputerName $Computer -ScriptBlock {
param($taskPath, $taskName, $xml)
$tempFile = [System.IO.Path]::GetTempFileName()
$xml | Out-File -FilePath $tempFile -Encoding Unicode -Force
$output = schtasks.exe /Create /TN "$taskPath$taskName" /XML $tempFile /F 2>&1
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
@{ ExitCode = $LASTEXITCODE; Output = $output }
} -ArgumentList $TaskPath, $TaskName, $taskXml -ErrorAction Stop
if ($result.ExitCode -eq 0) {
$success = $true
} else {
$errorMsg = $result.Output -join " "
}
}
}
}
catch {
$errorMsg = $_.Exception.Message
}return @{
Success = $success
Error = $errorMsg
}
}function Enable-SecureBootTask {
[CmdletBinding(SupportsShouldProcess)]
param(
[string]$Computer = $env:COMPUTERNAME
)$success = $false
$errorMsg = $nulltry {
if ($Computer -eq $env:COMPUTERNAME -or $Computer -eq "localhost" -or $Computer -eq ".") {
if ($PSCmdlet.ShouldProcess("$TaskPath$TaskName", "Enable scheduled task")) {
$output = schtasks.exe /Change /TN "$TaskPath$TaskName" /ENABLE 2>&1
if ($LASTEXITCODE -eq 0) {
$success = $true
} else {
$errorMsg = $output -join " "
}
}
}
else {
if ($PSCmdlet.ShouldProcess("$Computer\$TaskPath$TaskName", "Enable scheduled task")) {
$result = Invoke-Command -ComputerName $Computer -ScriptBlock {
param($fullTaskName)
$output = schtasks.exe /Change /TN $fullTaskName /ENABLE 2>&1
@{ ExitCode = $LASTEXITCODE; Output = $output }
} -ArgumentList "$TaskPath$TaskName" -ErrorAction Stop
if ($result.ExitCode -eq 0) {
$success = $true
} else {
$errorMsg = $result.Output -join " "
}
}
}
}
catch {
$errorMsg = $_.Exception.Message
}return @{
Success = $success
Error = $errorMsg
}
}# Main execution
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Secure Boot Update Task Enabler" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Task: $TaskPath$TaskName" -ForegroundColor Gray
Write-Host ""# Determine target computers
$targets = if ($ComputerName) { $ComputerName } else { @($env:COMPUTERNAME) }$results = @()foreach ($computer in $targets) {
Write-Host "Checking: $computer" -ForegroundColor Yellow
$status = Get-SecureBootTaskStatus -Computer $computer
if ($status.Error) {
Write-Host " Error: $($status.Error)" -ForegroundColor Red
}
elseif (-not $status.TaskExists) {
Write-Host " Task does not exist on this system" -ForegroundColor Red
# Create if requested, or prompt if Enable was specified
$shouldCreate = $Create
if (-not $shouldCreate -and $Enable) {
Write-Host ""
Write-Host " The task may have been deleted." -ForegroundColor Yellow
if ($Quiet) {
Write-Host " Auto-creating task (Quiet mode)" -ForegroundColor Cyan
$shouldCreate = $true
} else {
$confirm = Read-Host " Do you want to recreate the task? (Y/N)"
if ($confirm -eq 'Y' -or $confirm -eq 'y') {
$shouldCreate = $true
}
}
}
if ($shouldCreate) {
Write-Host " Creating task..." -ForegroundColor Yellow
$createResult = New-SecureBootTask -Computer $computer
if ($createResult.Success) {
Write-Host " Task created successfully" -ForegroundColor Green
# Re-check status
$status = Get-SecureBootTaskStatus -Computer $computer
if ($status.TaskExists) {
$stateColor = if ($status.IsEnabled) { "Green" } else { "Red" }
Write-Host " State: $($status.TaskState)" -ForegroundColor $stateColor
}
}
else {
Write-Host " Failed to create: $($createResult.Error)" -ForegroundColor Red
}
}
}
else {
$stateColor = if ($status.IsEnabled) { "Green" } else { "Red" }
Write-Host " State: $($status.TaskState)" -ForegroundColor $stateColor
if ($status.LastRunTime -and $status.LastRunTime -ne [DateTime]::MinValue) {
Write-Host " Last Run: $($status.LastRunTime)" -ForegroundColor Gray
}
if ($status.NextRunTime -and $status.NextRunTime -ne [DateTime]::MinValue) {
Write-Host " Next Run: $($status.NextRunTime)" -ForegroundColor Gray
}# Enable if requested and currently disabled
if ($Enable -and -not $status.IsEnabled) {
Write-Host " Enabling task..." -ForegroundColor Yellow
$enableResult = Enable-SecureBootTask -Computer $computer
if ($enableResult.Success) {
Write-Host " Task enabled successfully" -ForegroundColor Green
# Re-check status
$status = Get-SecureBootTaskStatus -Computer $computer
}
else {
Write-Host " Failed to enable: $($enableResult.Error)" -ForegroundColor Red
}
}
elseif ($Enable -and $status.IsEnabled) {
Write-Host " Task is already enabled" -ForegroundColor Green
}
}
$results += $status
Write-Host ""
}# Summary
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " Summary" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan$enabled = ($results | Where-Object { $_.IsEnabled }).Count
$disabled = ($results | Where-Object { $_.TaskExists -and -not $_.IsEnabled }).Count
$notFound = ($results | Where-Object { -not $_.TaskExists }).Count
$errors = ($results | Where-Object { $_.Error }).CountWrite-Host "Total Checked: $($results.Count)"
Write-Host "Enabled: $enabled" -ForegroundColor Green
if ($disabled -gt 0) { Write-Host "Disabled: $disabled" -ForegroundColor Red }
if ($notFound -gt 0) { Write-Host "Not Found: $notFound" -ForegroundColor Yellow }
if ($errors -gt 0) { Write-Host "Errors: $errors" -ForegroundColor Red }# Return results for pipeline
$results