重要 本條目包含此範例腳本的文章已退休。 從 2026 年 5 月 12 日及之後發布的 Windows 更新開始,範例腳本位於您裝置的 %systemroot%\SecureBoot\ExampleRolloutScripts 資料夾中。
複製貼上這個範例腳本,並根據你的環境進行修改:
<# .劇情簡介 將安全啟動部署協調器作為 Windows 排程任務。
.DESCRIPTION 建立一個排程任務,讓編排器在背景持續執行。任務執行時會以繞過執行策略執行,因此不會出現安全提示。 策劃者將: - 在指定區間內輪詢裝置更新 - 自動產生波次並部署 GPO - 持續直到所有符合資格的裝置更新 為止 使用以下方法監控進度:Get-SecureBootRolloutStatus.ps1
.PARAMETER AggregationInputPath UNC 從偵測 GPO) (的 JSON 裝置資料路徑
.PARAMETER ReportBasePath 報告與狀態檔案的本地路徑
.PARAMETER TargetOU OU 連結 GPO (可選,預設為網域根)
.PARAMETER PollIntervalMinutes 狀態檢查之間的幾分鐘。 預設值:30
.PARAMETER UseWinCS 使用 Windows 組態系統) WinCS (取代 AvailableUpdatesPolicy GPO。啟用後,會將 WinCsFlags.exe 排程任務部署到端點,而非登錄檔 GPO。
.PARAMETER WinCSKey WinCS 用於安全開機設定的金鑰。 預設:F33E0C8E002
.PARAMETER ServiceAccount 帳號來執行任務。 預設:系統 網域操作時,請使用網域管理員服務帳號。
.PARAMETER AllowListPath 包含主機名稱的檔案路徑,允許部署 (目標/試點部署) 。支援每行) .txt (一個主機名稱,.csv (欄位為 Hostname/ComputerName/Name 欄位) 。在指定時,只有這些裝置會納入推廣範圍。
.PARAMETER AllowADGroup 包含電腦帳號的 AD 安全群組名稱,允許。範例:「SecureBoot-Pilot-Computers」
.PARAMETER ExclusionListPath 包含主機名稱的檔案路徑,需排除 VIP/行政設備 () 。支援每行) .txt (一個主機名稱,.csv (欄位為 Hostname/ComputerName/Name 欄位) 。
.PARAMETER ExcludeADGroup 包含要排除的電腦帳號的 AD 安全群組名稱。範例:「VIP電腦」
.PARAMETER ScriptPath 通往編排器腳本的路徑。 預設值:與這個腳本相同的資料夾。
.PARAMETER Uninstall 移除排程任務
.EXAMPLE .\Deploy-OrchestratorTask.ps1 -AggregationInputPath “\\server\SecureBootData$” - ReportBasePath “C:\SecureBootReports” - ServiceAccount “DOMAIN\svc_secureboot”
.EXAMPLE .\Deploy-OrchestratorTask.ps1 -AggregationInputPath “\\server\SecureBootData$” -ReportBasePath “C:\SecureBootReports”
.EXAMPLE # 使用 WinCS 方法部署,而非 AvailableUpdatesPolicy .\Deploy-OrchestratorTask.ps1 -AggregationInputPath “\\server\SecureBootData$” - ReportBasePath “C:\SecureBootReports” - UseWinCS
.EXAMPLE .\Deploy-OrchestratorTask.ps1 -卸載 #>
[CmdletBinding()] 參數 ( [參數 (強制 = $false) ] [弦]$AggregationInputPath, [參數 (強制 = $false) ] [string]$ReportBasePath, [參數 (強制 = $false) ] [string]$TargetOU, [參數 (強制 = $false) ] [int]$PollIntervalMinutes = 30, [參數 (強制 = $false) ] [開關]$UseWinCS, [參數 (強制 = $false) ] [字串]$WinCSKey = 「F33E0C8E002」, [參數 (強制 = $false) ] [字串]$ServiceAccount = 「系統」, [參數 (強制 = $false) ] [string]$AllowListPath, [參數 (強制 = $false) ] [string]$AllowADGroup, [參數 (強制 = $false) ] [string]$ExclusionListPath, [參數 (強制 = $false) ] [string]$ExcludeADGroup, [參數 (強制 = $false) ] [string]$ScriptPath, [參數 (強制 = $false) ] [切換]$Uninstall )
$ErrorActionPreference = "Stop" $TaskName = 「SecureBoot-Rollout-Orchestrator」 $DownloadUrl = 「https://aka.ms/getsecureboot」 $DownloadSubPage = 「部署與監控樣本」
# ================================================================== # 依賴驗證# ==================================================================
function Test-ScriptDependencies { <# .劇情簡介 驗證所有必要的腳本都已具備。.描述 檢查腳本依賴性,若缺少則提供下載說明。#> 參數 ( [參數 (強制 = $true) ] [string]$ScriptDirectory, [參數 (強制 = $true) ] [string[]]$RequiredScripts ) $missingScripts = @ () $RequiredScripts) 中每個 ($script { $scriptPath = Join-Path $ScriptDirectory $script 如果 (-not (測試路徑$scriptPath) ) { $missingScripts += $script } } 如果 ($missingScripts.Count -gt 0) { Write-Host「」 Write-Host (“=” * 70) -前景紅色 Write-Host 「缺少依賴性」-前景紅色 Write-Host (“=” * 70) -前景紅色 Write-Host「」 Write-Host 「未找到以下所需的腳本:」-ForegroundColor Yellow $missingScripts) 中每個 ($script { Write-Host “ - $script” - 前景白色 } Write-Host「」 Write-Host 「請下載最新腳本來源:」-ForegroundColor Cyan Write-Host 「網址:$DownloadUrl」-前景白色 Write-Host 「導航至:『$DownloadSubPage』」-前景白色 Write-Host「」 Write-Host 「將所有腳本解壓到同一目錄,然後重新執行。」-ForegroundColor 黃色 Write-Host「」 $false } $true }
# Required scripts for orchestrator deployment $requiredScripts = @ ( 「Start-SecureBootRolloutOrchestrator.ps1」, 「Aggregate-SecureBootData.ps1」, 「Deploy-GPO-SecureBootCollection.ps1」, 「Detect-SecureBootCertUpdateStatus.ps1」, 「Get-SecureBootRolloutStatus.ps1」, 「Enable-SecureBootUpdateTask.ps1」 )
if (-not (Test-ScriptDependencies -ScriptDirectory $PSScriptRoot -RequiredScripts $requiredScripts)) { 出口1 }
# ================================================================== # 解除安裝# ==================================================================
if ($Uninstall) { Write-Host「」 Write-Host「移除排程任務:$TaskName」-前景色黃 $existingTask = Get-ScheduledTask -任務名稱 $TaskName -ErrorAction 靜默繼續 如果 ($existingTask) { Stop-ScheduledTask -任務名稱 $TaskName -錯誤動作靜默繼續 Unregister-ScheduledTask -任務名稱 $TaskName -確認:$false Write-Host「任務成功移除。」-前景綠色 } 否則 { Write-Host「任務未找到。」-前景灰色 } 出口0 }
# ================================================================== # 驗證# ==================================================================
if (-not $AggregationInputPath -or -not $ReportBasePath) { Write-Host 「錯誤:-AggregationInputPath 與 -ReportBasePath 是必需的。」-ForegroundColor Red Write-Host「」 Write-Host 「範例:」-前景色 黃色 Write-Host ' .\Deploy-OrchestratorTask.ps1 -AggregationInputPath “\\server\SecureBootData$” -ReportBasePath “C:\SecureBootReports”' 出口1 }
# Find orchestrator script 如果 (-不$ScriptPath) { $ScriptPath = Join-Path $PSScriptRoot「Start-SecureBootRolloutOrchestrator.ps1」 }
if (-not (Test-Path $ScriptPath)) { Write-Host 「錯誤:找不到編排器腳本:$ScriptPath」-前景紅色 出口1 }
# Find aggregation script (needed by orchestrator) $aggregateScript = Join-Path $PSScriptRoot「Aggregate-SecureBootData.ps1」 如果 (-not (測試路徑$aggregateScript) ) { Write-Host 「警告:Aggregate-SecureBootData.ps1 無法在腳本目錄中找到」-前景色黃 Write-Host「如果無法找到這個腳本,編排器可能會失敗。」——前景顏色:黃色 }
Write-Host "" Write-Host (“=” * 70) -前景色 青色 Write-Host 「安全啟動啟動協調器 - 任務部署」-前景青色 Write-Host (“=” * 70) -前景色 青色 Write-Host「」
# For display, show relative paths (script names only) $displayScriptPath = Split-Path $ScriptPath -葉片
Write-Host "Configuration:" -ForegroundColor Yellow Write-Host 「任務名稱:$TaskName」 Write-Host「指揮者:$displayScriptPath」 Write-Host 「輸入路徑:$AggregationInputPath」 Write-Host「報告路徑:$ReportBasePath」 Write-Host 「目標 OU: $ (如果 ($TargetOU) { $TargetOU } 否則 { ' (domain root) ' }) ” Write-Host 「投票間隔:$PollIntervalMinutes分鐘」 Write-Host 「服務帳號:$ServiceAccount」 Write-Host “部署方法:$ (如果 ($UseWinCS) { ”WinCS (WinCsFlags.exe) “ } 否則 { ”AvailableUpdatesPolicy (GPO) “ }) ” 如果 ($UseWinCS) { Write-Host 「WinCS 按鍵:$WinCSKey」 } Write-Host「」
# ================================================================== # GPO 偵測 - 若未中 自動部署# ==================================================================
$CollectionGPOName = "SecureBoot-EventCollection" $deployGpoScript = Join-Path $PSScriptRoot「Deploy-GPO-SecureBootCollection.ps1」
# Check if GroupPolicy module is available 如果 (Get-Module -ListAvailable -Name GroupPolicy) { Import-Module GroupPolicy -ErrorAction 靜默繼續 Write-Host「檢查偵測 GPO...」-ForegroundColor 黃色 試試看 { # 從 AggregationInputPath 取得網域,例如 \\domain\share () $domainFromPath = 如果 ($AggregationInputPath 匹配 '^\\\\ ([^\\]+) \\') { $matches[1] } 否則 { $env:USERDNSDOMAIN } # 查查GPO是否存在 $existingGpo = Get-GPO -Name $CollectionGPOName -ErrorAction 靜默繼續 如果 ($existingGpo) { Write-Host 「偵測 GPO 已找到:$CollectionGPOName」-前景綠色 } 否則 { Write-Host「」 Write-Host (“=” * 70) -前景色 黃色 Write-Host「偵測 GPO 未找到」-前景色:黃色 Write-Host (“=” * 70) -前景色 黃色 Write-Host「」 Write-Host「未找到偵測 GPO '$CollectionGPOName'」。-ForegroundColor Yellow Write-Host「此 GPO 必須收集裝置狀態資料。」-前景黃色 Write-Host「」 # 詢問使用者是否想現在部署 GPO Write-Host「你現在想部署偵測 GPO 嗎? (Y/N) “ -前景 青色 $response = 讀取主機 若 ($response -匹配 '^[Yy]') { Write-Host「」 Write-Host 「啟動 GPO 部署中......」-ForegroundColor 青色 Write-Host「」 # 建置 GPO 部署參數 $gpoParams = @{ 網域名稱 = $domainFromPath CollectionSharePath = $AggregationInputPath ScriptSourcePath = Join-Path $PSScriptRoot 「Detect-SecureBootCertUpdateStatus.ps1」 } 如果 ($TargetOU) { $gpoParams.OUPath = $TargetOU } 否則 { # 使用 AutoDetectOU 讓使用者選擇 $gpoParams.自動偵測OU = $true } # 執行 GPO 部署腳本 & $deployGpoScript @gpoParams 若 ($LASTEXITCODE -ne 0) { Write-Host「GPO 部署可能遇到問題。 請檢視上方的輸出。」-前景色黃 Write-Host「你可以繼續部署編排器,或按 Ctrl+C 中止。」-前景色黃 Write-Host「」 Read-Host「按 Enter 繼續」 } 否則 { Write-Host「」 Write-Host「偵測 GPO 成功部署!」-ForegroundColor Green Write-Host「」 } } 否則 { Write-Host「」 Write-Host「跳過 GPO 部署。 編排器不會接收裝置資料」-前景色黃 Write-Host「直到偵測 GPO 被手動部署為止。」-前景色黃 Write-Host「」 Write-Host 「稍後部署偵測 GPO,請執行:」-ForegroundColor 青色 Write-Host “.\Deploy-GPO-SecureBootCollection.ps1 -網域名稱 '”$domainFromPath'“ -AutoDetectOU” -前景白色 Write-Host「」 } } } 抓 { Write-Host 「無法查詢GPO:$ ($_。例外。訊息) “ -前景顏色 黃色 Write-Host「繼續部署編排器......」-前景灰色 } } 否則 { Write-Host「GroupPolicy 模組不可用 - 跳過 GPO 檢查」-前景顏色為灰色 Write-Host「確保偵測 GPO 是獨立部署的。」-Foreground Color Gray }
Write-Host ""
# ================================================================== # 建立論點# ==================================================================
$arguments = @( 「-無資料」 「-執行政策繞過」 「-檔案『$ScriptPath』」 「-AggregationInputPath '“$AggregationInputPath'” 「-報告BasePath '“$ReportBasePath'” 「-公投間隔分鐘$PollIntervalMinutes」 )
if ($TargetOU) { $arguments += “-TargetOU '”$TargetOU'” }
if ($UseWinCS) { $arguments += 「-UseWinCS」 $arguments += “-WinCSKey '”$WinCSKey'” }
if ($AllowListPath) { $arguments += “-AllowListPath '”$AllowListPath'” }
if ($AllowADGroup) { $arguments += “-AllowADGroup '”$AllowADGroup'” }
if ($ExclusionListPath) { $arguments += “-ExclusionListPath '”$ExclusionListPath'” }
if ($ExcludeADGroup) { $arguments += “-ExcludeADGroup '”$ExcludeADGroup'“” }
$argumentString = $arguments -join " "
# Don't display raw arguments with full paths - it's confusing for published scripts # 任務將內部使用完整路徑
# ================================================================== # 建立排程任務# ==================================================================
# Check for existing task $existingTask = Get-ScheduledTask -任務名稱 $TaskName -錯誤動作靜默繼續 如果 ($existingTask) { Write-Host「任務已經存在。 更新中......」-前景顏色 黃色 Stop-ScheduledTask -任務名稱 $TaskName -錯誤動作 靜默繼續 Unregister-ScheduledTask -任務名稱 $TaskName -確認:$false }
# Create task action $action = New-ScheduledTaskAction -執行「powershell.exe」 -參數 $argumentString -WorkingDirectory $PSScriptRoot
# Create trigger - run once, immediately (orchestrator loops internally) $trigger = New-ScheduledTaskTrigger -一次 -在 (約會) 。AddMinutes (1)
# Create principal 若 ($ServiceAccount -eq 「系統」) { $principal = New-ScheduledTaskPrincipal -UserID “NT AUTHORITY\SYSTEM” -LogonType ServiceAccount -RunLevel Highest } 否則 { # 標準化本地帳號格式:COMPUTERNAME\User -> User # Register-ScheduledTask 不接受本地帳號的 COMPUTERNAME\User 或 .\User $taskUser = $ServiceAccount 如果 ($ServiceAccount -匹配 “^$ ([正則表達式]::Escape ($env:COMPUTERNAME) ) \\ (.+) $”) { $taskUser = $Matches[1] Write-Host 「注意:偵測到本地帳號,使用『$taskUser』來註冊任務」 -前景灰色 }
# Prompt for password Write-Host 「輸入密碼以$ServiceAccount」-前景色 黃色 $cred = Get-Credential -使用者名稱 $taskUser -訊息「排程任務的服務帳號憑證」 如果 (-不$cred) { Write-Host「證件登錄取消。 中止。」-前景紅色 出口1 } $principal = New-ScheduledTaskPrincipal -使用者ID $taskUser -登入類型密碼 -最高執行等級 }
# Task settings $settings = New-ScheduledTaskSettingsSet ' -允許啟動電池 -不要停下,如果要用電池 -有空就開始 -RunOnlyIfNetwork可用 -RestartCount 3 ' -RestartInterval (新時間跨度 -5分鐘) ' -執行時間限制 (新時間跨度 -30天) # 允許長時間運行
# Register task 試試看 { 若 ($ServiceAccount -eq 「系統」) { Register-ScheduledTask -任務名稱 $TaskName -動作$action -觸發$trigger -主體$principal -設定 $settings -說明「安全啟動憑證推出 - 自動 GPO 部署」 } 否則 { # 使用 New-ScheduledTask 將 RunLevel 最高) 的主要 (嵌入任務物件中, # 然後註冊 -InputObject + -User/-Password (與 -Principal) $taskDefinition = New-ScheduledTask -動作 $action -觸發 $trigger -主要 $principal -設定 $settings $taskDefinition.Description = 「安全啟動憑證推出 - 自動 GPO 部署」 # 注意:Register-ScheduledTask 需要輸入純文字密碼 - 不存在 SecureString 過載 $netCred = $cred。GetNetworkCredential () Register-ScheduledTask -TaskName $TaskName -InputObject $taskDefinition -User $taskUser -Password $netCred.Password -ErrorAction 停止 $netCred = $null } Write-Host「排程任務成功建立!」-ForegroundColor Green } 抓 { Write-Host 「無法建立排程任務:$ ($_。例外。訊息) “ -前景紅色 出口1 }
# ================================================================== # 建立狀態捷徑# ==================================================================
$statusScript = Join-Path $PSScriptRoot "Get-SecureBootRolloutStatus.ps1" 若 (測試路徑$statusScript) { Write-Host「」 Write-Host 「要查詢推出狀態,請執行:」-前景色為黃色 Write-Host “.\Get-SecureBootRolloutStatus.ps1 -ReportBasePath '”$ReportBasePath'“ -ForegroundColor 青色 }
# ================================================================== # 輸出# ==================================================================
Write-Host "" Write-Host (“=” * 70) -前景綠色 Write-Host 「部署完成」-前景綠色 Write-Host (“=” * 70) -前景綠色 Write-Host「」 Write-Host「配器大約一分鐘後開始。」-前景白色 Write-Host「」 Write-Host 「監控中」:-前景色 黃色 Write-Host 「查看任務狀態:Get-ScheduledTask -任務名稱 '$TaskName' |選擇州」 Write-Host 「查看任務日誌:Get-Content '$ReportBasePath\RolloutState\Orchestrator_$ (Get-Date -格式 'yyyyMMdd') .log' -Tail 50” Write-Host 「檢視推出狀態:Get-Content '$ReportBasePath\RolloutState\RolloutState.json' |ConvertFrom-Json” Write-Host 「檢視儀表板:開始 '$ReportBasePath\Aggregation_*\SecureBoot_Dashboard*.html'」 Write-Host「快速狀態:.\Get-SecureBootRolloutStatus.ps1 -ReportBasePath '$ReportBasePath'」 Write-Host「」 Write-Host 「管理:」-前景色 黃色 Write-Host 「手動啟動:Start-ScheduledTask -任務名稱 '$TaskName'」 Write-Host 「停止:Stop-ScheduledTask -任務名稱 '$TaskName'」 Write-Host 「移除:.\Deploy-OrchestratorTask.ps1 -卸載」 Write-Host「」