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 を構成している場合は 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 でレジストリを操作する方法でした。

コメント

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