WinRMを使用したPowerShellの例
Windowsサービスの「Log on as」認証情報を更新するためのPAMスクリプト
最終更新
Windowsサービスの「Log on as」認証情報を更新するためのPAMスクリプト
最終更新
以降のページに掲載のPowerShellコード例では、Keeperローテーションでパスワードをローテーションした後、Windowsサービスの「Log on as」認証情報を更新します。これらのスクリプトは、ローカルのKeeperゲートウェイホストまたはターゲットのWindowsベースシステムで「Log on as」認証情報の更新を行う際に推奨される方法となります。
この例では、確立された「PSSession」を介してWindowsベースのターゲットシステムに「Invoke-Method」を使用し、サービス管理のためにネイティブなPowerShellコマンドレットを利用します。この場合、ターゲットのWindowsサービスの「Log on as」認証情報を管理するために、「Microsoft.PowerShell.Management」およびそのサブコマンド (「Get-Service」や「Set-Service」など) を使用しています。
Invoke-Command
を使用したPowerShellスクリプト (PSSessionとMicrosoft.PowerShell.Managementを利用)[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
[string]
$Record
)
try {
# このセクションでは、PAMユーザーのレコード情報を取得します
Write-Debug "Decoding and converting the PAM User Record Information from Base64"
$RecordJsonAsB64 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Record))
if (-not $RecordJsonAsB64) {
throw "Failed to decode the PAM User Record Information from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$RecordParams = $RecordJsonAsB64 | ConvertFrom-Json
if (-not $RecordParams) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "PAM User Record Information successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the PAM User Record Information: $_"
}
finally {
Write-Debug "Completed processing the PAM User Record Information."
}
# セクション終了
try {
# このセクションでは、すべての関連レコードとそのパラメータ情報を取得します
Write-Debug "Decoding and converting all associated records from Base64"
$recordsJSON = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($RecordParams.records))
if (-not $recordsJSON) {
throw "Failed to decode the associated records from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$records = $recordsJSON | ConvertFrom-Json
if (-not $records) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "Associated records successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the associated records: $_"
}
finally {
Write-Debug "Completed processing the associated records."
}
# セクション終了
try {
# このセクションでは、ユーザーレコードからのパラメータを定義します。"remotecomp" と "service" は PAM ユーザーレコードのカスタムフィールドから取得されます。
Write-Debug "Defining parameters from the User Record"
$ErrorActionPreference = 'Stop'
$DebugPreference = 'Continue'
$remoteComputer = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).remotecomp
if (-not $remoteComputer) {
throw "Failed to retrieve 'remotecomp' from the User Record."
}
$serviceName = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).service
if (-not $serviceName) {
throw "Failed to retrieve 'service' from the User Record."
}
$user = ($RecordParams.user)
if (-not $user) {
throw "Failed to retrieve 'user' from the User Record."
}
$newPassword = ($RecordParams.newPassword)
if (-not $newPassword) {
throw "Failed to retrieve 'newPassword' from the User Record."
}
Write-Debug "Parameters from the User Record successfully defined."
}
catch {
Write-Error "An error occurred while defining parameters from the User Record: $_"
}
finally {
Write-Debug "Completed defining parameters from the User Record."
}
# セクション終了
try {
# このセクションでは、リソースレコードから取得した AD 管理者認証情報を定義します。
Write-Debug "Defining AD Administrative credentials from the Resource Record"
$adAdminUser = ($records | Where-Object {$_.uid -eq $RecordParams.resourceRecordUid}).login
if (-not $adAdminUser) {
throw "Failed to retrieve 'login' from the Resource Record."
}
$adAdminPassword = ($records | Where-Object {$_.uid -eq $RecordParams.resourceRecordUid}).password
if (-not $adAdminPassword) {
throw "Failed to retrieve 'password' from the Resource Record."
}
Write-Debug "AD Administrative credentials successfully defined."
}
catch {
Write-Error "An error occurred while defining AD Administrative credentials from the Resource Record: $_"
}
finally {
Write-Debug "Completed defining AD Administrative credentials from the Resource Record."
}
# セクション終了
# 上記では、スクリプトに添付されたレコードではなく、リソースレコードを呼び出しています。以下は、スクリプトに添付されたレコードを呼び出す例です。
# $adAdminUser = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).login
# $adAdminPassword = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).password
try {
# このセクションでは、AD管理者の認証情報をセキュア文字列としてさらに安全に保護します。
Write-Debug "Securing the AD administrative credentials into a Secure String"
$securePassword = ConvertTo-SecureString $adAdminPassword -AsPlainText -Force
if (-not $securePassword) {
throw "Failed to convert the administrative password to a Secure String."
}
$credential = New-Object System.Management.Automation.PSCredential ("$adAdminUser", $securePassword)
if (-not $credential) {
throw "Failed to create PSCredential object."
}
Write-Debug "AD administrative credentials successfully secured and PSCredential object created."
}
catch {
Write-Error "An error occurred while securing AD administrative credentials: $_"
}
finally {
Write-Debug "Completed securing AD administrative credentials."
}
# セクション終了
try {
# このセクションでは、AD管理者リソースレコードを使用して新しいPSSessionを作成します。
Write-Debug "Creating a new PSSession with the AD Administrative Resource Record"
$session = New-PSSession -ComputerName $remoteComputer -Credential $credential -ErrorAction Stop
if (-not $session) {
throw "Failed to create a new PSSession."
}
Write-Debug "PSSession created successfully."
}
catch {
Write-Error "An error occurred while creating the PSSession: $_"
}
finally {
Write-Debug "Completed the attempt to create a new PSSession."
}
# セクション終了
try {
# このスクリプトブロックは、リモートコンピュータ上のサービスの状態を確認します。
Write-Debug "Checking the status of $serviceName"
$serviceStatus = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
$service = Get-Service -Name $serviceName -ErrorAction Stop
return $service.Status
}
catch {
throw "An error occurred while retrieving the service status: $_"
}
} -ArgumentList $serviceName
if ($serviceStatus -eq 'Stopped') {
Write-Debug "$serviceName is already stopped. Skipping the stop service script."
}
else {
try {
# このスクリプトブロックは、リモートコンピュータ上のサービスを停止します。
Write-Debug "Stopping $serviceName"
$stopServiceResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
Stop-Service -Name $serviceName -Force -ErrorAction Stop
$service = Get-Service -Name $serviceName
if ($service.Status -ne 'Stopped') {
throw "Service did not stop successfully. Current status: $($service.Status)"
}
Write-Output "Service stopped successfully"
}
catch {
throw "An error occurred while stopping the service: $_"
}
} -ArgumentList $serviceName
if ($stopServiceResult -ne "Service stopped successfully") {
throw "Service stop operation did not return success."
}
}
catch {
Write-Error "An error occurred while stopping the service: $_"
}
}
}
catch {
Write-Error "An error occurred while checking or stopping the service: $_"
}
finally {
Write-Debug "Completed checking and stopping the service."
}
try {
# このスクリプトブロックは、リモートコンピュータ上のサービスのパスワードを更新します。
Write-Debug "Changing $serviceName password"
$passwordChangeResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName, $user, $newPassword)
try {
$service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'" -ErrorAction Stop
$result = $service.change($null,$null,$null,$null,$null,$null,"$user","$newPassword")
if ($result.ReturnValue -eq 0) {
Write-Output "Password changed successfully"
}
else {
throw "Failed to change password with return value $($result.ReturnValue)"
}
}
catch {
throw "An error occurred while changing the service password: $_"
}
} -ArgumentList $serviceName, $user, $newPassword
if ($passwordChangeResult -ne "Password changed successfully") {
throw "Password change operation did not return success."
}
}
catch {
Write-Error "An error occurred while changing the service password: $_"
}
finally {
Write-Debug "Completed changing the service password."
}
try {
# このスクリプトブロックは、リモートコンピュータ上のサービスを開始します。
Write-Debug "Restarting $serviceName"
$startServiceResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
try {
Start-Service -Name $serviceName -ErrorAction Stop
$service = Get-Service -Name $serviceName
if ($service.Status -ne 'Running') {
throw "Service did not start successfully. Current status: $($service.Status)"
}
Write-Output "Service started successfully"
}
catch {
throw "An error occurred while starting the service: $_"
}
} -ArgumentList $serviceName
if ($startServiceResult -ne "Service started successfully") {
throw "Service start operation did not return success."
}
}
catch {
Write-Error "An error occurred while restarting the service: $_"
}
finally {
Write-Debug "Completed attempting to restart the service."
}
# End Script Block.
# このセクションは、PSSessionを削除します。
Remove-PSSession -Session $session
# セクション終了
以下は、結果として得られるボルト内のレコード設定となります。
この例では、Windowsベースのターゲットシステムへの「PSSession」を通じて「Service Control」を使用し、サービスの管理に必要なネイティブのPowerShellコマンドレットを利用します。この場合、「sc.exe stop SNMPTRAP」や「sc.exe start SNMPTRAP」などのサブコマンドを使って、ターゲットWindowsサービスの「Log on as」認証情報を管理します。
さらに、現在のPAMユーザーレコードと、スクリプトを実行するための管理者権限を持つ「管理者認証情報」レコードを選択して、2つの「ローテーションクレデンシャル」レコードを追加します。管理者認証情報は、「パスワードローテーション設定」で使用されているものと同じか、スクリプトとそのアクションを実行するための適切な管理者権限を持つ別のレコードとなります。
Invoke-Command
を使用したPowerShellスクリプト (PSSessionとサービスコントロールを利用)[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
[string]
$Record
)
try {
# このセクションでは、PAMユーザーレコード情報を取り込みます
Write-Debug "Decoding and converting the PAM User Record Information from Base64"
$RecordJsonAsB64 = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Record))
if (-not $RecordJsonAsB64) {
throw "Failed to decode the PAM User Record Information from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$RecordParams = $RecordJsonAsB64 | ConvertFrom-Json
if (-not $RecordParams) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "PAM User Record Information successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the PAM User Record Information: $_"
}
finally {
Write-Debug "Completed processing the PAM User Record Information."
}
# セクション終了
try {
# このセクションでは、すべての関連するレコードとそのパラメータ情報を取り込みます
Write-Debug "Decoding and converting all associated records from Base64"
$recordsJSON = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($RecordParams.records))
if (-not $recordsJSON) {
throw "Failed to decode the associated records from Base64."
}
Write-Debug "Converting the decoded JSON to PowerShell object"
$records = $recordsJSON | ConvertFrom-Json
if (-not $records) {
throw "Failed to convert the decoded JSON to PowerShell object."
}
Write-Debug "Associated records successfully retrieved and converted."
}
catch {
Write-Error "An error occurred while processing the associated records: $_"
}
finally {
Write-Debug "Completed processing the associated records."
}
# セクション終了
try {
# このセクションでは、ユーザーレコードからパラメータを定義します。「remotecomp」と「service」は、PAMユーザーレコードのカスタムフィールドから取得されます。
Write-Debug "Defining parameters from the User Record"
$ErrorActionPreference = 'Stop'
$DebugPreference = 'Continue'
$remoteComputer = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).remotecomp
if (-not $remoteComputer) {
throw "Failed to retrieve 'remotecomp' from the User Record."
}
$serviceName = ($records | Where-Object {$_.uid -eq $RecordParams.userRecordUid}).service
if (-not $serviceName) {
throw "Failed to retrieve 'service' from the User Record."
}
$user = ($RecordParams.user)
if (-not $user) {
throw "Failed to retrieve 'user' from the User Record."
}
$newPassword = ($RecordParams.newPassword)
if (-not $newPassword) {
throw "Failed to retrieve 'newPassword' from the User Record."
}
Write-Debug "Parameters from the User Record successfully defined."
}
catch {
Write-Error "An error occurred while defining parameters from the User Record: $_"
}
finally {
Write-Debug "Completed defining parameters from the User Record."
}
# セクション終了
try {
# このセクションでは、リソースレコードからAD管理者資格情報を定義します。
Write-Debug "Defining AD Administrative credentials from the Resource Record"
$adAdminUser = ($records | Where-Object {$_.uid -eq $RecordParams.resourceRecordUid}).login
if (-not $adAdminUser) {
throw "Failed to retrieve 'login' from the Resource Record."
}
$adAdminPassword = ($records | Where-Object {$_.uid -eq $RecordParams.resourceRecordUid}).password
if (-not $adAdminPassword) {
throw "Failed to retrieve 'password' from the Resource Record."
}
Write-Debug "AD Administrative credentials successfully defined."
}
catch {
Write-Error "An error occurred while defining AD Administrative credentials from the Resource Record: $_"
}
finally {
Write-Debug "Completed defining AD Administrative credentials from the Resource Record."
}
# セクション終了
# 上記は、スクリプトに添付されたレコードではなく、リソースレコードを呼び出しています。以下は、スクリプトに添付されたレコードを呼び出す例です。
# $adAdminUser = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).login
# $adAdminPassword = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).password
try {
# このセクションでは、AD管理者資格情報をさらに安全な文字列として保護します。
Write-Debug "Securing the AD administrative credentials into a Secure String"
$securePassword = ConvertTo-SecureString $adAdminPassword -AsPlainText -Force
if (-not $securePassword) {
throw "Failed to convert the administrative password to a Secure String."
}
$credential = New-Object System.Management.Automation.PSCredential ("$adAdminUser", $securePassword)
if (-not $credential) {
throw "Failed to create PSCredential object."
}
Write-Debug "AD administrative credentials successfully secured and PSCredential object created."
}
catch {
Write-Error "An error occurred while securing AD administrative credentials: $_"
}
finally {
Write-Debug "Completed securing AD administrative credentials."
}
# セクション終了
try {
# このセクションでは、AD管理者リソースレコードを使用して新しいPSSessionを作成します。d
Write-Debug "Creating a new PSSession with the AD Administrative Resource Record"
$session = New-PSSession -ComputerName $remoteComputer -Credential $credential -ErrorAction Stop
if (-not $session) {
throw "Failed to create a new PSSession."
}
Write-Debug "PSSession created successfully."
}
catch {
Write-Error "An error occurred while creating the PSSession: $_"
}
finally {
Write-Debug "Completed the attempt to create a new PSSession."
}
# セクション終了
# このスクリプトブロックは、サービスを停止します。
Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
# サービスがすでに停止しているか確認します。
$service = Get-Service -Name $serviceName
if ($service.Status -eq 'Stopped') {
Write-Debug "$serviceName is already stopped."
} else {
Write-Debug "Stopping $serviceName"
sc.exe stop $serviceName
# 停止コマンドが成功したか確認します。
if ($LASTEXITCODE -eq 0) {
Write-Debug "$serviceName stopped successfully."
} else {
Write-Error "Failed to stop $serviceName. Exit code: $LASTEXITCODE"
return # スクリプトブロックを終了します。
}
# サービスが停止するのを待つために5秒間スリープします。
Start-Sleep -Seconds 5
}
} -ArgumentList $serviceName
# スクリプトブロックの終了。
# サービスのパスワードの変更試行。
Invoke-Command -Session $session -ScriptBlock {
param ($user, $newPassword, $serviceName)
Write-Debug "Changing password for $serviceName"
sc.exe config $serviceName obj= $user password= $newPassword
# Configコマンドが成功したかどうかを確認します。
if ($LASTEXITCODE -eq 0) {
Write-Debug "Password for $serviceName changed successfully."
} else {
Write-Error "Failed to change password for $serviceName. Exit code: $LASTEXITCODE"
return # スクリプトブロックの終了。
}
# 変更が反映されるまで5秒間待機します。
Start-Sleep -Seconds 5
} -ArgumentList $user, $newPassword, $serviceName
# スクリプトブロックの終了。
# サービスを開始/再起動を試行。
Invoke-Command -Session $session -ScriptBlock {
param ($serviceName)
Write-Debug "Starting $serviceName"
sc.exe start $serviceName
# startコマンドが成功したか確認します。
if ($LASTEXITCODE -eq 0) {
Write-Debug "$serviceName started successfully."
} else {
Write-Error "Failed to start $serviceName. Exit code: $LASTEXITCODE"
return # Script Block exiting
}
# サービスが開始されるのを待つために5秒間スリープします。
Start-Sleep -Seconds 5
} -ArgumentList $serviceName
# スクリプトブロックの終了。
# このセクションはPSSessionを削除します。
Remove-PSSession -Session $session
# セクション終了
以下が結果として得られるボルト内のレコード設定となります。
以下は結果として得られるPAMスクリプト設定画面です。
PAMユーザーレコードに「remotecomp
」と「service
」という2つのカスタムテキストフィールドを追加します。「remotecomp
」フィールドには、サービスを実行しているターゲットシステムのDNS名を入力します。この例では、「EC2AMAZ-A0GBNDM」がターゲットシステムの名前となります。管理しているWindowsサービスがKeeperゲートウェイホストに対してローカルである場合は、「remotecomp
」フィールドに「localhost」を使用します。「service
」フィールドには、サービスの「Service Name」を入力します (「Display Name」ではありません)。この例では、「Service Name」は「SNMPTRAP」となります。
PAMユーザーレコードに「remotecomp
」と「service
」という2つのカスタムテキストフィールドを追加します。「remotecomp
」フィールドには、サービスを実行しているターゲットシステムのDNS名を入力します。この例では、「EC2AMAZ-A0GBNDM」がターゲットシステムの名前となります。管理しているWindowsサービスがKeeperゲートウェイホストに対してローカルである場合は、「remotecomp
」フィールドに「localhost」を使用します。「service
」フィールドには、サービスの「Service Name」を入力します (「Display Name」ではありません)。この例では、「Service Name」は「SNMPTRAP」となります。
さらに、「ローテーションクレデンシャル」レコードを2つ追加します。現在のPAMユーザーレコードと、このスクリプトを実行する管理者認証情報レコードを選択します。管理者認証情報は「パスワードローテーション設定」に使用されるものと同じものでも、スクリプトおよびそのアクションを実行するための正しい管理権限を持つ別のレコードでも構いません。
手順に従うと、Keeperのパスワードローテーションと同様に、[ローテーションする]ボタンを使用して、スクリプトを「オンデマンド」で実行してテストできます。また、「パスワードローテーション設定」でスクリプトのスケジュールを設定することもできます。
以下のPowerShellスクリプトを開いてコピーし、任意のファイル名で「.ps1」として保存します。この例では、スクリプトのファイル名を「rotate_service_cred.ps1
」としました。このスクリプトをPAMユーザーレコードの「PAMスクリプト」セクションに添付します。
以下のPowerShellスクリプトを開いてコピーし、任意のファイル名で「.ps1」として保存します。この例では、スクリプトのファイル名を「rotate_service_cred.ps1
」としました。このスクリプトをPAMユーザーレコードの「PAMスクリプト」セクションに添付します。