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
    #>
  • [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
    }