# Code Examples

### Echo Inputs

The below example post-rotation scripts simply echo the input parameters in various languages and platforms. The output of the print statements can be found in the Keeper Gateway log file.

* [Bash](#bash-script)
* [PowerShell](#powershell-script)
* [Keeper Secrets Manager SDKs](#keeper-secrets-manager-sdks)

#### Bash

Note: For this example, [jq](https://stedolan.github.io/jq/) needs to be installed to parse the JSON. Attach this as a PAM script and perform the rotation. The Gateway logfile will contain the output.

{% code title="decode-and-echo.sh" %}

```bash
#!/bin/bash

# Read the Base64 encoded JSON input and decode it
decoded_json=$(cat | base64 --decode)

# Extract the "records" field, which is Base64 encoded, and decode it separately
records_base64=$(echo "$decoded_json" | jq -r '.records')

# Decode the Base64 "records" field and pretty-print the JSON
decoded_records=$(echo "$records_base64" | base64 --decode | jq '.')

# Print the entire decoded JSON, replacing "records" with the decoded version
echo "$decoded_json" | jq --argjson records "$decoded_records" '.records = $records'
```

{% endcode %}

#### PowerShell

Attach this as a PAM script and perform the rotation. The Keeper Gateway logfile will contain the output. This script simply echoes the input.

{% code overflow="wrap" %}

```powershell
Begin {
    # Executes once before first item in pipeline is processed
}

Process {
    # Stop if error. If not set, result value will be True and assumed there
    # was no problem.
    $ErrorActionPreference = "Stop"

    # Executes once for each pipeline object    
    $JSON = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($_))
    $Params = ($JSON | ConvertFrom-Json)

    Write-Output "providerRecordUid=$($Params.providerRecordUid)"
    Write-Output "resourceRecordUid=$($Params.resourceRecordUid)"
    Write-Output "userRecordUid=$($Params.userRecordUid)"
    Write-Output "newPassword=$($Params.newPassword)"
    Write-Output "oldPassword=$($Params.oldPassword)"
    Write-Output "user=$($Params.user)"

    $recordsJSON = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Params.records))
    $records = ($recordsJSON | ConvertFrom-Json)

    # Output full JSON for records
    Write-Output "Full Records JSON: $recordsJSON"

    # Extract the provider title from the records
    $title = ($records | Where-Object {$_.uid -eq $Params.providerRecordUid}).title
    Write-Output "Provider Title=$title"

    # Loop through all records and display details
    foreach ($record in $records) {
        Write-Output "Record UID=$($record.uid)"
        Write-Output "Record Title=$($record.title)"
        Write-Output "Record Type=$($record.type)"
        Write-Output "Record Details=$($record.details | ConvertTo-Json)"
    }
}

End {
    # Executes once after last pipeline object is processed
}
```

{% endcode %}

Here's a PowerShell script that sends a Webhook to a 3rd party site.

```powershell
param (
    [Parameter(ValueFromPipeline=$true)]
    [string]
    $Record
)

# Decode the Base64 input and convert it to a PowerShell object
$RecordJsonAsB64 = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Record))
$Params = $RecordJsonAsB64 | ConvertFrom-Json

# Prepare the webhook payload
$webhookPayload = @{
    providerRecordUid=$Params.providerRecordUid
    resourceRecordUid=$Params.resourceRecordUid
    userRecordUid=$Params.userRecordUid
    user=$Params.user
    timestamp= (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssZ")
    message= "Post-rotation script executed successfully."
} | ConvertTo-Json

# Define the webhook URL
$webhookUrl = "https://webhook.site/3308ec5a-3fba-4e31-85ad-37b0f643ac82"

# Send the POST request to the webhook
try {
    Invoke-RestMethod -Uri $webhookUrl -Method Post -Body $webhookPayload -ContentType 'application/json'
    Write-Host "Webhook message sent successfully."
}
catch {
    Write-Error "Failed to send webhook message: $_"
}
```

#### Using Keeper Secrets Manager SDKs

The post rotation script is not limited to shell scripts. Applications can be written in languages like Python or C# to get the piped parameters. Since the UIDs of the Rotation involved records are passed in the params, the post-rotation script can use the [Keeper Secrets Manager SDKs](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library) to get additional information.

{% code overflow="wrap" %}

```python
#!/usr/bin/env python3

import sys
import base64
import json

from keeper_secrets_manager_core import SecretsManager

# sys.stdin is not an array, it can not subscripted (ie sys.stdin[0])
for base64_params in sys.stdin:
    params = json.loads(base64.b64decode(base64_params).decode())
        
    print(f"providerRecordUid={params.get('providerRecordUid')}")
    print(f"resourceRecordUid={params.get('resourceRecordUid')}")
    print(f"userRecordUid={params.get('userRecordUid')}")
    print(f"newPassword={params.get('newPassword')}")
    print(f"oldPassword={params.get('oldPassword')}")
    print(f"user={params.get('user')}")

    records = json.loads(base64.b64decode(params.get('records')).decode())
    print("Provider Title="
        f"{next((x for x in records if x['uid'] == params.get('providerRecordUid')), None).get('title')}")

    ksm = SecretsManager(config=...)
    resource_records = ksm.get_secrets(params.get('userRecordUid'))[0]
    
    break
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/en/keeperpam/privileged-access-manager/password-rotation/post-rotation-scripts/accessing-parameters.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
