Powershellでレジストリを操作する (取得編)

Powershell

Powershellではレジストリキーや値の取得や作成、更新、削除などができます。この記事では一番頻度が高いと思われるレジストリエントリの取得について、詳しく紹介します。

レジストリエントリの取得

レジストリエントリの取得には「Get-Item」コマンドレットか「Get-ItemProperty」コマンドレットを利用します。

Get-Itemによるレジストリエントリ取得

Get-Itemの-Pathにレジストリキーを指定すると、配下のレジストリ値が取得できます。

Powershellでレジストリキーを指定する場合、接頭語に「Registry::」を付与するか、HKEY_LOCAL_MACHINEをPSドライブ形式の「HKLM:」に変換する必要があります。その他、対応するルートキーは以下の通りとなります。

  • HKEY_LOCAL_MACHINE → HKLM:
  • HKEY_CURRENT_USER → HKCU:
  • HKEY_USERS → HKU:
PS C:\> Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT Name Property ---- -------- CurrentVersion SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略

単純なレジストリエントリの取得であれば、次に紹介する「Get-ItemProperty」を利用した方がスマートになりますが、配下のレジストリキー数やエントリの数を取得したい場合は「Get-Item」コマンドレットを利用するのが便利です。

PS C:\> Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" ` | Select-Object SubKeyCount,ValueCount SubKeyCount ValueCount ----------- ---------- 98 30

また、Get-ChildItemコマンドレットを利用すると、指定したレジストリキー配下のサブキーについてGet-Itemを実行したのと同じ結果を得られます。

Get-ItemPropertyによるレジストリエントリ取得

Get-ItemPropertyの-Pathにレジストリキーを指定すると、配下のレジストリ値が取得できます。

PS C:\> Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略

レジストリエントリがプロパティとして返されるので、値を取得したい場合は以下のようにします。

PS C:\> # コマンドレットの実行結果から直接プロパティ値を取り出す PS C:\> (Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion").SystemRoot C:\WINDOWS PS C:\> # 変数に格納してからプロパティ値を取り出す PS C:\> $value = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PS C:\> $value.SystemRoot C:\WINDOWS

Get-ItemとGet-ItemPropertyの違いと使い分け

どちらも出力の見た目は同じように見えますが、返されるオブジェクトの種類が異なります。

