Task name
PowerShell@2
Task version
2.279.1
Issue Description
An explicitly mapped environment variable named SECRET_VALUE is silently removed before the user's PowerShell script starts. The script observes an empty/missing value even when the environment variable was populated before task SDK initialization.
This report concerns diagnostics and discoverability, not a request to remove secret protection or make reserved prefixes unrestricted.
The symptom looks like a missing password, incorrect variable-group scope, or an authorization problem. I spent hours investigating the wrong configuration layer because there was no diagnostic identifying the environment-variable name collision.
Environment
- Azure DevOps Services (
dev.azure.com)
- Self-hosted Windows agent
- PowerShell@2 with
pwsh: true, launching PowerShell 7
- Exact agent and Windows versions are not included in this report.
Minimal pipeline example
This example uses only a synthetic, non-secret value. No variable group or credential is required to illustrate the collision.
trigger: none
pr: none
pool:
vmImage: windows-latest
steps:
- task: PowerShell@2
inputs:
targetType: inline
pwsh: true
script: |
$present = -not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE)
Write-Host "SECRET_VALUE present: $present"
if (-not $present) {
throw 'The explicitly mapped environment variable is missing.'
}
env:
SECRET_VALUE: offline-fixture-not-a-real-password
Workaround: rename the explicit environment mapping to a name without the reserved prefix, such as APP_AUTH_PASSWORD, and update the script to read $env:APP_AUTH_PASSWORD.
The real failure was observed on a self-hosted Windows agent. The simplified windows-latest pipeline above has not been queued; the controlled reproduction below was executed locally against the SDK shipped in the exact task version.
Verified local reproduction
To avoid waiting for a busy agent pool, I downloaded the PowerShell task package for version 2.279.1 from Azure DevOps and used its actual ps_modules\VstsTaskSdk\InputFunctions.ps1.
In a disposable PowerShell process, initialize a synthetic value, run the SDK's Initialize-Inputs, and then launch a child PowerShell process. The initialization function modifies the current process environment, so this should not be run inside a session containing real task credentials.
param(
[Parameter(Mandatory)]
[string]$TaskPackageDirectory
)
. (Join-Path $TaskPackageDirectory 'ps_modules\VstsTaskSdk\InputFunctions.ps1')
$env:SECRET_VALUE = 'offline-fixture-not-a-real-password'
$env:APP_AUTH_PASSWORD = 'offline-fixture-not-a-real-password'
Write-Host "Before: SECRET_VALUE present=$(-not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE))"
Write-Host "Before: APP_AUTH_PASSWORD present=$(-not [string]::IsNullOrWhiteSpace($env:APP_AUTH_PASSWORD))"
Initialize-Inputs
pwsh -NoLogo -NoProfile -NonInteractive -Command {
Write-Host "Child: SECRET_VALUE present=$(-not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE))"
Write-Host "Child: APP_AUTH_PASSWORD present=$(-not [string]::IsNullOrWhiteSpace($env:APP_AUTH_PASSWORD))"
}
In the executed controlled test, the original script was also run in a child pwsh process with external operations mocked. Changing only the mapped environment name and its script references produced:
| Mapping |
Before SDK initialization |
After SDK initialization |
Child script |
SECRET_VALUE |
Present |
Missing |
Failed with the same missing-value error |
Non-reserved name (RABBITMQ_AUTH_PASSWORD in the test) |
Present |
Present |
Passed; the dummy value reached the mocked command intact |
No actual credential was needed, inspected, or changed for this reproduction. No deployment was performed.
Relevant log output
The original task's user-script guard reported:
The configured secret value is empty or missing.
PowerShell exited with code '1'.
The local reproduction showed:
Before SDK initialization: SECRET_VALUE present=True
After SDK initialization: SECRET_VALUE present=False
Verified child exit code: 1
Before SDK initialization: RABBITMQ_AUTH_PASSWORD present=True
After SDK initialization: RABBITMQ_AUTH_PASSWORD present=True
PASS: configured password reached the child process and mocked secret creation.
Verified child exit code: 0
Full private pipeline logs are intentionally omitted. The synthetic reproduction isolates the behavior without infrastructure details or secrets.
Source-level explanation
In the SDK bundled with PowerShell 2.279.1, InputFunctions.ps1:
- Line 459 enumerates
Env:ENDPOINT_?*, Env:INPUT_?*, Env:SECRET_?*, and Env:SECUREFILE_?*.
- Matching values are stored in the SDK's internal vault.
- Line 483 removes each matching environment variable with
Remove-Item.
VstsTaskSdk.psm1, line 158 in that package, calls Initialize-Inputs before invoking the task script. The Windows PowerShell task subsequently launches the user's pwsh process, which no longer inherits SECRET_VALUE.
The same mechanism is visible in the public source:
Expected behavior / requested improvement
Please detect collisions in user-supplied explicit env: mappings, at a layer that can distinguish them from legitimate SDK-internal variables, and provide an actionable warning or validation error. For example:
The explicitly mapped environment variable 'SECRET_VALUE' uses a reserved task SDK prefix and will not be available to the child script. Rename the environment mapping to a non-reserved name.
The diagnostic must not print the value. It should not warn indiscriminately about normal internal SECRET_* variables.
A task-specific documentation example and a regression test for explicit mappings would also help prevent this misleading failure mode.
Related issue
microsoft/azure-pipelines-task-lib#544 describes the broader reserved-prefix collision, primarily for pipeline variables beginning with Input.. This report adds an exact-version Windows PowerShell@2 reproduction for an explicit env: SECRET_VALUE mapping and requests actionable diagnostics.
Task name
PowerShell@2
Task version
2.279.1
Issue Description
An explicitly mapped environment variable named
SECRET_VALUEis silently removed before the user's PowerShell script starts. The script observes an empty/missing value even when the environment variable was populated before task SDK initialization.This report concerns diagnostics and discoverability, not a request to remove secret protection or make reserved prefixes unrestricted.
The symptom looks like a missing password, incorrect variable-group scope, or an authorization problem. I spent hours investigating the wrong configuration layer because there was no diagnostic identifying the environment-variable name collision.
Environment
dev.azure.com)pwsh: true, launching PowerShell 7Minimal pipeline example
This example uses only a synthetic, non-secret value. No variable group or credential is required to illustrate the collision.
Workaround: rename the explicit environment mapping to a name without the reserved prefix, such as
APP_AUTH_PASSWORD, and update the script to read$env:APP_AUTH_PASSWORD.The real failure was observed on a self-hosted Windows agent. The simplified
windows-latestpipeline above has not been queued; the controlled reproduction below was executed locally against the SDK shipped in the exact task version.Verified local reproduction
To avoid waiting for a busy agent pool, I downloaded the PowerShell task package for version 2.279.1 from Azure DevOps and used its actual
ps_modules\VstsTaskSdk\InputFunctions.ps1.In a disposable PowerShell process, initialize a synthetic value, run the SDK's
Initialize-Inputs, and then launch a child PowerShell process. The initialization function modifies the current process environment, so this should not be run inside a session containing real task credentials.In the executed controlled test, the original script was also run in a child
pwshprocess with external operations mocked. Changing only the mapped environment name and its script references produced:SECRET_VALUERABBITMQ_AUTH_PASSWORDin the test)No actual credential was needed, inspected, or changed for this reproduction. No deployment was performed.
Relevant log output
The original task's user-script guard reported:
The local reproduction showed:
Full private pipeline logs are intentionally omitted. The synthetic reproduction isolates the behavior without infrastructure details or secrets.
Source-level explanation
In the SDK bundled with PowerShell 2.279.1,
InputFunctions.ps1:Env:ENDPOINT_?*,Env:INPUT_?*,Env:SECRET_?*, andEnv:SECUREFILE_?*.Remove-Item.VstsTaskSdk.psm1, line 158 in that package, callsInitialize-Inputsbefore invoking the task script. The Windows PowerShell task subsequently launches the user'spwshprocess, which no longer inheritsSECRET_VALUE.The same mechanism is visible in the public source:
Expected behavior / requested improvement
Please detect collisions in user-supplied explicit
env:mappings, at a layer that can distinguish them from legitimate SDK-internal variables, and provide an actionable warning or validation error. For example:The diagnostic must not print the value. It should not warn indiscriminately about normal internal
SECRET_*variables.A task-specific documentation example and a regression test for explicit mappings would also help prevent this misleading failure mode.
Related issue
microsoft/azure-pipelines-task-lib#544 describes the broader reserved-prefix collision, primarily for pipeline variables beginning with
Input.. This report adds an exact-version Windows PowerShell@2 reproduction for an explicitenv: SECRET_VALUEmapping and requests actionable diagnostics.