diff --git a/scripts/Set-HistorianCredentials.ps1 b/scripts/Set-HistorianCredentials.ps1 new file mode 100644 index 0000000..fae789d --- /dev/null +++ b/scripts/Set-HistorianCredentials.ps1 @@ -0,0 +1,117 @@ +<# +.SYNOPSIS +Prompts for Historian credentials and persists them to an encrypted file under the +current user's profile, or loads previously-saved credentials into the current +session's HISTORIAN_USER and HISTORIAN_PASSWORD environment variables. + +.DESCRIPTION +Persistence uses Windows DPAPI via Export-Clixml. The resulting XML can only be +decrypted by the same user account on the same machine. The file is saved +outside the repository (default: $env:USERPROFILE\.histsdk\credentials.xml) so +it cannot be accidentally committed. + +The integration tests in this repo read HISTORIAN_USER and HISTORIAN_PASSWORD +from the process environment. Run this script with -Load before launching +`dotnet test` to inject the saved credentials into the current session. + +.PARAMETER Load +Read previously-saved credentials and set $env:HISTORIAN_USER + $env:HISTORIAN_PASSWORD +in the current PowerShell session. The variables persist for the lifetime of +this session only - re-run with -Load in a new shell. + +.PARAMETER Clear +Delete the saved credentials file. Subsequent -Load calls will fail until +credentials are re-saved. + +.PARAMETER Path +Override the default storage path. Useful for keeping multiple credential sets +side-by-side (e.g. local-vs-remote). + +.PARAMETER UserName +Skip the username prompt and use the supplied value. Password is still prompted +interactively. Convenient for scripted re-saves where only the password rotates. + +.EXAMPLE +PS> .\scripts\Set-HistorianCredentials.ps1 +Prompts for username + password, saves both to %USERPROFILE%\.histsdk\credentials.xml. + +.EXAMPLE +PS> .\scripts\Set-HistorianCredentials.ps1 -Load +Loads the saved credentials into HISTORIAN_USER and HISTORIAN_PASSWORD for this session. + +.EXAMPLE +PS> .\scripts\Set-HistorianCredentials.ps1 -Clear +Deletes the saved credentials file. +#> +[CmdletBinding(DefaultParameterSetName = 'Save')] +param( + [Parameter(ParameterSetName = 'Load')] + [switch]$Load, + + [Parameter(ParameterSetName = 'Clear')] + [switch]$Clear, + + [string]$Path = (Join-Path $env:USERPROFILE '.histsdk\credentials.xml'), + + [Parameter(ParameterSetName = 'Save')] + [string]$UserName +) + +$ErrorActionPreference = 'Stop' + +function ConvertTo-PlainText { + param([Parameter(Mandatory)][securestring]$SecureString) + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) + try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } + finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } +} + +if ($Clear) { + if (Test-Path $Path) { + Remove-Item -LiteralPath $Path -Force + Write-Host "Deleted $Path" + } else { + Write-Host "Nothing to clear (file does not exist): $Path" + } + return +} + +if ($Load) { + if (-not (Test-Path $Path)) { + throw "No saved credentials at $Path. Run this script without -Load to save them first." + } + $cred = Import-Clixml -LiteralPath $Path + if ($cred -isnot [System.Management.Automation.PSCredential]) { + throw "File at $Path is not a PSCredential - re-save with this script." + } + $env:HISTORIAN_USER = $cred.UserName + $env:HISTORIAN_PASSWORD = ConvertTo-PlainText $cred.Password + Write-Host "Loaded credentials for '$($cred.UserName)' from $Path." + Write-Host "HISTORIAN_USER and HISTORIAN_PASSWORD are set for this PowerShell session." + return +} + +# Save mode (default). +$dir = Split-Path -Parent $Path +if (-not (Test-Path $dir)) { + New-Item -ItemType Directory -Force -Path $dir | Out-Null +} + +if ([string]::IsNullOrWhiteSpace($UserName)) { + $suggested = "$env:COMPUTERNAME\$env:USERNAME" + $UserName = Read-Host "Historian user [$suggested]" + if ([string]::IsNullOrWhiteSpace($UserName)) { + $UserName = $suggested + } +} + +$securePassword = Read-Host "Historian password for '$UserName'" -AsSecureString +$cred = New-Object System.Management.Automation.PSCredential($UserName, $securePassword) +$cred | Export-Clixml -LiteralPath $Path + +Write-Host "" +Write-Host "Saved credentials for '$UserName' to $Path" +Write-Host "(DPAPI-encrypted; decryptable only by '$env:USERNAME' on '$env:COMPUTERNAME'.)" +Write-Host "" +Write-Host "Run '.\scripts\Set-HistorianCredentials.ps1 -Load' in any new session to inject" +Write-Host "the credentials into HISTORIAN_USER and HISTORIAN_PASSWORD."