InputFunctions.ps1
$script:secureInputs = @{ } <# .SYNOPSIS Gets an endpoint. .DESCRIPTION Gets an endpoint object for the specified endpoint name. The endpoint is returned as an object with three properties: Auth, Data, and Url. The Data property requires a 1.97 agent or higher. .PARAMETER Require Writes an error to the error pipeline if the endpoint is not found. #> function Get-Endpoint { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [switch]$Require) # Get the URL. $url = (Get-SecureInput -Name (Get-LocString -Key PSLIB_EndpointUrl0 -ArgumentList $Name) -Path "Env:ENDPOINT_URL_$Name" -Require:$Require) # Short-circuit if not found. if ($Require -and !$url) { return } # Get the auth object. if ($auth = (Get-SecureInput -Name (Get-LocString -Key PSLIB_EndpointAuth0 -ArgumentList $Name) -Path "Env:ENDPOINT_AUTH_$Name" -Require:$Require)) { $auth = ConvertFrom-Json -InputObject $auth } # Short-circuit if not found. if ($Require -and !$auth) { return } # Get the data. if ($data = (Get-SecureInput -Name "'$Name' service endpoint data" -Path "Env:ENDPOINT_DATA_$Name")) { $data = ConvertFrom-Json -InputObject $data } # Return the endpoint. if ($url -or $auth -or $data) { New-Object -TypeName psobject -Property @{ Url = $url Auth = $auth Data = $data } } } <# .SYNOPSIS Gets an input. .DESCRIPTION Gets the value for the specified input name. .PARAMETER AsBool Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. .PARAMETER AsInt Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. .PARAMETER Default Default value to use if the input is null or empty. .PARAMETER Require Writes an error to the error pipeline if the input is null or empty. #> function Get-Input { [CmdletBinding(DefaultParameterSetName = 'Require')] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(ParameterSetName = 'Default')] $Default, [Parameter(ParameterSetName = 'Require')] [switch]$Require, [switch]$AsBool, [switch]$AsInt) # Update the Name in the bound parameters hashtable for downstream user facing # messages (i.e. required error message or interactive prompt). $PSBoundParameters['Name'] = (Get-LocString -Key PSLIB_Input0 -ArgumentList $Name) # Get the secure input. Splat the bound parameters hashtable. Splatting is required # in order to concisely invoke the correct parameter set. Get-SecureInput @PSBoundParameters -Path "Env:INPUT_$($Name.Replace(' ', '_').ToUpperInvariant())" } <# .SYNOPSIS Gets a task variable. .DESCRIPTION Gets the value for the specified task variable. .PARAMETER AsBool Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. .PARAMETER AsInt Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. .PARAMETER Default Default value to use if the input is null or empty. .PARAMETER Require Writes an error to the error pipeline if the input is null or empty. #> function Get-TaskVariable { [CmdletBinding(DefaultParameterSetName = 'Require')] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(ParameterSetName = 'Default')] $Default, [Parameter(ParameterSetName = 'Require')] [switch]$Require, [switch]$AsBool, [switch]$AsInt) # Update the Name in the bound parameters hashtable for downstream user facing # messages (i.e. required error message or interactive prompt). $PSBoundParameters['Name'] = Get-LocString -Key PSLIB_TaskVariable0 -ArgumentList $Name # Attempt to get the secret variable. $value = $null $path = "Env:SECRET_$(Format-VariableName $Name)" if ($psCredential = $script:secureInputs[$path]) { # The secret variable was found. $value = $psCredential.GetNetworkCredential().Password Get-FinalValue @PSBoundParameters -Path $path -Value $value } else { # Attempt to get the environment variable. $item = $null $path = "Env:$(Format-VariableName $Name)" if ((Test-Path -LiteralPath $path) -and ($item = Get-Item -LiteralPath $path).Value) { # Intentionally empty. } elseif (!$script:nonInteractive) { # The value wasn't found. Prompt for the value if running in interactive dev mode. Set-Item -LiteralPath $path -Value (Read-Host -Prompt $Name) if (Test-Path -LiteralPath $path) { $item = Get-Item -LiteralPath $path } } # Get the converted value. Splat the bound parameters hashtable. Splatting is required # in order to concisely invoke the correct parameter set. Get-FinalValue @PSBoundParameters -Path $path -Value $item.Value } } <# .SYNOPSIS Sets a task variable. .DESCRIPTION Sets a task variable in the current task context as well as in the current job context. This allows the task variable to retrieved by subsequent tasks within the same job. #> function Set-TaskVariable { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [string]$Value, [switch]$Secret) # Set the environment variable. $path = "Env:$(Format-VariableName $Name)" Write-Verbose "Set $path = '$(if ($Secret) { '********' } else { $Value })'" Set-Item -LiteralPath $path -Value $Value # Persist the variable in the task context. Write-SetVariable -Name $Name -Value $Value -Secret:$Secret } ######################################## # Private functions. ######################################## function Get-SecureInput { [CmdletBinding(DefaultParameterSetName = 'Require')] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Path, [Parameter(ParameterSetName = 'Require')] [switch]$Require, [Parameter(ParameterSetName = 'Default')] [object]$Default, [switch]$AsBool, [switch]$AsInt) # Attempt to get the secure variable. $value = $null if ($psCredential = $script:secureInputs[$Path]) { $value = $psCredential.GetNetworkCredential().Password } elseif (!$script:nonInteractive) { # The value wasn't found. Prompt for the value if running in interactive dev mode. $value = Read-Host -Prompt $Name if ($value) { $script:secureInputs[$Path] = New-Object System.Management.Automation.PSCredential( $Path, (ConvertTo-SecureString -String $value -AsPlainText -Force)) } } Get-FinalValue -Value $value @PSBoundParameters } function Get-FinalValue { [CmdletBinding(DefaultParameterSetName = 'Require')] param( [string]$Value, [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Path, [Parameter(ParameterSetName = 'Require')] [switch]$Require, [Parameter(ParameterSetName = 'Default')] [object]$Default, [switch]$AsBool, [switch]$AsInt) $result = $Value if ($result) { if ($Path -like 'Env:ENDPOINT_AUTH_*') { Write-Verbose "$($Path): '********'" } else { Write-Verbose "$($Path): '$result'" } } else { Write-Verbose "$Path (empty)" # Write error if required. if ($Require) { Write-Error "$(Get-LocString -Key PSLIB_Required0 $Name)" return } # Fallback to the default if provided. if ($PSCmdlet.ParameterSetName -eq 'Default') { $result = $Default Write-Verbose " Defaulted to: '$result'" } else { $result = '' } } # Convert to bool if specified. if ($AsBool) { if ($result -isnot [bool]) { $result = "$result" -in '1', 'true' Write-Verbose " Converted to bool: $result" } return $result } # Convert to int if specified. if ($AsInt) { if ($result -isnot [int]) { try { $result = [int]"$result" } catch { $result = 0 } Write-Verbose " Converted to int: $result" } return $result } return $result } function Initialize-SecureInputs { # Store endpoints/inputs in a secure fashion. foreach ($variable in (Get-ChildItem -Path Env:ENDPOINT_*, Env:INPUT_*, Env:SECRET_*)) { $path = "Env:$($variable.Name)" if ($variable.Value) { $script:secureInputs[$path] = New-Object System.Management.Automation.PSCredential( $path, (ConvertTo-SecureString -String $variable.Value -AsPlainText -Force)) } # Clear the environment variable. Remove-Item -LiteralPath $path } } function Format-VariableName { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name) if ($Name -ne 'agent.jobstatus') { $Name = $Name.Replace('.', '_') } $Name.ToUpperInvariant() } |