Created
February 12, 2025 07:45
-
-
Save ebibibi/2443a4ccd98a0bd9d167e28998d9ed69 to your computer and use it in GitHub Desktop.
Hybrid Microsoft Entra Joinのトラブルシューティング用情報取得スクリプト
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
デバイス登録状況、ローカル証明書、Active Directory 上の証明書、Microsoft Graph のデバイス情報を取得・保存するスクリプト | |
.DESCRIPTION | |
本スクリプトは、以下の順序で各種情報を収集します。 | |
1. 出力先ディレクトリの作成 | |
2. dsregcmd /status を実行して出力ファイルに保存し、DeviceId を抽出 | |
3. Microsoft.Graph モジュールがインストールされていなければインストールし、認証済みかチェックして、未認証の場合は認証を促し接続。 | |
接続後、抽出した DeviceId を用いてデバイス情報を取得し、JSON 形式で保存 | |
4. Cert:\LocalMachine\My 内の各証明書を個別ファイルとしてエクスポート(詳細情報はファイル出力のみ) | |
5. Active Directory モジュールがなければ RSAT 経由でインストールし、AD のコンピューターオブジェクトの userCertificate 属性から各証明書を取得して保存 | |
.NOTES | |
・本スクリプトは Windows 環境専用です。 | |
・管理者権限が必要な処理が含まれます。 | |
#> | |
#region ユーティリティ関数 | |
# 進捗や重要なメッセージを色付きで表示する関数 | |
function Write-Status { | |
param( | |
[Parameter(Mandatory = $true)] | |
[string]$Message, | |
[Parameter(Mandatory = $false)] | |
[ValidateSet("Info", "Success", "Warning", "Error", "Progress")] | |
[string]$Type = "Info" | |
) | |
switch ($Type) { | |
"Info" { Write-Host $Message -ForegroundColor Cyan } | |
"Success" { Write-Host $Message -ForegroundColor Green } | |
"Warning" { Write-Host $Message -ForegroundColor Yellow } | |
"Error" { Write-Host $Message -ForegroundColor Red } | |
"Progress" { Write-Host $Message -ForegroundColor Magenta } | |
} | |
} | |
# 指定したディレクトリが存在しない場合は作成する関数 | |
function Ensure-Directory { | |
param( | |
[Parameter(Mandatory = $true)] | |
[string]$Path | |
) | |
if (-not (Test-Path -Path $Path)) { | |
try { | |
New-Item -Path $Path -ItemType Directory -Force | Out-Null | |
Write-Status "ディレクトリを作成しました: $Path" -Type Success | |
} | |
catch { | |
Write-Status "ディレクトリ '$Path' の作成に失敗しました: $_" -Type Error | |
exit 1 | |
} | |
} | |
} | |
# 指定したモジュールが存在しなければインストールする関数 | |
function Install-ModuleIfNeeded { | |
param( | |
[Parameter(Mandatory = $true)] | |
[string]$ModuleName, | |
[string]$Scope = "CurrentUser" | |
) | |
if (-not (Get-Module -ListAvailable -Name $ModuleName)) { | |
Write-Status "$ModuleName モジュールが見つかりません。インストールを開始します..." -Type Info | |
try { | |
Install-Module $ModuleName -Scope $Scope -Force -ErrorAction Stop | |
Write-Status "$ModuleName をインストールしました。" -Type Success | |
} | |
catch { | |
Write-Status "モジュール ${ModuleName} のインストールに失敗しました: $_" -Type Error | |
exit 1 | |
} | |
} | |
} | |
#endregion | |
#region 1. 初期設定・出力先ディレクトリの作成 | |
$debugDir = "C:\tmp\debug" | |
Ensure-Directory -Path $debugDir | |
# タイムスタンプおよびコンピューター名の取得 | |
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss" | |
$computerName = $env:COMPUTERNAME | |
#endregion | |
#region 2. dsregcmd の実行と DeviceId の抽出 | |
try { | |
Write-Status "dsregcmd /status を実行中です..." -Type Progress | |
$dsregOutput = dsregcmd /status | |
$dsregOutputFile = Join-Path -Path $debugDir -ChildPath "${timestamp}_${computerName}_dsregcmd.txt" | |
$dsregOutput | Out-File -FilePath $dsregOutputFile -Encoding UTF8 | |
Write-Status "dsregcmd の出力が次に保存されました: $dsregOutputFile" -Type Success | |
} | |
catch { | |
Write-Status "dsregcmd の実行または出力の保存に失敗しました: $_" -Type Error | |
exit 1 | |
} | |
# dsregcmd の出力から DeviceId を抽出 | |
$deviceId = "" | |
$deviceIdLine = $dsregOutput | Where-Object { $_ -match "^\s*DeviceId\s*:" } | |
if ($deviceIdLine -match ":\s*(\S+)") { | |
$deviceId = $matches[1] | |
Write-Status "抽出された DeviceId: $deviceId" -Type Success | |
} | |
else { | |
Write-Status "dsregcmd の出力から DeviceId を抽出できませんでした。" -Type Error | |
exit 1 | |
} | |
#endregion | |
#region 3. Microsoft Graph への接続とデバイス情報の取得 | |
# Microsoft.Graph モジュールの存在確認および必要に応じたインストール | |
Install-ModuleIfNeeded -ModuleName "Microsoft.Graph" | |
# 既に Microsoft Graph に接続済みかチェック(認証済みなら再認証をスキップ) | |
try { | |
$mgContext = Get-MgContext -ErrorAction Stop | |
} | |
catch { | |
$mgContext = $null | |
} | |
if (-not $mgContext) { | |
try { | |
Write-Status "Microsoft Graph に接続されていません。接続を開始します(認証ダイアログが表示される場合があります)..." -Type Progress | |
Connect-MgGraph -Scopes "Device.Read.All" -ErrorAction Stop | |
Write-Status "Microsoft Graph に接続しました。" -Type Success | |
} | |
catch { | |
Write-Status "Microsoft Graph への接続に失敗しました: $_" -Type Error | |
exit 1 | |
} | |
} | |
else { | |
Write-Status "既に Microsoft Graph に接続済みです。再認証はスキップします。" -Type Info | |
} | |
# コンピューター名と一致する DisplayName のデバイス情報を取得する | |
try { | |
Write-Status "DisplayName が '$computerName' のデバイス情報を Microsoft Graph から取得しています..." -Type Progress | |
$devices = Get-MgDevice -Filter "displayName eq '$computerName'" -ErrorAction Stop | |
$deviceInfo = $null | |
if ($devices -eq $null -or $devices.Count -eq 0) { | |
Write-Status "DisplayName '$computerName' のデバイスが見つかりませんでした。" -Type Error | |
exit 1 | |
} | |
elseif ($devices.Count -gt 1) { | |
Write-Status "DisplayName '$computerName' のデバイスが複数見つかりました。最初のものを使用します。" -Type Warning | |
$deviceInfo = $devices[0] | |
} | |
else { | |
$deviceInfo = $devices | |
} | |
$deviceInfoFile = Join-Path -Path $debugDir -ChildPath "${computerName}_EntraID_deviceinfo.txt" | |
$deviceInfo | ConvertTo-Json -Depth 10 | Out-File -FilePath $deviceInfoFile -Encoding UTF8 | |
Write-Status "デバイス情報が次に保存されました: $deviceInfoFile" -Type Success | |
} | |
catch { | |
Write-Status "Microsoft Graph からデバイス情報の取得に失敗しました: $_" -Type Error | |
exit 1 | |
} | |
#endregion | |
#region 4. ローカルマシン証明書のエクスポート | |
Write-Status "Cert:\LocalMachine\My からローカル証明書をエクスポートしています..." -Type Progress | |
Get-ChildItem -Path Cert:\LocalMachine\My | | |
Where-Object { -not $_.PSIsContainer } | | |
ForEach-Object { | |
$localCertPath = Join-Path -Path $debugDir -ChildPath "local_$($_.Thumbprint).cer" | |
try { | |
Export-Certificate -Cert $_ -FilePath $localCertPath -Type Cert | Out-Null | |
Write-Status "ローカル証明書がエクスポートされました: $localCertPath" -Type Success | |
} | |
catch { | |
Write-Status "ローカル証明書(Thumbprint: $($_.Thumbprint))のエクスポートに失敗しました: $_" -Type Error | |
} | |
} | |
#endregion | |
#region 5. Active Directory モジュールの確認・インストールと AD 証明書のエクスポート | |
# Active Directory モジュールが存在しなければ、RSAT 経由でインストールする | |
if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { | |
Write-Status "Active Directory モジュールが見つかりません。RSAT のインストールを試みます..." -Type Info | |
if ($env:OS -match "Windows_NT") { | |
$osMajorVersion = [System.Environment]::OSVersion.Version.Major | |
if ($osMajorVersion -ge 10) { | |
# Windows 10/11 の場合 | |
$rsatCapability = Get-WindowsCapability -Online | Where-Object { $_.Name -like "Rsat.ActiveDirectory*" } | Select-Object -ExpandProperty Name -ErrorAction SilentlyContinue | |
if ($rsatCapability) { | |
try { | |
Add-WindowsCapability -Online -Name $rsatCapability | Out-Null | |
Write-Status "RSAT-AD-PowerShell をインストールしました。" -Type Success | |
} | |
catch { | |
Write-Status "RSAT-AD-PowerShell のインストールに失敗しました: $_" -Type Error | |
exit 1 | |
} | |
} | |
else { | |
Write-Status "RSAT-AD-PowerShell の機能が見つかりませんでした。" -Type Error | |
exit 1 | |
} | |
} | |
elseif ($osMajorVersion -ge 6) { | |
# Windows Server の場合 | |
try { | |
Install-WindowsFeature -Name RSAT-AD-PowerShell -IncludeManagementTools | Out-Null | |
Write-Status "RSAT-AD-PowerShell をインストールしました(Windows Server)。" -Type Success | |
} | |
catch { | |
Write-Status "RSAT-AD-PowerShell のインストールに失敗しました: $_" -Type Error | |
exit 1 | |
} | |
} | |
else { | |
Write-Status "この OS では RSAT-AD-PowerShell のインストールはサポートされていません。" -Type Error | |
exit 1 | |
} | |
} | |
else { | |
Write-Status "このスクリプトは Windows OS でのみ実行できます。" -Type Error | |
exit 1 | |
} | |
} | |
# Active Directory モジュールのインポート | |
try { | |
Import-Module ActiveDirectory -ErrorAction Stop | |
Write-Status "Active Directory モジュールをインポートしました。" -Type Success | |
} | |
catch { | |
Write-Status "Active Directory モジュールのインポートに失敗しました: $_" -Type Error | |
exit 1 | |
} | |
# AD 上のコンピューターオブジェクトの userCertificate 属性から証明書を取得・エクスポートする | |
try { | |
Write-Status "AD からコンピュータオブジェクト '$computerName' を取得しています..." -Type Progress | |
$adComputer = Get-ADComputer -Identity $computerName -Properties userCertificate | |
} | |
catch { | |
Write-Status "AD からコンピュータオブジェクトの取得に失敗しました: $_" -Type Error | |
exit 1 | |
} | |
$adCertList = $adComputer.userCertificate | |
if ($adCertList) { | |
foreach ($certBytes in $adCertList) { | |
try { | |
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(, $certBytes) | |
} | |
catch { | |
Write-Status "AD に不正な証明書データが見つかりました。この証明書はスキップします。" -Type Warning | |
continue | |
} | |
try { | |
$adCertFile = Join-Path -Path $debugDir -ChildPath "ad_$($cert.Thumbprint).cer" | |
[System.IO.File]::WriteAllBytes($adCertFile, $cert.RawData) | |
Write-Status "AD の証明書がエクスポートされました: $adCertFile" -Type Success | |
} | |
catch { | |
Write-Status "AD の証明書のエクスポートに失敗しました: $_" -Type Error | |
} | |
} | |
} | |
else { | |
Write-Status "AD コンピュータオブジェクトに userCertificate 属性が見つかりませんでした。" -Type Warning | |
} | |
#endregion | |
Write-Status "全ての処理が正常に完了しました。" -Type Success |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment