Assets/New-OpsCreds.ps1

<#
.SYNOPSIS
    Creates and stores credentials securely.
.DESCRIPTION
    Stores a PSCredential with Export-Clixml. On Windows this is encrypted with
    DPAPI under the *current* user, so the file can only be read back by that
    same account: create secrets as the account the job runs under.
.PARAMETER Name
    Name of the credential (filename).
.PARAMETER Credential
    Credential to store. Prompts if not supplied.
#>

param (
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [string]$Name,

    [System.Management.Automation.PSCredential]
    [System.Management.Automation.Credential()]
    $Credential
)

$ErrorActionPreference = "Stop"

if ($Name -match '[\\/:*?"<>|]') {
    throw "Name '$Name' contains characters that are invalid in a file name (\ / : * ? "" < > |)."
}

# The Ops root defaults to C:\Ops. OPS_ROOT overrides it for development and
# testing, matching the dashboard server's existing convention.
$OpsRoot = if ([string]::IsNullOrWhiteSpace($env:OPS_ROOT)) { "C:\Ops" } else { $env:OPS_ROOT }
$SecretsDir = Join-Path $OpsRoot "Secrets"
if (-not (Test-Path $SecretsDir)) {
    New-Item -ItemType Directory -Path $SecretsDir -Force | Out-Null
}

if ($null -eq $Credential) {
    $Credential = Get-Credential -Message "Enter the credential to store as '$Name'"
}
if ($null -eq $Credential) {
    throw "No credential supplied."
}

$Path = Join-Path $SecretsDir "$Name.xml"

$Credential | Export-Clixml -Path $Path

Write-Host "Credential saved to $Path"
Write-Host "Note: DPAPI-encrypted for '$env:USERDOMAIN\$env:USERNAME'. The job's service account must be the same user to read it back."