Sample Get-SecureBootRolloutStatus.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  
    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  
#&gt;
- `[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 -&gt; $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  
}