PS C:\> Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" ' | Get-Member TypeName: Microsoft.Win32.RegistryKey Name MemberType Definition ---- ---------- ---------- Close Method void Close() CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType) CreateSubKey Method Microsoft.Win32.RegistryKey CreateSubKey(string subkey... ・・・省略 PS C:\> Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" ` | Get-Member TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() BaseBuildRevisionNumber NoteProperty int BaseBuildRevisionNumber=1 BuildBranch NoteProperty string BuildBranch=19h1_release ・・・省略

Get-ItemはWin32.RegistryKeyが返され、Get-ItemPropertyではPSCustomObjectが返されます。

細かい説明は省きますが、Get-ItemPropertyではレジストリエントリがNotePropertyとして構成されているため、レジストリエントリの取得は簡単ですが、それ以外に出来ることは何もありません。(と言ったら言い過ぎにはなるのですが、レジストリ操作関連で出来ることはないと捉えてください)

Get-Itemではレジストリ操作に関するMethodが多数用意されているため、レジストリエントリの種類(REG_DWORDなど)を取得したり、レジストリエントリの追加・更新・削除なども可能になっています。

では、レジストリエントリの追加・更新・削除を行うにはGet-Itemを使用しなくてはいけないかと言われると、それぞれ別のコマンドレットが用意されています。Get-Itemでのレジストリ操作は少し難易度が高いので、基本的にはGet-ItemProperyを利用するのがいいかと思います。

参考までに、Get-Itemでレジストリの種類を取得する書き方です。

PS C:\> (Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValueKind("SystemRoot") String PS C:\> (Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion").GetValueKind("BaseBuildRevisionNumber") DWord

取得できるフィールド名とレジストリデータ型の紐づけは以下のようになっています。

フィールド名 レジストリデータ型
BinaryREG_BINARY
DWordREG_DWORD
ExpandString REG_EXPAND_SZ
MultiString REG_MULTI_SZ
QWord REG_QWORD
String REG_SZ

リモートコンピュータのレジストリを取得する

リモートコンピュータのレジストリエントリを取得するにはInvoke-Commandコマンドレットを利用します。リモートレジストリを取得するコマンドレットではなく、リモートコンピュータで任意のコマンドを実行する形になります。

Invoke-Commandコマンドレットを利用するための前提条件

Invoke-Commandコマンドレットによるリモートコマンド実行には、接続先・接続元でWinRMが有効になっている必要があります。Windows Server 2012以降のServer系OSでは既定で有効になっているため、特に準備は不要ですが、Firewallを構成している場合はTCP5985を開放する必要があります。

Client系OSでは明示的に有効化する必要があります。以下コマンドレットでWinRMを有効化することができます。

PS C:\> Enable-PSRemoting -SkipNetworkProfileCheck WinRM は要求を受信するように更新されました。 WinRM サービスの種類を正しく変更できました。 WinRM サービスが開始されました。 WinRM ファイアウォールの例外を有効にしました。

細かい内容については別記事を書きたいと思っています。

リモートコンピュータのレジストリを取得する

以下コマンドレットで取得可能です。

PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock ` { Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" } SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略

ScriptBlock内にリモートコンピュータで実行したいコマンドを記述します。

スクリプトブロック内で変数を使う

補足的な内容となりますが、ScriptBlock内で変数を使うのは少し癖があります。

以下はローカルで実行した場合。変数にレジストリキーを格納し、-Pathに変数を引き渡すことで、正常に動作しているのが確認できます。

PS C:\> $Reg = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PS C:\> Get-ItemProperty -Path $Reg SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略

ではScriptBlock内で変数を利用してみます。

PS C:\> $Reg = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock ` { Get-ItemProperty -Path $Reg } 引数が null であるため、パラメーター 'Path' にバインドできません。 + CategoryInfo : InvalidData: (:) [Get-ItemProperty]、ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetItemPropertyCommand + PSComputerName : localhost

引数がnullというエラーが発生しました。原因はScriptBlock内のコマンドは呼び出し元と別のプロセスで実行されるためで、ScriptBlock外の変数を利用するには特別な記述が必要となります。

2つの方法を紹介します。

PS C:\> # Invoke-Commandの-ArgumentListを利用する PS C:\> $Reg = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock ` { Get-ItemProperty -Path $Args[0] } -ArgumentList $Reg SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略
PS C:\> # using:ラベルを利用する PS C:\> $Reg = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock ` { Get-ItemProperty -Path $using:Reg } SystemRoot : C:\WINDOWS BaseBuildRevisionNumber : 1 BuildBranch : 19h1_release BuildGUID : ffffffff-ffff-ffff-ffff-ffffffffffff BuildLab : 18362.19h1_release.190318-1202 BuildLabEx : 18362.1.amd64fre.19h1_release.190318-1202 ・・・省略

ArgumentListを利用する場合、ScriptBlock内の引数は指定しなければ$Args[x]とする必要があります。もちろんScriptBlock内で事前に引数について定義することもできます。定義方法については以下のページを参照してください。

一方、using:ラベルはPowershell 3.0から利用可能になった機能となります。個人的にはコードの見通しも良くなるので、ラベルを使うほうが好みです。

レジストリエントリでの条件分岐

一番需要がありそうなレジストリエントリの有無や値による条件分岐を用いたサンプルを紹介します。

OS情報を取得し、対象OSの場合のみ処理を行う

簡単ではありますが、対象OSがWindows 10 Enterpriseの場合のみ処理を行うスクリプトのサンプルです。

# sample.ps1
# 取得対象のレジストリキーを格納
$RegKey = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion"

# レジストリキーが存在するかチェック
If(Test-Path -Path $RegKey){
    Write-Host $RegKey "を確認できました。"
}Else{
    Write-Host $RegKey "は存在しないため、処理を中止します。"
    Exit(1)
}

# OSがWindows 10 Enterpriseの場合、処理を行う
$ProductName = Get-ItemProperty -Path $RegKey -Name ProductName

If($ProductName.ProductName -eq "Windows 10 Enterprise"){
    Write-Host "対象OSです。処理を行います。"
    # 何かしらの処理を記述
}Else{
    Write-Host "対象外OSです。処理を中止します。"
    Exit(2)
}
PS C:\> C:\sample1.ps1 Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion を確認できました。 対象OSです。処理を行います。

以上、Powershellでレジストリを取得する方法でした。

コメント

タイトルとURLをコピーしました