-
Notifications
You must be signed in to change notification settings - Fork 60
Implement Microsoft.PowerShell.SecretManagement extension #1074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| microsoft.powershell.secret.ps1 | ||
| microsoft.powershell.dsc.extension.json | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "$schema": "https://aka.ms/dsc/schemas/v3/bundled/extension/manifest.json", | ||
| "type": "Microsoft.PowerShell/SecretManagement", | ||
| "version": "0.1.0", | ||
| "description": "Retrieve secrets using the Microsoft.PowerShell.SecretManagement module", | ||
| "secret": { | ||
| "executable": "pwsh", | ||
| "args": [ | ||
| "-NoLogo", | ||
| "-NonInteractive", | ||
| "-NoProfile", | ||
| "-Command", | ||
| "./microsoft.powershell.secret.ps1", | ||
| { | ||
| "nameArg": "-Name" | ||
| }, | ||
| { | ||
| "vaultArg": "-Vault" | ||
| } | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,25 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Copyright (c) Microsoft Corporation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Licensed under the MIT License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| [CmdletBinding()] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| param( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Parameter(Mandatory = $true)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [string]$Name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [Parameter()] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [string]$Vault | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Get-Command Get-Secret -ErrorAction Ignore) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| $secretParams = @{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Name = $Name | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| AsPlainText = $true | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (-not ([string]::IsNullOrEmpty($Vault))) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| $secretParams['Vault'] = $Vault | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| $secret = Get-Secret @secretParams -ErrorAction Ignore | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| $secret = Get-Secret @secretParams -ErrorAction Ignore | |
| $secret = Get-Secret @secretParams -ErrorAction Ignore |
Copilot
AI
Mar 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Get-Secret isn’t available (module missing) or Get-Secret fails for reasons other than “not found”, this script silently produces no output due to the Get-Command guard and -ErrorAction Ignore. That can surface as a misleading “Secret '' not found” from DSC. Consider emitting a clear error to stderr and returning a non-zero exit code when prerequisites are missing or when Get-Secret errors unexpectedly, while still returning no output for the “secret not found” case.
| $secret = Get-Secret @secretParams -ErrorAction Ignore | |
| Write-Output $secret | |
| try { | |
| $secret = Get-Secret @secretParams -ErrorAction Stop | |
| Write-Output $secret | |
| } | |
| catch { | |
| $errorRecord = $_ | |
| $exceptionTypeName = $errorRecord.Exception.GetType().Name | |
| $fullyQualifiedErrorId = $errorRecord.FullyQualifiedErrorId | |
| # Treat "secret not found" as a non-error and return no output to preserve existing behavior. | |
| if ($exceptionTypeName -eq 'SecretNotFoundException' -or | |
| $fullyQualifiedErrorId -like '*SecretNotFound*') { | |
| return | |
| } | |
| Write-Error -Message ("Failed to retrieve secret '{0}': {1}" -f $Name, $errorRecord.Exception.Message) | |
| exit 1 | |
| } | |
| } | |
| else { | |
| Write-Error -Message "Required cmdlet 'Get-Secret' was not found. Ensure the Microsoft.PowerShell.SecretManagement module is installed and imported." | |
| exit 1 |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,41 @@ | ||||||||||||||||||||||||||||||||||
| # Copyright (c) Microsoft Corporation. | ||||||||||||||||||||||||||||||||||
| # Licensed under the MIT License. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| BeforeDiscovery { | ||||||||||||||||||||||||||||||||||
| $runningInCI = $false | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+4
to
+6
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| BeforeAll { | ||||||||||||||||||||||||||||||||||
| $FullyQualifiedName = @() | ||||||||||||||||||||||||||||||||||
| $FullyQualifiedName += @{ModuleName="Microsoft.PowerShell.SecretManagement";ModuleVersion="1.1.2"} | ||||||||||||||||||||||||||||||||||
| $FullyQualifiedName += @{ModuleName="Microsoft.PowerShell.SecretStore";ModuleVersion="1.0.6"} | ||||||||||||||||||||||||||||||||||
| foreach ($module in $FullyQualifiedName) { | ||||||||||||||||||||||||||||||||||
| if (-not (Get-Module -ListAvailable -FullyQualifiedName $module)) { | ||||||||||||||||||||||||||||||||||
| Save-PSResource -Name $module.ModuleName -Version $module.ModuleVersion -Path $TestDrive -Repository PSGallery -TrustRepository | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+14
|
||||||||||||||||||||||||||||||||||
| foreach ($module in $FullyQualifiedName) { | |
| if (-not (Get-Module -ListAvailable -FullyQualifiedName $module)) { | |
| Save-PSResource -Name $module.ModuleName -Version $module.ModuleVersion -Path $TestDrive -Repository PSGallery -TrustRepository | |
| # Select repository dynamically to align with CI configuration | |
| $repositoryName = 'PSGallery' | |
| if ($env:TF_BUILD -and (Get-Command -Name Get-PSResourceRepository -ErrorAction SilentlyContinue)) { | |
| $cfsRepo = Get-PSResourceRepository -Name 'CFS' -ErrorAction SilentlyContinue | |
| if ($null -ne $cfsRepo) { | |
| $repositoryName = 'CFS' | |
| } | |
| } | |
| foreach ($module in $FullyQualifiedName) { | |
| if (-not (Get-Module -ListAvailable -FullyQualifiedName $module)) { | |
| Save-PSResource -Name $module.ModuleName -Version $module.ModuleVersion -Path $TestDrive -Repository $repositoryName -TrustRepository |
Copilot
AI
Mar 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$env:PSModulePath is modified but never restored. This can leak state into later Pester suites in the same run; please capture the original value in BeforeAll and restore it in AfterAll (similar to how other tests restore $env:PATH).
Copilot
AI
Mar 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reset-SecretStore resets the current user’s SecretStore and can delete/overwrite existing secrets. If this suite is intended for CI-only execution, please ensure it is skipped locally; otherwise, consider using an isolated/temporary store configuration so running Invoke-Pester doesn’t destroy a developer’s SecretStore state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding
copy_files.txtsuggests these files should be included in build/package outputs, butpackaging.ps1currently only builds/copiesextensions/appxunder theextensions/tree. Without addingextensions/powershell/secretto the build/packaging project list (or otherwise wiring this directory into packaging), these files likely won’t ship in produced artifacts.