Sample Enable-SecureBootUpdateTask.ps1 script

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.  
#&gt;
- `[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&gt;&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&gt;&1  
                @{  
                    ExitCode = $LASTEXITCODE  
                    Output = $output  
                }  
            } -ArgumentList "$TaskPath$TaskName" -ErrorAction Stop
- `            if ($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 = @"  
&lt;?xml version="1.0" encoding="UTF-16"?&gt;  
&lt;Task version="1.6" xmlns="http:⁠//schemas.microsoft.com/windows/2004/02/mit/task"&gt;  
  &lt;RegistrationInfo&gt;  
    &lt;Date&gt;2012-02-07T16:39:20&lt;/Date&gt;  
    &lt;SecurityDescriptor&gt;O:BAG:BAD:P(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS)&lt;/SecurityDescriptor&gt;  
    &lt;Source&gt;\`$(@%SystemRoot%\\system32\\TpmTasks.dll,-601)&lt;/Source&gt;  
    &lt;Author&gt;\`$(@%SystemRoot%\\system32\\TpmTasks.dll,-600)&lt;/Author&gt;  
    &lt;Description&gt;\`$(@%SystemRoot%\\system32\\TpmTasks.dll,-604)&lt;/Description&gt;  
    &lt;URI&gt;\\Microsoft\\Windows\\PI\\Secure-Boot-Update&lt;/URI&gt;  
  &lt;/RegistrationInfo&gt;  
  &lt;Principals&gt;  
    &lt;Principal id="LocalSystem"&gt;  
      &lt;UserId&gt;S-1-5-18&lt;/UserId&gt;  
    &lt;/Principal&gt;  
  &lt;/Principals&gt;  
  &lt;Settings&gt;  
    &lt;DisallowStartIfOnBatteries&gt;false&lt;/DisallowStartIfOnBatteries&gt;  
    &lt;StopIfGoingOnBatteries&gt;false&lt;/StopIfGoingOnBatteries&gt;  
    &lt;ExecutionTimeLimit&gt;PT1H&lt;/ExecutionTimeLimit&gt;  
    &lt;MultipleInstancesPolicy&gt;IgnoreNew&lt;/MultipleInstancesPolicy&gt;  
    &lt;StartWhenAvailable&gt;true&lt;/StartWhenAvailable&gt;  
    &lt;IdleSettings&gt;  
      &lt;StopOnIdleEnd&gt;true&lt;/StopOnIdleEnd&gt;  
      &lt;RestartOnIdle&gt;false&lt;/RestartOnIdle&gt;  
    &lt;/IdleSettings&gt;  
    &lt;UseUnifiedSchedulingEngine&gt;true&lt;/UseUnifiedSchedulingEngine&gt;  
  &lt;/Settings&gt;  
  &lt;Triggers&gt;  
    &lt;BootTrigger&gt;  
      &lt;Delay&gt;PT5M&lt;/Delay&gt;  
      &lt;Repetition&gt;  
        &lt;Interval&gt;PT12H&lt;/Interval&gt;  
      &lt;/Repetition&gt;  
    &lt;/BootTrigger&gt;  
  &lt;/Triggers&gt;  
  &lt;Actions Context="LocalSystem"&gt;  
    &lt;ComHandler&gt;  
      &lt;ClassId&gt;{5014B7C8-934E-4262-9816-887FA745A6C4}&lt;/ClassId&gt;  
      &lt;Data&gt;&lt;!\[CDATA\[SBServicing\]\]&gt;&lt;/Data&gt;  
    &lt;/ComHandler&gt;  
  &lt;/Actions&gt;  
&lt;/Task&gt;  
"@
- `    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&gt;&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&gt;&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 = $null
- `    try {`  
        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&gt;&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&gt;&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 }).Count
- `Write-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