Skip to content

Instantly share code, notes, and snippets.

@ebibibi
Created February 12, 2025 07:45
Show Gist options
  • Save ebibibi/2443a4ccd98a0bd9d167e28998d9ed69 to your computer and use it in GitHub Desktop.
Save ebibibi/2443a4ccd98a0bd9d167e28998d9ed69 to your computer and use it in GitHub Desktop.
Hybrid Microsoft Entra Joinのトラブルシューティング用情報取得スクリプト
<#
.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