このサンプル スクリプトをコピーして貼り付け、環境に合わせて必要に応じて変更します。
<# .SYNOPSIS セキュリティで保護されたブート イベント コレクションの GPO 展開スクリプト GPO を作成してリンクし、スケジュールされたタスクとしてコレクション スクリプトを展開します
.DESCRIPTION このスクリプトは、グループ ポリシーを使用して Secure Boot イベント コレクションのデプロイを自動化します。: を使用して GPO を作成します - コレクション スクリプトを毎日実行するスケジュールされたタスク - 中央共有への書き込みに対する適切なアクセス許可 - 特定の OS バージョンを対象とする WMI フィルター
.PARAMETER GPOName 新しい GPO の名前
.PARAMETER DomainName ターゲット ドメイン FQDN
.PARAMETER OUPath GPO をリンクする OU の識別名。複数の OU を配列として受け入れます。 -AutoDetectOU が指定されている場合は必須ではありません。
.PARAMETER AutoDetectOU 対話形式で一覧表示に切り替え、Active Directory から [OU] を選択します。指定した場合、-OUPath は省略可能です。
.PARAMETER CollectionSharePath コレクションの結果が格納される UNC パス
.PARAMETER ScriptSourcePath コレクション スクリプトが格納されるパス (SYSVOL にコピーされます)
.PARAMETER RandomDelayHours スクリプトの実行をエンドポイント間でランダムに分散させる時間数。これにより、すべてのマシンが共有に同時に書き込むのを防ぐことができます。既定値: 4 時間。 有効な範囲: 1 から 24 時間。 推奨値: - 1 から 10,000 台のデバイス: 4 時間 (既定値) - 10K-50K デバイス: 8 時間 - 50K 以上のデバイス: 12 ~ 24 時間
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath "OU=Workstations,DC=contoso,DC=com"
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath "OU=Workstations,DC=contoso,DC=com" -RandomDelayHours 8
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -AutoDetectOU ドメイン内のすべての OU を一覧表示し、選択を求めるメッセージを表示します。
.EXAMPLE .\Deploy-GPO-SecureBootCollection.ps1 -DomainName "contoso.com" -OUPath @("OU=Workstations,DC=contoso,DC=com", "OU=Laptops,DC=contoso,DC=com") GPO を 1 回の実行で複数の OU にリンクします。
.NOTES 必須: Active Directory PowerShell モジュール、グループ ポリシー モジュール ドメイン 管理または委任された GPO の作成権限を使用して実行する必要があります #>
[CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$GPOName = "SecureBoot-EventCollection", [Parameter(Mandatory = $false)] [string]$DomainName, [Parameter(Mandatory = $false)] [string[]]$OUPath, [Parameter(Mandatory = $false)] [switch]$AutoDetectOU, [Parameter(Mandatory = $false)] [string]$CollectionSharePath = "\\$DomainName\NETLOGON\SecureBootLogs", [Parameter(Mandatory = $false)] [string]$ScriptSourcePath = ".\Detect-SecureBootCertUpdateStatus.ps1", [Parameter(Mandatory = $false)] [ValidateSet("Daily", "Weekly", "AtStartup")] [string]$Schedule = "Daily", [Parameter(Mandatory = $false)] [string]$ScheduleTime = "14:00", [Parameter(Mandatory = $false)] [ValidateRange(1, 24)] [int]$RandomDelayHours = 4 )
#Requires -Modules ActiveDirectory, GroupPolicy #Requires -バージョン 5.1
$ErrorActionPreference = "Stop" $DownloadUrl = "https://aka.ms/getsecureboot" $DownloadSubPage = "デプロイと監視のサンプル"
# ============================================================================ # DEPENDENCY VALIDATION # ============================================================================
function Test-ScriptDependencies { param( [Parameter(Mandatory = $true)] [string]$ScriptDirectory, [Parameter(Mandatory = $true)] [string[]]$RequiredScripts ) $missingScripts = @() foreach ($RequiredScripts の$script) { $scriptPath = Join-Path $ScriptDirectory $script if (-not (Test-Path $scriptPath)) { $missingScripts += $script } } if ($missingScripts.Count -gt 0) { "" を Write-Host する Write-Host ("=" * 70) -ForegroundColor Red Write-Host "MISSING DEPENDENCIES" -ForegroundColor Red Write-Host ("=" * 70) -ForegroundColor Red "" を Write-Host する Write-Host "次の必要なスクリプトが見つかりませんでした:" -ForegroundColor Yellow foreach ($missingScripts の$script) { Write-Host " - $script" -ForegroundColor White } "" を Write-Host する Write-Host "から最新のスクリプトをダウンロードしてください:" -ForegroundColor シアン Write-Host " URL: $DownloadUrl" -ForegroundColor White Write-Host " に移動: '$DownloadSubPage'" -ForegroundColor White "" を Write-Host する Write-Host "すべてのスクリプトを同じディレクトリに抽出し、もう一度実行します"。-ForegroundColor Yellow "" を Write-Host する return $false } return $true }
# The Detect script is required - it gets deployed to endpoints via GPO $requiredScripts = @( "Detect-SecureBootCertUpdateStatus.ps1" )
if (-not (Test-ScriptDependencies -ScriptDirectory $PSScriptRoot -RequiredScripts $requiredScripts)) { 終了 1 }
# ============================================================================ # ドメイン名の自動検出 # ============================================================================
if (-not $DomainName) { $DomainName = $env:USERDNSDOMAIN if (-not $DomainName) { # AD モジュールから取得してみてください {を試す ActiveDirectory -ErrorAction Stop を Import-Module します $DomainName = (Get-ADDomain)。DNSRoot } catch { Write-Host "ERROR: ドメイン名を自動検出できませんでした"。-ForegroundColor Red 「-DomainName パラメーターを指定してください」と Write-Host -ForegroundColor Yellow "" を Write-Host する Write-Host "Example:" -ForegroundColor Gray Write-Host " .\Deploy-GPO-SecureBootCollection.ps1 -DomainName contoso.com -AutoDetectOU" -ForegroundColor White 終了 1 } } "自動検出されたドメイン: $DomainName" -ForegroundColor Green を Write-Host します }
# Set CollectionSharePath default if not explicitly provided if (-not $PSBoundParameters.ContainsKey('CollectionSharePath')) { $CollectionSharePath = "\\$DomainName\NETLOGON\SecureBootLogs" }
Write-Host "============================================" -ForegroundColor Cyan Write-Host "セキュア ブート コレクション - GPO の展開" -ForegroundColor シアン Write-Host "============================================" -ForegroundColor シアン
# Validate prerequisites Write-Host "'n[1/6] 前提条件の検証... -ForegroundColor Yellow
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { throw "ActiveDirectory モジュールが見つかりません。 RSAT ツールをインストールします。 }
if (-not (Get-Module -ListAvailable -Name GroupPolicy)) { throw "GroupPolicy モジュールが見つかりません。 RSAT ツールをインストールします。 }
Import-Module ActiveDirectory Import-Module GroupPolicy
# Validate domain connectivity {を試す $domain = Get-ADDomain -Server $DomainName Write-Host " ドメインに接続: $($domain。DNSRoot)" -ForegroundColor Green } catch { throw "ドメインに接続できません: $DomainName。 エラー: $_" }
# Handle OU selection if ($AutoDetectOU) { Write-Host "'n ドメイン内の OU を検出しています... -ForegroundColor Cyan $allOUs = Get-ADOrganizationalUnit -Filter * -Server $DomainName | DistinguishedName | の Sort-Object Select-Object @{N='Index';E={0}}、Name、DistinguishedName # インデックスを割り当てます for ($i = 0;$i -lt $allOUs.Count; $i++) { $allOUs[$i].Index = $i + 1 } Write-Host "'n Available OU:" -ForegroundColor Yellow Write-Host " ---------------------------------------------------------------------" -ForegroundColor DarkGray $allOUs |{ の ForEach-Object Write-Host (" {0,3}) {1}" -f $_。Index、$_。DistinguishedName) -ForegroundColor White } Write-Host " ---------------------------------------------------------------------" -ForegroundColor DarkGray Write-Host " ヒント: コンマ区切りの数値を入力して複数の OU (1,3,5 など) を選択します"-ForegroundColor DarkGray Write-Host "A と入力してすべての OU を選択します" -ForegroundColor DarkGray "" を Write-Host する $selection = Read-Host " OU を選択して GPO をリンクする" if ($selection -eq 'A' -or $selection -eq 'a') { $OUPath = $allOUs.DistinguishedName Write-Host " Selected ALL $($OUPath.Count) OU" -ForegroundColor Green } else { $indices = $selection -split ',' |ForEach-Object { [int]$_.Trim() } $OUPath = @() foreach ($indices の$idx) { $selected = $allOUs |{ $_ を Where-Object します。Index -eq $idx } if ($selected) { += $selectedを$OUPathします。DistinguishedName } else { "無効なインデックス: $idx - スキップ" を Write-Warning } } } if ($OUPath.Count -eq 0) { throw "NO OU selected. 中止中です。 } Write-Host "'n Selected $($OUPath.Count) OU(s):" -ForegroundColor Green $OUPath |ForEach-Object { Write-Host " - $_" -ForegroundColor Gray } } elseif (-not $OUPath -or $OUPath.Count -eq 0) { throw "-OUPath または -AutoDetectOU を指定する必要があります" } それ以外の { # 各 OU が存在することを検証します foreach ($OUPath の$path) { { を試す $ou = Get-ADOrganizationalUnit -Identity $path -Server $DomainName Write-Host " ターゲット OU が見つかりました: $($ou。Name)" -ForegroundColor Green } catch { throw "OU not found: $path" } } }
# Validate source script exists if (-not (Test-Path $ScriptSourcePath)) { throw "Collection script not found: $ScriptSourcePath" }
# Step 2: Create collection share structure Write-Host "'n[2/6] コレクション共有の設定... -ForegroundColor Yellow
$sysvolScriptPath = "\\$DomainName\SYSVOL\$DomainName\Scripts\SecureBootCollection"
# Create SYSVOL script folder if (-not (Test-Path $sysvolScriptPath)) { New-Item -ItemType Directory -Path $sysvolScriptPath -Force |Out-Null Write-Host "CREATE SYSVOL script folder: $sysvolScriptPath" -ForegroundColor Green }
# Copy collection script to SYSVOL $destScript = "Detect-SecureBootCertUpdateStatus.ps1" Join-Path $sysvolScriptPath
# Remove existing destination if it's a directory (fix for Copy-Item bug) if (Test-Path $destScript -PathType Container) { Remove-Item $destScript -Recurse -Force }
Copy-Item -Path $ScriptSourcePath -Destination $destScript -Force Write-Host " コレクション スクリプトを SYSVOL にコピーしました" -ForegroundColor Green
# Create a wrapper script that calls the main script with parameters $wrapperScript = @" # セキュア ブート イベント コレクション ラッパー # Deploy-GPO-SecureBootCollection.ps1 によって自動生成される
`$ErrorActionPreference = 'SilentlyContinue'
# Configuration '$CollectionShare = '$CollectionSharePath' '$ScriptPath = '$sysvolScriptPath\Detect-SecureBootCertUpdateStatus.ps1'
# Run collection with -OutputPath parameter if (Test-Path '$ScriptPath) { & '$ScriptPath -OutputPath '$CollectionShare } それ以外の { Write-EventLog -LogName Application -Source "SecureBootCollection" -EventId 1001 -EntryType エラー -Message "Collection script not found: '$ScriptPath" } "@
$wrapperPath = Join-Path $sysvolScriptPath "Run-SecureBootCollection.ps1" $wrapperScript |Out-File -FilePath $wrapperPath -Encoding UTF8 -Force Write-Host "作成されたラッパー スクリプト" -ForegroundColor Green
# Create collection share (if on a file server) Write-Host "コレクション共有パス: $CollectionSharePath" -ForegroundColor シアン Write-Host " 注: この共有が 'Domain Computers' 書き込みアクセス権と共に存在することを確認する" -ForegroundColor Yellow
# Step 3: Create the GPO Write-Host "'n[3/6] グループ ポリシー オブジェクトの作成... -ForegroundColor Yellow
# Check if GPO already exists $existingGPO = Get-GPO -Name $GPOName -Domain $DomainName -ErrorAction SilentlyContinue
if ($existingGPO) { Write-Host " GPO '$GPOName' が既に存在します。 更新中..." -ForegroundColor Yellow $gpo = $existingGPO } else { $gpo = New-GPO -Name $GPOName -Domain $DomainName -Comment "Deploys Secure Boot event collection script to endpoints" Write-Host "作成された GPO: $GPOName" -ForegroundColor Green }
# Step 4: Configure Scheduled Task via GPO Preferences Write-Host "'n[4/6] スケジュールされたタスクの構成... -ForegroundColor Yellow
# Build the scheduled task XML # RandomDelay は、サーバーの過負荷を防ぐために、エンドポイント間で実行を分散します Write-Host "ランダム遅延: $RandomDelayHours 時間 (フリート間で負荷を分散)" -ForegroundColor シアン
$taskTrigger = switch ($Schedule) { "Daily" { @" <CalendarTrigger> <StartBoundary>2024-01-01T${ScheduleTime}:00</StartBoundary> <有効>true</Enabled> <ScheduleByDay> <DaysInterval>1</DaysInterval> /ScheduleByDay> の < <RandomDelay>PT${RandomDelayHours}H</RandomDelay> </CalendarTrigger> "@ } "週単位" { @" <CalendarTrigger> <StartBoundary>2024-01-01T${ScheduleTime}:00</StartBoundary> <有効>true</Enabled> <ScheduleByWeek> <WeeksInterval>1</WeeksInterval> <DaysOfWeek> <水曜日 /> </DaysOfWeek> /ScheduleByWeek> の < <RandomDelay>PT${RandomDelayHours}H</RandomDelay> </CalendarTrigger> "@ } "AtStartup" { # スタートアップ トリガーの場合は、Delay を使用してランダムな開始時刻を追加します # 各マシンは、起動から 5 分後から (5 + RandomDelayHours*60) 分後に開始されます $maxDelayMinutes = 5 + ($RandomDelayHours * 60) @" BootTrigger> の < <有効>true</Enabled> PT5M</Delay>>遅延の < <RandomDelay>PT${RandomDelayHours}H</RandomDelay> /BootTrigger> の < "@ } }
$scheduledTaskXML = @" <?xml version="1.0" encoding="UTF-16"?> <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <説明>エンタープライズ国勢調査</Description> のセキュア ブート イベント データを収集します <Enterprise Security</Author>>作成者 </RegistrationInfo> <トリガーの> $taskTrigger /Triggers> の < <プリンシパル> <プリンシパル id="Author"> <UserId>S-1-5-18</UserId> <RunLevel>HighestAvailable</RunLevel> /Principal> の < </Principals> <設定> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> stopIfGoingOnBatteries <false></StopIfGoingOnBatteries> AllowHardTerminate <true</AllowHardTerminate>> <StartWhenAvailable>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> IdleSettings> の < StopOnIdleEnd <false></StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> /IdleSettings> の < AllowStartOnDemand>true</AllowStartOnDemand> の < <有効>true</Enabled> <非表示>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> UseUnifiedSchedulingEngine <true></UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT1H</ExecutionTimeLimit> <Priority>7</Priority> /Settings> の < <Actions Context="Author"> <Exec> <コマンド>powershell.exe</Command> <引数>-NoProfile -ExecutionPolicy Bypass -File "$wrapperPath"</Arguments> /Exec> の < /Actions> の < /Task> の < "@
# Save task XML to SYSVOL for reference/backup $taskXmlPath = "SecureBootCollection-Task.xml"を Join-Path $sysvolScriptPath $scheduledTaskXML |Out-File -FilePath $taskXmlPath -Encoding Unicode -Force Write-Host " スケジュールされたタスク XML を SYSVOL に保存 (バックアップ)" -ForegroundColor Green
# Inject scheduled task into GPO Preferences Write-Host " GPO の基本設定にスケジュールされたタスクを挿入します。.. -ForegroundColor Cyan
$gpoId = $gpo.Id.ToString() $gpoPrefPath = "\\$DomainName\SYSVOL\$DomainName\Policies\{$gpoId}\Machine\Preferences\ScheduledTasks"
# Create Preferences folder structure if (-not (Test-Path $gpoPrefPath)) { New-Item -ItemType Directory -Path $gpoPrefPath -Force |Out-Null }
# Generate unique GUID for the task $taskGuid = [guid]::NewGuid()。ToString("B")。ToUpper()
# Build GPO Preferences ScheduledTasks.xml format # これは標準のタスク スケジューラ XML とは異なります。これは GPP 形式です $gppScheduledTasksXml = @" <?xml version="1.0" encoding="utf-8"?> <ScheduledTasks clsid="{CC63F200-7309-4ba0-B154-A71CD118DBCC}"> <TaskV2 clsid="{D8896631-B747-47a7-84A6-C155337F3BC8}" name="SecureBoot-EventCollection" image="0" が変更されました ="$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" uid="$taskGuid" userContext="0" removePolicy="0"> <プロパティ action="C" name="SecureBoot-EventCollection" runAs="NT AUTHORITY\System" logonType="S4U"> <Task version="1.3"> <RegistrationInfo> <Enterprise Security</Author>>作成者 <説明>エンタープライズ コンプライアンス監視のセキュリティで保護されたブート証明書の状態を収集</Description> /RegistrationInfo> の < <プリンシパル> <プリンシパル id="Author"> <UserId>NT AUTHORITY\System</UserId> <LogonType>S4U</LogonType> <RunLevel>HighestAvailable</RunLevel> /Principal> の < </Principals> <設定の> <IdleSettings> PT10M</Duration> の <期間> pt1H</WaitTimeout>>WaitTimeout の < StopOnIdleEnd <false</StopOnIdleEnd> を> <RestartOnIdle>false</RestartOnIdle> /IdleSettings> の < <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> stopIfGoingOnBatteries <false></StopIfGoingOnBatteries> AllowHardTerminate <true</AllowHardTerminate>> <StartWhenAvailable>true</StartWhenAvailable> <RunOnlyIfNetworkAvailable>true</RunOnlyIfNetworkAvailable> AllowStartOnDemand>true</AllowStartOnDemand>< <有効>true</Enabled> <非表示>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT1H</ExecutionTimeLimit> <Priority>7</Priority> /Settings> の < <トリガーの> $taskTrigger /Triggers> を <する <Actions Context="Author"> <Exec> /Command> の <コマンド>powershell.exe< <引数>-NoProfile -ExecutionPolicy Bypass -File "$wrapperPath"</Arguments> /Exec> の < /Actions> の < /Task> の < </Properties> /TaskV2> の < /ScheduledTasks> の < "@
# Write GPP ScheduledTasks.xml to GPO $gppXmlPath = "ScheduledTasks.xml"Join-Path $gpoPrefPath $gppScheduledTasksXml |Out-File -FilePath $gppXmlPath -Encoding UTF8 -Force Write-Host " [OK] スケジュールされたタスクが GPO に挿入されました" -ForegroundColor Green Write-Host " タスク スケジュール: $RandomDelayHours 時間ランダム遅延で$ScheduleTimeで$Schedule" -ForegroundColor Gray
# Step 5: Link GPO to OU(s) Write-Host "'n[5/6] GPO を OU にリンクしています。." -ForegroundColor Yellow
$linkedCount = 0 $skippedCount = 0
foreach ($targetOU in $OUPath) { $existingLink = Get-GPInheritance -Target $targetOU -Domain $DomainName | Select-Object -ExpandProperty GpoLinks | { $_ を Where-Object します。DisplayName -eq $GPOName }
if (-not $existingLink) { New-GPLink -Name $GPOName -Target $targetOU -Domain $DomainName -LinkEnabled Yes |Out-Null Write-Host " [OK] リンク先: $targetOU" -ForegroundColor Green $linkedCount++ } else { Write-Host " - 既にリンクされています: $targetOU" -ForegroundColor Yellow $skippedCount++ } }
Write-Host "`n Summary: $linkedCount new links, $skippedCount already existed" -ForegroundColor Cyan
# Step 6: Create WMI Filter (optional - for Windows 10/11 only) Write-Host "'n[6/6] WMI フィルターの作成... -ForegroundColor Yellow
$wmiFilterName = "Windows 10 and 11 Workstations" $wmiQuery = 'SELECT * FROM Win32_OperatingSystem WHERE Version LIKE "10.%" and ProductType = "1"'
Write-Host @" [注]省略可能: GPMC で WMI フィルターを作成します フィルター名: $wmiFilterName クエリ: $wmiQuery これにより、GPO がフィルター処理され、Windows 10/11 ワークステーションにのみ適用されます。
"@ -ForegroundColor Yellow
# Summary Write-Host "'n============================================" -ForegroundColor シアン Write-Host "DEPLOYMENT COMPLETE" -ForegroundColor Green Write-Host "============================================" -ForegroundColor シアン Write-Host @"
Summary: - GPO 名: $GPOName - ターゲット OU: $OUPath - コレクション共有: $CollectionSharePath - スクリプトの場所: $sysvolScriptPath - スケジュール: $ScheduleTimeで$Schedule
Next Steps: 1. 適切なアクセス許可でコレクション共有を作成する: - 共有: $CollectionSharePath - アクセス許可: ドメイン コンピューター (書き込み)、ドメイン管理者 (フル)
2. Complete the scheduled task configuration in GPMC (see instructions above)
3. Run 'gpupdate /force' on a test machine to verify deployment
4. Monitor collection results in: $CollectionSharePath
5. Run aggregation script to generate reports: .\Aggregate-SecureBootData.ps1 -InputPath "$CollectionSharePath"
"@ -ForegroundColor White