Sysinternals
で配布されているRemote Desktop Connection Manager
。
こちらのソフトウェアについて、一時期配布が取りやめになっていましたがまさかの復活を遂げています。
こちらのソフトウェアについて、接続情報を.rdg
ファイルとして保存しておりますが。
今回は.rdg
ファイルから設定を読み取り、パスワードを復号する方法を説明します。
なお本手順で説明する復号化については、rdgファイル
を作成したユーザ & Windows環境のPowerShell でないと復号はできないかと思います。
ドキュメント・参考サイト
- Sysinternals
- Sysinternals Remote Desktop Connection Manager
- DECRYPTING REMOTE DESKTOP CONNECTION MANAGER PASSWORDS WITH POWERSHELL
- https://www.pdq.com/blog/rdcman-file-powershell/
復号化
.rdg
ファイルは実体としてはxmlファイルとなっており、password
ノードに暗号化されて保存されています。
このpsswordノードに記載されている文字列はRDCMan.exeをPowerShell
のImport-Module <<rdcman.exeパス>>
とすると[RdcMan.Encryption]
がインポート出来るので。
※WindowsPowerShell
では拡張子.exeをImport-Moduleで読めないので。RDCMan.exeをRDCMan.dllに変更して読み込んで下さい。
ここに用意されているDecryptString
メソッドを使うと復号化できるようになります。
# RDCMan.exeをdllに変更してImport-Module
Import-Module .\RDCMan.dll
# DecryptStringメソッドで復号化
[RdcMan.Encryption]::DecryptString( <<<passwordnoteの文字列>>>, $(New-Object -TypeName RdcMan.EncryptionSettings))
rdgファイルを読み込むサンプル
Inherit from parent
で資格情報を参照設定している物については未対応ですが、RDCMan.exe
が存在するディレクトリに下記スクリプト配置して実行すると情報を一覧で出力するサンプルとなります。
#!/usr/bin/env pwsh
<#
.SYNOPSIS
rdgファイルから設定情報を抽出
.DESCRIPTION
rdgファイルから設定情報を抽出
rdcman.exeを配置しているディレクトリに配置して実行して下さい
Inherit from parentの設定方法には未対応
.EXAMPLE
PS C:\> ./Convert-FromRDGFile.ps1 -Path <<RDG File>>
Explanation of what the example does
.INPUTS
none
.OUTPUTS
Output (if any)
.NOTES
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$RDGFilePath
)
PROCESS {
Set-StrictMode -Version Latest
$ErrorActionPreference = "stop"
# RDCman.exeをインポート
# WindowsPowerShellでは拡張子exeは読み込めないためdllとしてコピー
if (-not (Test-Path -Path "$PSScriptRoot\RDCMan.dll")){
Copy-Item -path "$PSScriptRoot\RDCMan.exe" -Destination "$PSScriptRoot\RDCMan.dll" -Force
}
Import-Module "$PSScriptRoot\RDCMan.dll" -Force
$EncryptionSettings = New-Object -TypeName RdcMan.EncryptionSettings
# rdgファイルを読み込み
[xml]$rdgFile = Get-Content -Path $RDGFilePath
$servers = Select-Xml -Xml $rdgFile -XPath '//server' | Select-Object -ExpandProperty Node
foreach ($serverNode in $servers) {
$outputRow = [PSCustomObject]@{
scope = ""
displayName = ""
name = ""
userName = ""
domain = ""
passwordString = ""
}
# displayNameが存在するかチェック
if ([boolean]($serverNode.properties | Get-Member DisplayName)) {
$outputRow.displayName = $serverNode.properties.displayName
}
$outputRow.name = $serverNode.properties.Name
# logonCredentialsが登録なければループを飛ばす
if (-not [boolean]($serverNode | Get-Member logonCredentials)) {
write-output $outputRow
continue
}
switch ($serverNode.logonCredentials.profileName.scope) {
"Local" {
$outputRow.scope = "Local"
$outputRow.userName = $serverNode.logonCredentials.userName
$outputRow.domain = $serverNode.logonCredentials.domain
$outputRow.passwordString = [RdcMan.Encryption]::DecryptString($serverNode.logonCredentials.password, $EncryptionSettings)
}
"File" {
$outputRow.scope = "File"
$XPATH = "//credentialsProfile[profileName='{0}']" -f $serverNode.logonCredentials.profileName."#text"
$credentialsProfile = Select-Xml -Xml $rdgFile -XPath $XPATH
$outputRow.userName = $credentialsProfile.Node.userName
$outputRow.domain = $credentialsProfile.Node.userName
$outputRow.passwordString = [RdcMan.Encryption]::DecryptString($credentialsProfile.Node.password, $EncryptionSettings)
}
Default {}
}
write-output $outputRow
}
}
総評
使う機会はないような気がしますが、こういう方法があるんですね。 といった感あります。