PowerShell Example with WinRM
PAM script for updating the credential of a Windows Server using WinRM
Last updated
Was this helpful?
PAM script for updating the credential of a Windows Server using WinRM
Last updated
Was this helpful?
The following PowerShell code example updates the credential on a Windows Service after its password has been rotated via Keeper Rotation. This script is the preferred method of performing a service account credential update on either the local or remote system.
Step 1: Add a custom text field to the Keeper record called "remotecomp
" and provide the DNS name of the machine which is running the service. For this example, "EC2AMAZ-A0GBNDM" is the name of the machine.
Step 2: Add a custom text field to the Keeper record called "service" and provide the value of the service name. For example, "SNMPTRAP".
Step 3: Copy the PowerShell script below into a file which is saved to the PAM Scripts section of the record. Include two additional records in the selector. Select the current record and the administrative record (the same one used in the rotation settings).
Here's the resulting Record configuration in the vault:
The PAM Script configuration screen is below:
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
[string]
$Record
)
try {
# This Section brings in the PAM User Record Information
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."
}
# End of Section.
try {
# This Section brings in ALL associated Records and their Parameter Information
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."
}
# End of Section.
try {
# This Section Defines parameters from the User Record. "remotecomp" and "service" are coming from custom fields in the Pam User Record
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."
}
$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."
}
# End of Section.
try {
# This Section Defines your AD Administrative credentials from the Resource Record
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."
}
# End of Section.
# The above calls the Resrouce Record NOT any attached record to the script. Below is an example of calling out an atttached record to the script.
# $adAdminUser = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).login
# $adAdminPassword = ($records | Where-Object {$_.uid -eq "UID of Record Here"}).password
try {
# This Section further secures the AD administrative credentials into a Secure String
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."
}
# End of Section.
try {
# This Section creates a new PSSession with the AD Administrative Resource Record
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."
}
# End of Section.
try {
# This Script Block checks the status of the service on the remote computer
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 {
# This Script Block stops the service on the remote computer
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 {
# This Script Block Updates the service password on the remote computer
Write-Debug "Changing $serviceName password"
$passwordChangeResult = Invoke-Command -Session $session -ScriptBlock {
param ($serviceName, $newPassword)
try {
$service = Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'" -ErrorAction Stop
$result = $service.change($null,$null,$null,$null,$null,$null,$null,"$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, $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 {
# This Script Block Starts the service on the remote computer
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.
# This Sections Removes the PSSession
Remove-PSSession -Session $session
# End of Section