PowerShell Example via WinRM

Using Admin Credentials

To update the 'Log On As' property on a Windows Service, you will need a credential with the appropriate permissions, such as an Administrator account.

When attaching a PAM script to a record, you have the option to add a Resource Credential that is passed to the Gateway as part of the BASE64-encoded JSON data. The above credential will need to be attached as a Resource Credential.

As many Resource Credentials can be attached to a PAM script, knowing the UID of the Resource Credential you have attached helps ensure your script uses the correct one to update the Service's 'Log On As' property.

Updating the Service

PowerShell 7 makes it easy to update service credentials. By default, even in PowerShell 7, when remoting, the default PSSession will be Windows Powershell (v5). To remote using PowerShell 7, you can specify the built-in PowerShell 7 configuration: PowerShell.7. Once the rotation is complete, we will log the service status to DEBUG.

$ScheduledTaskName = '<Task Name>'
$ScheduledTaskStatus = Invoke-Command `
    -ComputerName '<Target Machine>' `
    -Credential $AdminCredential `
    -ConfigurationName 'PowerShell.7' `
    -ScriptBlock { 
        Stop-ScheduledTask -TaskName $Using:ScheduledTaskName
        Set-ScheduledTask -TaskName $Using:ScheduledTaskName -User $Using:Params.user -Password $Using:Params.newPassword
        Start-ScheduledTask -TaskName $Using:ScheduledTaskName
        return Get-ScheduledTask -TaskName $Using:ScheduledTaskName | Select-Object "State"
}

Write-Debug "$ScheduledTaskName is: $($ScheduledTaskStatus.State)"

Full Example

[CmdletBinding()]
param (
    [Parameter(ValueFromPipeline=$true)]
    [string]
    $B64Input
)

$ErrorActionPreference = "Stop"
$DebugPreference = 'Continue'

function ConvertFrom-B64 {
    param (
        [string] $B64String
    )

    try {
        $Json = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($B64String))
        $Output = $Json | ConvertFrom-Json
    }
    catch {
        Write-Error "Failed to convert Base64 string: $B64String"
    }
    return $Output
}

function New-PSCredential {
    param (
        [string] $Username,
        [string] $Password
    )

    try {
        $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
        $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $SecurePassword
        Write-Debug "New PSCredential created for: $Username" 
    }
    catch {
        Write-Error "Failed to create PSCredential for: $Username"
    }
    return $Credential
}

# The JSON data is passed to the Gateway as a Base64 encoded string.
$Params = ConvertFrom-B64 -B64String $B64Input
Write-Debug "Running Post-Rotation Script on: $($Params.userRecordUid)" 

# Create a PSCredential to be used to update the Service's `Log On As` property.
$ServiceAccountCredential = New-PSCredential -Username $Params.user -Password $Params.newpassword

# Convert the attached Resource Records from Base64 encoded JSON string and find the 
# Admin Record we need to update the Service's `Log On As` property by filtering by the 
# Admin Record's UID.
$ResourceCredentials = ConvertFrom-B64 -B64 $Params.records
$AdminRecord = $ResourceCredentials | Where-Object { $_.uid -eq '<Admin Record UID>' }

# Each record type will have a different JSON structure. In this instance, we are using 
# a PAM Directory record type, so we need to build the username from the `login` and 
# `domainName` properties.
$AdminCredential = New-PSCredential -Username "$($AdminRecord.login)@$($AdminRecord.domainName)" -Password $($AdminRecord.password)

# Rotate the Service's `Log On As` property
$ServiceName = '<Target Service>'
$ServiceStatus = Invoke-Command `
                    -ComputerName '<Target Machine>' `
                    -Credential $AdminCredential `
                    -ConfigurationName 'PowerShell.7' `
                    -ScriptBlock { `
                        Stop-Service $Using:ServiceName; `
                        Set-Service -Name $Using:ServiceName -Credential $Using:ServiceAccountCredential; `
                        Start-Service $Using:ServiceName; `
                        return Get-Service $Using:ServiceName;
                    }

Write-Debug "$ServiceName is: $($ServiceStatus.Status)"

Last updated