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
Shows the current status of the Secure Boot rollout orchestrator.
- `.DESCRIPTION`
Provides real-time visibility into the rollout progress:
- Current wave number and devices targeted
- Devices updated vs pending
- Blocked buckets requiring attention
- Recent activity log
- Dashboard link
Run this anytime to see how the rollout is progressing.
- `.PARAMETER ReportBasePath`
Path to the report/state directory used by the orchestrator
- `.PARAMETER ShowLog`
Display recent log entries (last 50 lines)
- `.PARAMETER ShowBlocked`
Show details of blocked buckets
- `.PARAMETER ShowWaves`
Show wave history with device counts
- `.PARAMETER Watch`
Continuously refresh status every N seconds
- `.PARAMETER OpenDashboard`
Open the latest HTML dashboard in browser
- `.EXAMPLE`
.\\Get-SecureBootRolloutStatus.ps1 -ReportBasePath "C:\\SecureBootReports"
- `.EXAMPLE`
.\\Get-SecureBootRolloutStatus.ps1 -ReportBasePath "C:\\SecureBootReports" -Watch 30
- `.EXAMPLE`
.\\Get-SecureBootRolloutStatus.ps1 -ReportBasePath "C:\\SecureBootReports" -OpenDashboard
#>
- `[CmdletBinding()]`
param(
\[Parameter(Mandatory = $true)\]
\[string\]$ReportBasePath,
\[Parameter(Mandatory = $false)\]
\[switch\]$ShowLog,
\[Parameter(Mandatory = $false)\]
\[switch\]$ShowBlocked,
\[Parameter(Mandatory = $false)\]
\[switch\]$ShowWaves,
\[Parameter(Mandatory = $false)\]
\[int\]$Watch = 0,
\[Parameter(Mandatory = $false)\]
\[switch\]$OpenDashboard
)
- `$ErrorActionPreference = "Stop"`
$DownloadUrl = "https://aka.ms/getsecureboot"
$DownloadSubPage = "Deployment and Monitoring Samples"
- `# Note: This script has no dependencies on other scripts.`
# For the complete toolset, download from: $DownloadUrl -> $DownloadSubPage
- `# ============================================================================`
# HELPER FUNCTIONS
# ============================================================================
- `function ConvertTo-Hashtable {`
param(\[Parameter(ValueFromPipeline = $true)\]$InputObject)
process {
if ($null -eq $InputObject) { return @{} }
if ($InputObject -is \[System.Collections.IDictionary\]) { return $InputObject }
if ($InputObject -is \[PSCustomObject\]) {
$hash = @{}
foreach ($prop in $InputObject.PSObject.Properties) {
$hash\[$prop.Name\] = ConvertTo-Hashtable $prop.Value
}
return $hash
}
if ($InputObject -is \[System.Collections.IEnumerable\] -and $InputObject -isnot \[string\]) {
return @($InputObject | ForEach-Object { ConvertTo-Hashtable $\_ })
}
return $InputObject
}
}
- `function Show-Status {`
$stateDir = Join-Path $ReportBasePath "RolloutState"
$rolloutStatePath = Join-Path $stateDir "RolloutState.json"
$blockedBucketsPath = Join-Path $stateDir "BlockedBuckets.json"
Clear-Host
Write-Host ""
Write-Host ("=" \* 80) -ForegroundColor Cyan
Write-Host " SECURE BOOT ROLLOUT STATUS" -ForegroundColor Cyan
Write-Host " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Gray
Write-Host ("=" \* 80) -ForegroundColor Cyan
Write-Host ""
# Check if orchestrator task is running
$task = Get-ScheduledTask -TaskName "SecureBoot-Rollout-Orchestrator" -ErrorAction SilentlyContinue
if ($task) {
$taskState = $task.State
$color = if ($taskState -eq "Running") { "Green" } elseif ($taskState -eq "Ready") { "Yellow" } else { "Red" }
Write-Host "Scheduled Task: " -NoNewline
Write-Host $taskState -ForegroundColor $color
} else {
Write-Host "Scheduled Task: " -NoNewline
Write-Host "Not Installed" -ForegroundColor Gray
}
# Load rollout state
if (-not (Test-Path $rolloutStatePath)) {
Write-Host ""
Write-Host "No rollout state found. Orchestrator may not have started yet." -ForegroundColor Yellow
Write-Host "State path: $rolloutStatePath" -ForegroundColor Gray
return
}
$state = Get-Content $rolloutStatePath -Raw | ConvertFrom-Json | ConvertTo-Hashtable
Write-Host ""
Write-Host "ROLLOUT PROGRESS" -ForegroundColor Yellow
Write-Host ("-" \* 40)
$status = $state.Status
$statusColor = switch ($status) {
"Completed" { "Green" }
"InProgress" { "Cyan" }
"NotStarted" { "Gray" }
default { "White" }
}
Write-Host "Status: " -NoNewline
Write-Host $status -ForegroundColor $statusColor
Write-Host "Current Wave: $($state.CurrentWave)"
Write-Host "Total Targeted: $($state.TotalDevicesTargeted)"
Write-Host "Total Updated: $($state.TotalDevicesUpdated)"
if ($state.StartedAt) {
Write-Host "Started: $($state.StartedAt)"
}
if ($state.LastAggregation) {
Write-Host "Last Check: $($state.LastAggregation)"
}
if ($state.CompletedAt) {
Write-Host "Completed: $($state.CompletedAt)" -ForegroundColor Green
}
# Show progress bar
if ($state.TotalDevicesTargeted -gt 0) {
$pct = if ($state.TotalDevicesUpdated -and $state.TotalDevicesTargeted) {
\[math\]::Round(($state.TotalDevicesUpdated / $state.TotalDevicesTargeted) \* 100, 1)
} else { 0 }
Write-Host ""
Write-Host "Progress: " -NoNewline
$barWidth = 40
$filled = \[math\]::Floor($barWidth \* $pct / 100)
Write-Host "\[" -NoNewline
Write-Host ("█" \* $filled) -ForegroundColor Green -NoNewline
Write-Host ("░" \* ($barWidth - $filled)) -ForegroundColor DarkGray -NoNewline
Write-Host "\] $pct%"
}
# Blocked buckets summary
if (Test-Path $blockedBucketsPath) {
$blocked = Get-Content $blockedBucketsPath -Raw | ConvertFrom-Json | ConvertTo-Hashtable
if ($blocked.Count -gt 0) {
Write-Host ""
Write-Host "BLOCKED BUCKETS: " -NoNewline -ForegroundColor Red
Write-Host "$($blocked.Count) buckets need attention" -ForegroundColor Red
if ($ShowBlocked) {
Write-Host ""
foreach ($key in $blocked.Keys) {
$info = $blocked\[$key\]
Write-Host " ► $key" -ForegroundColor Red
Write-Host " Reason: $($info.Reason)" -ForegroundColor Gray
Write-Host " Device: $($info.FailedDevice)" -ForegroundColor Gray
Write-Host " Since: $($info.BlockedAt)" -ForegroundColor Gray
}
} else {
Write-Host " Run with -ShowBlocked for details" -ForegroundColor Gray
}
}
}
# Wave history
if ($ShowWaves -and $state.WaveHistory -and $state.WaveHistory.Count -gt 0) {
Write-Host ""
Write-Host "WAVE HISTORY" -ForegroundColor Yellow
Write-Host ("-" \* 40)
foreach ($wave in $state.WaveHistory) {
Write-Host "Wave $($wave.WaveNumber): " -NoNewline -ForegroundColor Cyan
Write-Host "$($wave.DeviceCount) devices" -NoNewline
Write-Host " - $($wave.StartedAt)" -ForegroundColor Gray
}
}
# Latest dashboard
$latestAggregation = Get-ChildItem -Path $ReportBasePath -Directory -Filter "Aggregation\_\*" -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
if ($latestAggregation) {
$dashboard = Get-ChildItem -Path $latestAggregation.FullName -Filter "\*Dashboard\*.html" -ErrorAction SilentlyContinue |
Select-Object -First 1
if ($dashboard) {
Write-Host ""
Write-Host "LATEST DASHBOARD" -ForegroundColor Yellow
Write-Host $dashboard.FullName -ForegroundColor Gray
if ($OpenDashboard) {
Start-Process $dashboard.FullName
}
}
}
# Recent log
if ($ShowLog) {
$logFile = Get-ChildItem -Path $stateDir -Filter "Orchestrator\_\*.log" -ErrorAction SilentlyContinue |
Sort-Object Name -Descending |
Select-Object -First 1
if ($logFile) {
Write-Host ""
Write-Host "RECENT LOG" -ForegroundColor Yellow
Write-Host ("-" \* 40)
Get-Content $logFile.FullName -Tail 20 | ForEach-Object {
if ($\_ -match '\\\[ERROR\\\]') {
Write-Host $\_ -ForegroundColor Red
} elseif ($\_ -match '\\\[WARN\\\]') {
Write-Host $\_ -ForegroundColor Yellow
} elseif ($\_ -match '\\\[OK\\\]') {
Write-Host $\_ -ForegroundColor Green
} elseif ($\_ -match '\\\[WAVE\\\]') {
Write-Host $\_ -ForegroundColor Cyan
} else {
Write-Host $\_ -ForegroundColor Gray
}
}
}
}
Write-Host ""
Write-Host ("-" \* 80) -ForegroundColor DarkGray
if (-not $ShowLog -or -not $ShowWaves -or -not $ShowBlocked) {
Write-Host "Options: -ShowLog | -ShowWaves | -ShowBlocked | -OpenDashboard | -Watch 30" -ForegroundColor DarkGray
}
}
- `# ============================================================================`
# MAIN
# ============================================================================
- `if (-not (Test-Path $ReportBasePath)) {`
Write-Host "Report path not found: $ReportBasePath" -ForegroundColor Red
exit 1
}
- `if ($Watch -gt 0) {`
Write-Host "Watching status every $Watch seconds. Press Ctrl+C to stop." -ForegroundColor Cyan
while ($true) {
Show-Status
Start-Sleep -Seconds $Watch
}
} else {
Show-Status
}