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
取得できるフィールド名とレジストリデータ型の紐づけは以下のようになっています。
フィールド名 レジストリデータ型 Binary REG_BINARY DWord REG_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 を構成している場合は TCP 5985 を開放する必要 があります。
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 でレジストリを操作する方法でした。
リンク
コメント