├── .config
└── tsaoptions.json
├── .github
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE
│ ├── Bug_Report.yaml
│ ├── Feature_Request.yaml
│ └── config.yml
├── SECURITY.md
└── workflows
│ └── ci-test.yml
├── .gitignore
├── .pipelines
└── SecretManagement-Official.yml
├── CHANGELOG.md
├── Directory.Build.props
├── Directory.Packages.props
├── Docs
└── ARCHITECTURE.md
├── Ev2Specs
└── ServiceGroupRoot
│ ├── RolloutSpec.json
│ ├── ScopeBindings.json
│ ├── SecretManagementToACR.Rollout.json
│ ├── ServiceModel.json
│ ├── Shell
│ └── Run
│ │ └── Run.ps1
│ └── buildver.txt
├── ExtensionModules
├── AKVaultScript
│ ├── AKVaultScript.Extension
│ │ ├── AKVaultScript.Extension.psd1
│ │ └── AKVaultScript.Extension.psm1
│ └── AKVaultScript.psd1
├── CredManStore
│ ├── Microsoft.PowerShell.CredManStore.Extension
│ │ └── Microsoft.PowerShell.CredManStore.Extension.psd1
│ ├── README.md
│ ├── Tests
│ │ └── Microsoft.PowerShell.CredManStore.Tests.ps1
│ ├── help
│ │ └── en-US
│ │ │ └── about_Microsoft.PowerShell.CredManStore.md
│ └── src
│ │ ├── Microsoft.PowerShell.CredManStore.psd1
│ │ └── code
│ │ ├── CredManStore.cs
│ │ ├── Microsoft.PowerShell.CredManStore.csproj
│ │ └── Utils.cs
└── TestLocalScript
│ ├── TestLocalScript.Extension
│ ├── TestLocalScript.Extension.psd1
│ └── TestLocalScript.Extension.psm1
│ └── TestLocalScript.psd1
├── LICENSE
├── README.md
├── SecretManagement.build.ps1
├── SecretManagement.sln
├── ThirdPartyNotices.txt
├── global.json
├── help
├── Get-Secret.md
├── Get-SecretInfo.md
├── Get-SecretVault.md
├── Register-SecretVault.md
├── Remove-Secret.md
├── Set-Secret.md
├── Set-SecretInfo.md
├── Set-SecretVaultDefault.md
├── Test-SecretVault.md
├── Unlock-SecretVault.md
└── Unregister-SecretVault.md
├── nuget.config
├── src
├── Microsoft.PowerShell.SecretManagement.format.ps1xml
├── Microsoft.PowerShell.SecretManagement.psd1
└── code
│ ├── Microsoft.PowerShell.SecretManagement.Library.nuspec
│ ├── Microsoft.PowerShell.SecretManagement.csproj
│ ├── SecretManagement.cs
│ ├── Utils.cs
│ └── images
│ └── PowerShell_64.png
├── test
└── Microsoft.PowerShell.SecretManagement.Tests.ps1
└── tools
├── installPSResources.ps1
└── updateVersion.ps1
/.config/tsaoptions.json:
--------------------------------------------------------------------------------
1 | {
2 | "instanceUrl": "https://msazure.visualstudio.com",
3 | "projectName": "One",
4 | "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell",
5 | "notificationAliases": [ "andschwa@microsoft.com", "slee@microsoft.com" ],
6 | "codebaseName": "PowerShell_SecretManagement_20240903",
7 | "tools": [ "CredScan", "PoliCheck", "BinSkim" ]
8 | }
9 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 | - Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support)
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Bug_Report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug report 🐛
2 | description: Report errors or unexpected behavior 🤔
3 | labels:
4 | - Needs-Triage
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: >
9 | This repository is **ONLY** for issues related to SecretManagement.
10 | - type: checkboxes
11 | attributes:
12 | label: Prerequisites
13 | options:
14 | - label: Write a descriptive title.
15 | required: true
16 | - label: Make sure you are able to repro it on the [latest released version](https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretManagement)
17 | required: true
18 | - label: Search the existing issues.
19 | required: true
20 | - type: textarea
21 | attributes:
22 | label: Steps to reproduce
23 | description: >
24 | List of steps, sample code, failing test or link to a project that reproduces the behavior.
25 | Make sure you place a stack trace inside a code (```) block to avoid linking unrelated issues.
26 | placeholder: >
27 | I am experiencing a problem with X.
28 | I think Y should be happening but Z is actually happening.
29 | validations:
30 | required: true
31 | - type: textarea
32 | attributes:
33 | label: Expected behavior
34 | render: console
35 | placeholder: |
36 | PS> 2 + 2
37 | 4
38 | validations:
39 | required: true
40 | - type: textarea
41 | attributes:
42 | label: Actual behavior
43 | render: console
44 | placeholder: |
45 | PS> 2 + 2
46 | 5
47 | validations:
48 | required: true
49 | - type: textarea
50 | attributes:
51 | label: Error details
52 | description: Paste verbatim output from `Get-Error` if PowerShell returns an error.
53 | render: console
54 | placeholder: PS> Get-Error
55 | - type: textarea
56 | attributes:
57 | label: Environment data
58 | description: Paste verbatim output from `$PSVersionTable` below.
59 | render: PowerShell
60 | placeholder: PS> $PSVersionTable
61 | validations:
62 | required: true
63 | - type: input
64 | validations:
65 | required: true
66 | attributes:
67 | label: Version
68 | description: Specify the version of Crescendo you are using.
69 | - type: textarea
70 | attributes:
71 | label: Visuals
72 | description: >
73 | Please upload images or animations that can be used to reproduce issues in the area below.
74 | Try the [Steps Recorder](https://support.microsoft.com/en-us/windows/record-steps-to-reproduce-a-problem-46582a9b-620f-2e36-00c9-04e25d784e47)
75 | on Windows or [Screenshot](https://support.apple.com/en-us/HT208721) on macOS.
76 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/Feature_Request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature Request / Idea 🚀
2 | description: Suggest a new feature or improvement (this does not mean you have to implement it)
3 | labels:
4 | - Issue-Enhancement
5 | - Needs-Triage
6 | body:
7 | - type: textarea
8 | attributes:
9 | label: Summary of the new feature / enhancement
10 | description: >
11 | A clear and concise description of what the problem is that the
12 | new feature would solve. Try formulating it in user story style
13 | (if applicable).
14 | placeholder: "'As a user I want X so that Y...' with X being the being the action and Y being the value of the action."
15 | validations:
16 | required: true
17 | - type: textarea
18 | attributes:
19 | label: Proposed technical implementation details (optional)
20 | placeholder: >
21 | A clear and concise description of what you want to happen.
22 | Consider providing an example experience with expected result.
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: PowerShell Issues
4 | url: https://github.com/PowerShell/PowerShell/issues/new
5 | about: PowerShell issues or suggestions.
6 | - name: Windows PowerShell Issues
7 | url: https://support.microsoft.com/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332
8 | about: Windows PowerShell issues or suggestions.
9 | - name: Support
10 | url: https://github.com/PowerShell/PowerShell/blob/master/.github/SUPPORT.md
11 | about: PowerShell Support Questions/Help
12 | - name: Documentation Issue
13 | url: https://github.com/MicrosoftDocs/PowerShell-Docs-Modules/issues/new/choose
14 | about: Please open issues on documentation for SecretManagement here.
15 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin) and [PowerShell](https://github.com/PowerShell).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.github/workflows/ci-test.yml:
--------------------------------------------------------------------------------
1 | name: CI Tests
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 | merge_group:
9 | types: [ checks_requested ]
10 |
11 | jobs:
12 | ci:
13 | name: pester
14 | strategy:
15 | matrix:
16 | os: [ windows-latest, macos-latest, ubuntu-latest ]
17 | runs-on: ${{ matrix.os }}
18 | env:
19 | DOTNET_NOLOGO: true
20 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@v4
24 |
25 | - name: Install dotnet
26 | uses: actions/setup-dotnet@v4
27 | with:
28 | cache: true
29 | cache-dependency-path: '**/*.csproj'
30 | dotnet-version: 8.x
31 |
32 | - name: Install PSResources
33 | run: ./tools/installPSResources.ps1
34 | shell: pwsh
35 |
36 | - name: Build and test
37 | run: Invoke-Build -Configuration Release -Task Build, Package, Test
38 | shell: pwsh
39 |
40 | - name: Test Windows PowerShell
41 | run: |
42 | Install-Module Pester -Scope CurrentUser -Force -SkipPublisherCheck
43 | Invoke-Pester Test
44 | if: matrix.os == 'windows-latest'
45 | shell: powershell
46 |
47 | - name: Upload build artifacts
48 | uses: actions/upload-artifact@v4
49 | if: always()
50 | with:
51 | name: SecretManagement-package-${{ matrix.os }}
52 | path: out/**/*.nupkg
53 |
54 | - name: Upload test results
55 | uses: actions/upload-artifact@v4
56 | if: always()
57 | with:
58 | name: SecretManagement-tests-${{ matrix.os }}
59 | path: testResults.xml
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | artifacts/
2 | module/
3 | bin/
4 | obj/
5 | out/
6 | testResults.xml
7 |
--------------------------------------------------------------------------------
/.pipelines/SecretManagement-Official.yml:
--------------------------------------------------------------------------------
1 | #################################################################################
2 | # OneBranch Pipelines #
3 | # This pipeline was created by EasyStart from a sample located at: #
4 | # https://aka.ms/obpipelines/easystart/samples #
5 | # Documentation: https://aka.ms/obpipelines #
6 | # Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
7 | # Retail Tasks: https://aka.ms/obpipelines/tasks #
8 | # Support: https://aka.ms/onebranchsup #
9 | #################################################################################
10 |
11 | trigger:
12 | - main
13 |
14 | schedules:
15 | - cron: '40 18 * * 2'
16 | displayName: Weekly CodeQL
17 | branches:
18 | include:
19 | - main
20 | always: true
21 |
22 | parameters:
23 | - name: debug
24 | displayName: Enable debug output
25 | type: boolean
26 | default: false
27 |
28 | variables:
29 | - name: system.debug
30 | value: ${{ parameters.debug }}
31 | - name: BuildConfiguration
32 | value: Release
33 | - name: WindowsContainerImage
34 | value: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest
35 | - name: DOTNET_NOLOGO
36 | value: true
37 | - name: DOTNET_GENERATE_ASPNET_CERTIFICATE
38 | value: false
39 | - group: SecretManagementAcr
40 |
41 | resources:
42 | repositories:
43 | - repository: templates
44 | type: git
45 | name: OneBranch.Pipelines/GovernedTemplates
46 | ref: refs/heads/main
47 |
48 | extends:
49 | # https://aka.ms/obpipelines/templates
50 | template: v2/OneBranch.Official.CrossPlat.yml@templates
51 | parameters:
52 | globalSdl: # https://aka.ms/obpipelines/sdl
53 | asyncSdl:
54 | enabled: true
55 | forStages: [build]
56 | featureFlags:
57 | EnableCDPxPAT: false
58 | WindowsHostVersion:
59 | Version: 2022
60 | Network: KS3
61 | stages:
62 | - stage: build
63 | jobs:
64 | - job: main
65 | displayName: Build package
66 | pool:
67 | type: windows
68 | variables:
69 | ob_outputDirectory: $(Build.SourcesDirectory)/out
70 | steps:
71 | - pwsh: |
72 | [xml]$xml = Get-Content Directory.Build.props
73 | $version = $xml.Project.PropertyGroup.ModuleVersion
74 | Write-Output "##vso[task.setvariable variable=version;isOutput=true]$version"
75 | name: package
76 | displayName: Get version from project properties
77 | - task: onebranch.pipeline.version@1
78 | displayName: Set OneBranch version
79 | inputs:
80 | system: Custom
81 | customVersion: $(package.version)
82 | - task: UseDotNet@2
83 | displayName: Use .NET SDK
84 | inputs:
85 | packageType: sdk
86 | useGlobalJson: true
87 | - pwsh: ./tools/installPSResources.ps1 -PSRepository CFS
88 | displayName: Install PSResources
89 | - pwsh: Invoke-Build -Configuration $(BuildConfiguration) -Task Build, Test
90 | displayName: Build
91 | - task: onebranch.pipeline.signing@1
92 | displayName: Sign 1st-party files in module
93 | inputs:
94 | command: sign
95 | signing_profile: external_distribution
96 | search_root: $(Build.SourcesDirectory)/module
97 | files_to_sign: |
98 | Microsoft.*.dll;
99 | Microsoft.*.psd1;
100 | Microsoft.*.ps1xml;
101 | - task: onebranch.pipeline.signing@1
102 | displayName: Sign 1st-party files in library
103 | inputs:
104 | command: sign
105 | signing_profile: external_distribution
106 | search_root: $(Build.SourcesDirectory)/artifacts
107 | files_to_sign: |
108 | publish/**/Microsoft.PowerShell.SecretManagement.dll;
109 | refs/**/Microsoft.PowerShell.SecretManagement.dll;
110 | - task: ArchiveFiles@2
111 | displayName: Zip module
112 | inputs:
113 | rootFolderOrFile: $(Build.SourcesDirectory)/module
114 | includeRootFolder: false
115 | archiveType: zip
116 | archiveFile: out/SecretManagement-v$(package.version).zip
117 | - pwsh: Invoke-Build -Configuration $(BuildConfiguration) Package
118 | displayName: Package module
119 | - task: onebranch.pipeline.signing@1
120 | displayName: Sign NuGet package
121 | inputs:
122 | command: sign
123 | signing_profile: external_distribution
124 | search_root: $(Build.SourcesDirectory)/out
125 | files_to_sign: |
126 | *.nupkg
127 | - stage: release
128 | dependsOn: build
129 | condition: eq(variables['Build.Reason'], 'Manual')
130 | variables:
131 | version: $[ stageDependencies.build.main.outputs['package.version'] ]
132 | drop: $(Pipeline.Workspace)/drop_build_main
133 | jobs:
134 | - job: github
135 | displayName: Publish draft to GitHub
136 | pool:
137 | type: windows
138 | variables:
139 | ob_outputDirectory: $(Build.SourcesDirectory)/out
140 | steps:
141 | - download: current
142 | displayName: Download artifacts
143 | - task: GitHubRelease@1
144 | displayName: Create GitHub release
145 | inputs:
146 | gitHubConnection: GitHub
147 | repositoryName: PowerShell/SecretManagement
148 | assets: |
149 | $(drop)/Microsoft.PowerShell.SecretManagement.$(version).nupkg
150 | $(drop)/Microsoft.PowerShell.SecretManagement.Library.$(version).nupkg
151 | $(drop)/SecretManagement-v$(version).zip
152 | tagSource: userSpecifiedTag
153 | tag: v$(version)
154 | isDraft: true
155 | addChangeLog: false
156 | releaseNotesSource: inline
157 | releaseNotesInline: ""
158 | - job: validation
159 | displayName: Manual validation
160 | pool:
161 | type: agentless
162 | timeoutInMinutes: 1440
163 | steps:
164 | - task: ManualValidation@0
165 | displayName: Wait 24 hours for validation
166 | inputs:
167 | notifyUsers: $(Build.RequestedForEmail)
168 | instructions: Please validate the release and then publish it!
169 | timeoutInMinutes: 1440
170 | - job: publish
171 | dependsOn: validation
172 | displayName: Publish to PowerShell Gallery
173 | pool:
174 | type: windows
175 | variables:
176 | ob_outputDirectory: $(Build.SourcesDirectory)/out
177 | steps:
178 | - download: current
179 | displayName: Download artifacts
180 | - task: NuGetCommand@2
181 | displayName: Publish module to PowerShell Gallery
182 | inputs:
183 | command: push
184 | packagesToPush: $(drop)/Microsoft.PowerShell.SecretManagement.$(version).nupkg
185 | nuGetFeedType: external
186 | publishFeedCredentials: PowerShellGallery
187 | - task: NuGetCommand@2
188 | displayName: Publish library to NuGet
189 | inputs:
190 | command: push
191 | packagesToPush: $(drop)/Microsoft.PowerShell.SecretManagement.Library.$(version).nupkg
192 | nuGetFeedType: external
193 | publishFeedCredentials: PowerShellNuGetOrgPush
194 | - stage: PrepForEv2
195 | condition: eq(variables['Build.Reason'], 'Manual')
196 | dependsOn: build
197 | variables:
198 | drop: $(Pipeline.Workspace)/drop_build_main
199 | version: $[ stageDependencies.build.main.outputs['package.version'] ]
200 | jobs:
201 | - job: CopyEv2FilesToArtifact
202 | displayName: Copy Ev2 Files To Artifact
203 | variables:
204 | - name: ob_outputDirectory
205 | value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT'
206 | pool:
207 | timeoutInMinutes: 30
208 | type: windows
209 | steps:
210 | - task: onebranch.pipeline.signing@1
211 | displayName: Sign 1st Party Files
212 | inputs:
213 | command: 'sign'
214 | signing_profile: external_distribution
215 | files_to_sign: '**\*.ps1'
216 | search_root: '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell'
217 | - download: current
218 | displayName: Download artifacts
219 | - task: CopyFiles@2
220 | inputs:
221 | SourceFolder: $(drop)
222 | Contents: Microsoft.PowerShell.SecretManagement.$(version).nupkg
223 | TargetFolder: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/SrcFiles/
224 | - task: ArchiveFiles@2
225 | inputs:
226 | rootFolderOrFile: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell/Run
227 | includeRootFolder: false
228 | archiveType: tar
229 | tarCompression: none
230 | archiveFile: $(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/Shell/Run.tar
231 | displayName: Compress Run script into tar file as needed for EV2 Shell extension
232 | - pwsh: |
233 | $pathToJsonFile = '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json'
234 | $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json
235 |
236 | $environmentVariables = @()
237 |
238 | $environmentVariables += [PSCustomObject]@{name="DESTINATION_ACR_NAME"; value='$(acr_name)'}
239 | $environmentVariables += [PSCustomObject]@{name="DESTINATION_ACR_URI"; value='$(acr_uri)'}
240 | $environmentVariables += [PSCustomObject]@{name="MI_NAME"; value='$(managed_identity_name)'}
241 | $environmentVariables += [PSCustomObject]@{name="MI_CLIENTID"; value='$(managed_identity_clientid)'}
242 | $environmentVariables += [PSCustomObject]@{name="SECRET_MANAGEMENT_VERSION"; value='$(version)'}
243 | $environmentVariables += [PSCustomObject]@{name="SECRET_MANAGEMENT_MODULE"; reference=[PSCustomObject]@{path="SrcFiles\\Microsoft.PowerShell.SecretManagement.$(version).nupkg"}}
244 |
245 | $content.shellExtensions.launch.environmentVariables = $environmentVariables
246 |
247 | $identityString = "/subscriptions/$(acr_subscription)/resourcegroups/$(acr_resource_group)/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$(managed_identity_name)"
248 | $content.shellExtensions.launch.identity.userAssignedIdentities[0] = $identityString
249 |
250 | Remove-Item -Path $pathToJsonFile
251 | $content | ConvertTo-Json -Depth 6 | Out-File $pathToJsonFile
252 | displayName: 'Replace values in SecretManagementToACR.Rollout.json file'
253 | - pwsh: |
254 | $pathToJsonFile = Join-Path -Path '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot' -ChildPath 'RolloutSpec.json'
255 | $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json
256 | $content.RolloutMetadata.Notification.Email.To = '$(email_address)'
257 |
258 | Remove-Item -Path $pathToJsonFile
259 | $content | ConvertTo-Json -Depth 4 | Out-File $pathToJsonFile
260 |
261 | displayName: 'Replace values in RolloutSpecPath.json'
262 | - pwsh: |
263 | $pathToJsonFile = Join-Path -Path '$(Build.SourcesDirectory)/EV2Specs/ServiceGroupRoot' -ChildPath 'ServiceModel.json'
264 | $content = Get-Content -Path $pathToJsonFile | ConvertFrom-Json
265 | $content.ServiceResourceGroups[0].AzureResourceGroupName = '$(acr_resource_group)'
266 | $content.ServiceResourceGroups[0].AzureSubscriptionId = '$(acr_subscription)'
267 |
268 | Remove-Item -Path $pathToJsonFile
269 | $content | ConvertTo-Json -Depth 9 | Out-File $pathToJsonFile
270 |
271 | displayName: 'Replace values in ServiceModel.json'
272 | - task: CopyFiles@2
273 | inputs:
274 | Contents: 'EV2Specs/**'
275 | TargetFolder: $(ob_outputDirectory)
276 | - stage: 'Prod_release'
277 | displayName: Deploy Images to ACR with EV2
278 | dependsOn:
279 | - PrepForEV2
280 | variables:
281 | - name: ob_release_environment
282 | value: "Production"
283 | - name: repoRoot
284 | value: $(Build.SourcesDirectory)
285 | jobs:
286 | - job: Prod_ReleaseJob
287 | pool:
288 | type: release
289 | steps:
290 | - download: current
291 | displayName: Download artifacts
292 | - task: vsrm-ev2.vss-services-ev2.adm-release-task.ExpressV2Internal@1
293 | displayName: 'Ev2: Push to ACR'
294 | inputs:
295 | UseServerMonitorTask: true
296 | EndpointProviderType: ApprovalService
297 | ApprovalServiceEnvironment: Production
298 | ServiceRootPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEv2FilesToArtifact/EV2Specs/ServiceGroupRoot'
299 | RolloutSpecPath: '$(Pipeline.Workspace)/drop_PrepForEV2_CopyEv2FilesToArtifact/EV2Specs/ServiceGroupRoot/RolloutSpec.json'
300 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | ## 1.1.2 - 2022-01-27
4 |
5 | ### Fixes
6 |
7 | - Fix for type initialization error on WindowsPowerShell (Issue #89)
8 |
9 | ### Changes
10 |
11 | ### New Features
12 |
13 | ## 1.1.1 - 2021-10-8
14 |
15 | ### Fixes
16 |
17 | - Fix for disabled user interaction after tab completion (Issue #174)
18 |
19 | ### Changes
20 |
21 | ### New Features
22 |
23 | ## 1.1.0 - 2021-6-1
24 |
25 | ### Fixes
26 |
27 | - Extension vault data streams (Warning, Verbose, etc.) now honor cmdlet stream direction commands (Issue #151)
28 |
29 | ### Changes
30 |
31 | ### New Features
32 |
33 | ## 1.1.0-preview - 2021-5-24
34 |
35 | ### Fixes
36 |
37 | - Provide better error message when extension vault does not provide required functions (Issue #137)
38 |
39 | - Provide better error message when running under Windows built-in accounts (Issue #143)
40 |
41 | - SecretManagement now runs in ConstrainedLanguage mode (Issue #144)
42 |
43 | ### Changes
44 |
45 | - Set-SecretInfo now takes pipeline input (Issue #129).
46 |
47 | - Extension vaults are now loaded and run in a separate PowerShell runspace session (Issue #144)
48 |
49 | - Extension vaults can now optionally support a `Unlock-SecretVault` function (Issue #147)
50 |
51 | ### New Features
52 |
53 | - `Unlock-SecretVault` command added to SecretManagement (Issue #147)
54 |
55 | ## 1.0.0 - 2021-4-5
56 |
57 | ### Fixes
58 |
59 | - Fix manifest license link (Issue #112)
60 |
61 | - Fix help document md to xml file compilation (Issue #90, #106)
62 |
63 | - Remove unnecessary assert in registry write code (Issue #119)
64 |
65 | ### Changes
66 |
67 | - Add constructor for `SecretInformation` class that accepts metadata as a hash table (Issue #108)
68 |
69 | ### New Features
70 |
71 | ## 0.9.1 - 2021-3-1
72 |
73 | ### Fixes
74 |
75 | - `Get-Secret` and `Remove-Secret` cmdlets now honor the `VaultName` parameter from a piped in `SecretInformation` object (Issue #97)
76 |
77 | - Secret name and vault name autocompletion now correctly handles names with spaces (Issue #91)
78 |
79 | ### Changes
80 |
81 | - A warning is now displayed when secret cmdlets are used and no vaults are currently registered
82 |
83 | ### New Features
84 |
85 | - `SecretInformation` class now has a new `Metadata` property to support the new secret metadata support (Issue #46)
86 |
87 | - `Set-Secret` cmdlet now has a new optional `-Metadata` property to include additional non-sensitive data associated with a secret (Issue #46)
88 |
89 | - New `Set-SecretInfo` cmdlet that takes a `-Metadata` property which sets additional non-sensitive data to a secret (Issue #46)
90 |
91 | ## 0.9.0 - 2021-1-15
92 |
93 | ### Fixes
94 |
95 | - `Register-SecretVault` no longer emits error when strict language mode is set (Issue #81)
96 |
97 | ### Changes
98 |
99 | - `Set-DefaultVault` cmdlet has been renamed to `Set-SecretVaultDefault` (Issue #79)
100 |
101 | - ReadME.md document now includes installation information (Issue #86)
102 |
103 | ### New Features
104 |
105 | ## 0.5.5-Preview5 - 2020-11-16
106 |
107 | ### Fixes
108 |
109 | - Incompatibility with WindowsPowerShell 5.1 (Issue #73)
110 |
111 | ### Changes
112 |
113 | - The first extension vault added will automatically be designated the default vault (Issue #61)
114 |
115 | - `Unregister-SecretVault` `-Name` property now supports string[] type and wild cards (Issue #57,#58)
116 |
117 | - `Register-SecretVault` now checks `-VaultParameters` hashtable for reserved `Verbose` entry and throws error if found
118 |
119 | - `Set-DefaultVault` now has a `-ClearDefault` parameter that designates no registered vault as the default vault
120 |
121 | ### New Features
122 |
123 | - `Register-SecretVault` now supports a `-Description` parameter and registration information will include an optional extension vault description (Issue #46)
124 |
125 | ## 0.5.4-Preview5 - 2020-11-4
126 |
127 | ### Fixes
128 |
129 | ### Changes
130 |
131 | - `Get-Secret` `-Name` parameter now accepts arguments with wild card characters as literals (Issue #67)
132 |
133 | - The `Verbose` parameter switch is now passed to extension vault module functions as an `AdditionalParameters` name/value pair (Issue #66)
134 |
135 | - `Get-SecretVault` `-Name` parameter now takes a `string[]` type argument (Issue #59)
136 |
137 | - `Test-SecretVault` `-Name` parameter now takes a `string[]` type argument and accepts wild card characters (Issue #56)
138 |
139 | - `Register-SecretVault` now has a `-PassThru` parameter to return information on the secret vault just registered
140 |
141 | ### New Features
142 |
143 | - When an extension vault is unregistered and if the vault provides a `Unregister-SecretVault` function, that extension vault function will be called before the extension vault is unregistered (Issue #60)
144 |
145 | - Vault name and Secret name completers have been added to the cmdlets (Issue #35)
146 |
147 | ## 0.5.3-Preview4 - 2020-09-24
148 |
149 | ### Fixes
150 |
151 | - Windows PowerShell cannot register extension vaults (Error: Cannot bind argument to parameter 'Path' ...)
152 |
153 | ### Changes
154 |
155 | - Change SecretVaultInfo `VaultName` property to `Name`, for consistency
156 |
157 | - `Test-SecretVault` `-Vault` parameter changed to `-Name` for consistency
158 |
159 | ### New Features
160 |
161 | - Add `-AllowClobber` parameter switch to `Register-SecretVault`, to allow overwriting existing vault
162 |
163 | - `Register-SecretVault` `-Name` parameter is now optional, and will use module name if not provided
164 |
165 | - `Unregister-SecretVault` now supports `Name` parameter argument from pipeline
166 |
167 | - `Set-DefaultVault` now supports `Name` and `SecretVaultVaultInfo` parameter arguments from pipeline
168 |
169 | - `Set-Secret` now supports `SecretInfo` objects from the pipeline
170 |
171 | - Add `WhatIf` support to `Secret-Secret`
172 |
173 | - Add `WhatIf` support to `Remove-Secret`
174 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | 1.1.2
6 | true
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Docs/ARCHITECTURE.md:
--------------------------------------------------------------------------------
1 | # PowerShell SecretManagement Module Architecture
2 |
3 | ## Description
4 |
5 | The purpose of the SecretManagement module is to provide secure storage and access of secrets, through registered extension vaults.
6 | The registered extension vaults are PowerShell modules that conform to SecretManagement module requirements.
7 | The extension vaults perform the actual work of authentication, and securely storing and retrieving secrets.
8 | An extension vault can store secrets locally or remotely for a cloud based store.
9 | Extension vault registration registers vaults for the current user context.
10 | So, the SecretManagement module is essentially an orchestrator of extension vaults.
11 |
12 | The SecretManagement module provides commands for registering vault extensions, and accessing vault secrets.
13 | This greatly reduces the temptation to hard code secrets directly into production source code, and instead use the SecretManagement module to dynamically retrieve secrets at runtime.
14 |
15 | ### Using SecretManagement
16 |
17 | ```powershell
18 | Import-Module Microsoft.PowerShell.SecretManagement
19 |
20 | # See what extension vaults are registered for current user
21 | Get-SecretVault
22 |
23 | VaultName ModuleName IsDefaultVault
24 | --------- ---------- --------------
25 | CredMan Microsoft.PowerShell.CredManStore False
26 | LocalStore Microsoft.PowerShell.SecretStore True
27 |
28 | # Publish a module to the PowerShell Gallery, using a key from the SecretManagement default extension vault
29 | Publish-Module -Path C:\Modules\Publish\MyNewModule -NuGetApiKey (Get-Secret NuGetApiKey -AsPlainText)
30 |
31 | # Run management script on multiple machines, using stored credentials from the default extension vault
32 | Invoke-Command -Cn $machines -FilePath .\MyMgmtScript.ps1 -Credential (Get-Secret MgmtCred)
33 | ```
34 |
35 | The design is based on the [SecretManagement RFC](https://github.com/PowerShell/PowerShell-RFC/pull/208).
36 |
37 | ## Supported secret types
38 |
39 | Secret objects supported by this module are currently limited to:
40 |
41 | - byte[] - Blob secret
42 |
43 | - string - String secret
44 |
45 | - SecureString - Secure string secret
46 |
47 | - PSCredential - PowerShell credential secret
48 |
49 | - Hashtable - Hash table of name value pairs, where values are restricted to the above secret types.
50 |
51 | ## Secret metadata
52 |
53 | Extension vaults can optionally support storing and retrieving additional secret metadata, that is data associated with the secret.
54 | Secret metadata is not security sensitive and does not need to be stored securely in the extension vault.
55 |
56 | Secret metadata can be included by using the `-Metadata` parameter: `Set-Secret -Metadata @{ Name=Value }`.
57 | The `-Metadata` parameter takes a `Hashtable` type argument consisting of name/value pairs.
58 | Extension vaults should at minimum support the following value types:
59 |
60 | - string
61 |
62 | - int
63 |
64 | - DateTime
65 |
66 | The secret metadata is included in the `SecretInformation` type object returned by `Get-SecretInfo`, in a `Metadata` property.
67 | The `Metadata` property is a `ReadonlyDictionary` type.
68 |
69 | ## Vault extension hosting
70 |
71 | Extension vault modules are hosted in a separate PowerShell runspace session that is separate from the current user PowerShell session.
72 | This provides a layer of isolation between the user and extension vault operations.
73 | But it also means that extension vaults cannot depend on any shared state with the user session, such as variables or loaded modules.
74 | An extension vault must ensure all module dependencies are listed in its manifest, and any required information is passed in explicitly to the module.
75 |
76 | There is one shared component between the extension vault session and the current user session, and that is the PowerShell host (PSHost).
77 | The PSHost is the object used by PowerShell to communicate with a user in an interactive session.
78 | When the extension vault runspace session is created, the current user session PSHost object is transferred to the vault session.
79 | This provides extension vaults with the ability to write error, warning, verbose, etc. information to the host for the user, including directly prompting the user interactively (for example prompting the user for a password).
80 |
81 | Vault extension modules were originally hosted in the same session as the user session.
82 | However, this prevented SecretManagement from running in a constrained language mode session.
83 | Consequently, starting with v1.1, the extension vaults are hosted in a separate runspace process.
84 |
85 | ## Vault extension registration
86 |
87 | Extension vaults are registered to the current user context.
88 | Information about the extension vault is collected via a registration cmdlet and information is stored as a json file in a user context based location.
89 |
90 | Example:
91 |
92 | ``` json
93 | {
94 | "Vaults": {
95 | "CredMan": {
96 | "VaultParameters": {},
97 | "ModulePath": "C:\\Modules\\Microsoft.PowerShell.CredManStore",
98 | "ModuleName": "Microsoft.PowerShell.CredManStore"
99 | },
100 | "LocalStore": {
101 | "VaultParameters": {
102 | "DefaultLocation": "None"
103 | },
104 | "ModulePath": "C:\\Modules\\Microsoft.PowerShell.SecretStore",
105 | "ModuleName": "Microsoft.PowerShell.SecretStore"
106 | }
107 | },
108 | "DefaultVaultName": "LocalStore"
109 | }
110 | ```
111 |
112 | Validation checks are performed on each module before being registered.
113 |
114 | ## Extension vaults
115 |
116 | Vault extensions are PowerShell modules that provide five required functions, and one optional function
117 |
118 | ### Extension vault module required functions
119 |
120 | #### Set-Secret
121 |
122 | Adds a secret to the vault
123 |
124 | #### Set-SecretInfo
125 |
126 | Adds or replaces additional secret metadata to an existing secret in the vault.
127 | Metadata is not stored securely.
128 |
129 | #### Get-Secret
130 |
131 | Retrieves a secret from the vault
132 |
133 | #### Remove-Secret
134 |
135 | Removes a secret from the vault
136 |
137 | #### Get-SecretInfo
138 |
139 | Returns information about one or more secrets (but not the secret itself)
140 |
141 | #### Test-SecretVault
142 |
143 | Tests that extension vault functions and returns True or diagnostic errors
144 |
145 | #### Unregister-SecretVault
146 |
147 | This function is called if provided by the extension vault, to allow the extension vault to perform an clean up tasks before the vault extension is unregistered
148 |
149 | ### Unlock-SecretVault
150 |
151 | Unlocks the extension vault through a passed in SecureString password
152 |
153 | #### Verbose and AdditionalParameters
154 |
155 | Each extension vault function takes a set of parameter arguments that includes an `AdditionalParameters` hash table.
156 | The values of the hash table come from the `VaultParameters` field of the registered vault, which are additional parameters an extension vault implementation might need beyond the specific parameters of a particular function.
157 | The `AdditionalParameters` hash table can also include an automatic `Verbose` boolean parameter.
158 | If the extension vault function is being called with the `-Verbose` common parameter, then the `Verbose` boolean parameter will be included in the `AdditionalParameters` hash table.
159 | The `Verbose` parameter is reserved and provided automatically by SecretManagement when verbose output is specified.
160 | It cannot be included in `VaultParameters`.
161 |
162 | Example:
163 |
164 | ```powershell
165 | function Get-Secret
166 | {
167 | [CmdletBinding()]
168 | param (
169 | [string] $Name,
170 | [string] $VaultName,
171 | [hashtable] $AdditionalParameters
172 | )
173 |
174 | # Enable verbose output if directed
175 | if ($AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)) {
176 | $VerbosePreference = 'Continue'
177 | }
178 |
179 | ...
180 | }
181 | ```
182 |
183 | ### Script module vault extension example
184 |
185 | This is a minimal vault extension example to demonstrate the directory structure and functional requirements of an extension vault module.
186 | The extension vault module name is 'TestVault'.
187 |
188 | #### Module directory structure
189 |
190 | ./TestVault
191 | ./TestVault/TestVault.psd1
192 | ./TestVault/TestStoreImplementation.dll
193 | ./TestVault/TestVault.Extension
194 | ./TestVault/TestVault.Extension/TestVault.Extension.psd1
195 | ./TestVault/TestVault.Extension/TestVault.Extension.psm1
196 |
197 | #### TestVault.psd1 file
198 |
199 | ```powershell
200 | @{
201 | ModuleVersion = '1.0'
202 | RootModule = '.\TestStoreImplementation.dll'
203 | NestedModules = @('.\TestVault.Extension')
204 | CmdletsToExport = @('Set-TestStoreConfiguration','Get-TestStoreConfiguration')
205 | }
206 | ```
207 |
208 | The TestVault extension module has a binary component (TestStoreImplementation.dll) which implements the vault. It publicly exports two cmdlets that are used to configure the store.
209 | It also declares the required nested module (TestVault.Extension) that exports the five functions required by SecretManagement registration.
210 |
211 | Note that the nested module conforms to the required naming format:
212 | '[ModuleName].Extension'
213 |
214 | Note that only the 'NestedModules' entry is required because it loads 'TestVault.Extension' into the module scope, and allows SecretManagement access to the required five functions.
215 | The 'RootModule' and 'CmdletsToExport' entries are only for configuring the TestStore in this specific case, and are not needed in general.
216 |
217 | #### TestVault.Extension.psd1 file
218 |
219 | ```powershell
220 | @{
221 | ModuleVersion = '1.0'
222 | RootModule = '.\TestVault.Extension.psm1'
223 | RequiredAssemblies = '..\TestStoreImplementation.dll'
224 | FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
225 | }
226 | ```
227 |
228 | This nested module implements and exports the five functions required by SecretManagement.
229 | It also specifies the TestStoreImplementation.dll binary as a 'RequiredAssemblies' because the five exported functions depend on it.
230 |
231 | #### TestVault.Extension.psm1 file
232 |
233 | ```powershell
234 | function Get-Secret
235 | {
236 | [CmdletBinding()]
237 | param (
238 | [string] $Name,
239 | [string] $VaultName,
240 | [hashtable] $AdditionalParameters
241 | )
242 |
243 | return [TestStore]::GetItem($Name, $AdditionalParameters)
244 | }
245 |
246 | function Get-SecretInfo
247 | {
248 | [CmdletBinding()]
249 | param (
250 | [string] $Filter,
251 | [string] $VaultName,
252 | [hashtable] $AdditionalParameters
253 | )
254 |
255 | # return [TestStore]::GetItemInfo($Filter, $AdditionalParameters)
256 | return @(,[Microsoft.PowerShell.SecretManagement.SecretInformation]::new(
257 | "Name", # Name of secret
258 | "String", # Secret data type [Microsoft.PowerShell.SecretManagement.SecretType]
259 | $VaultName, # Name of vault
260 | $Metadata) # Optional ReadonlyDictionary secret metadata
261 | }
262 |
263 | function Set-Secret
264 | {
265 | [CmdletBinding()]
266 | param (
267 | [string] $Name,
268 | [object] $Secret,
269 | [string] $VaultName,
270 | [hashtable] $AdditionalParameters,
271 | [hashtable] $Metadata # Optional metadata parameter
272 | )
273 |
274 | [TestStore]::SetItem($Name, $Secret)
275 | }
276 |
277 | # Optional function
278 | function Set-SecretInfo
279 | {
280 | [CmdletBinding()]
281 | param (
282 | [string] $Name,
283 | [hashtable] $Metadata,
284 | [string] $VaultName,
285 | [hashtable] $AdditionalParameters
286 | )
287 |
288 | [TestStore]::SetItemMetadata($Name, $Metadata)
289 | }
290 |
291 | function Remove-Secret
292 | {
293 | [CmdletBinding()]
294 | param (
295 | [string] $Name,
296 | [string] $VaultName,
297 | [hashtable] $AdditionalParameters
298 | )
299 |
300 | [TestStore]::RemoveItem($Name)
301 | }
302 |
303 | function Test-SecretVault
304 | {
305 | [CmdletBinding()]
306 | param (
307 | [string] $VaultName,
308 | [hashtable] $AdditionalParameters
309 | )
310 |
311 | return [TestStore]::TestVault()
312 | }
313 |
314 | # Optional function
315 | function Unregister-SecretVault
316 | {
317 | [CmdletBinding()]
318 | param (
319 | [string] $VaultName,
320 | [hashtable] $AdditionalParameters
321 | )
322 |
323 | # Perform optional work to extension vault before it is unregistered
324 | [TestStore]::RunUnregisterCleanup()
325 | }
326 |
327 | # Optional function
328 | function Unlock-SecretVault
329 | {
330 | [CmdletBinding()]
331 | param (
332 | [SecureString] $Password,
333 | [string] $VaultName,
334 | [hashtable] $AdditionalParameters
335 | )
336 |
337 | [TestStore]::UnlockVault($Password)
338 | }
339 | ```
340 |
341 | This module script implements the five required functions, as cmdlets.
342 | It also implements an optional `Unregister-SecretVault` function that is called during vault extension un-registration.
343 | It also implements an optional function `Set-SecretInfo` function that sets secret metadata to a specific secret in the vault.
344 | It also implements an optional `Unlock-SecretVault` function that unlocks the vault for the current session based on a provided password.
345 |
346 | The `Set-Secret`, `Set-SecretInfo`, `Remove-Secret`, `Unregister-SecretVault` functions do not write any data to the pipeline, i.e., they do not return any data.
347 |
348 | The `Get-Secret` cmdlet writes the retrieved secret value to the output pipeline on return, or null if no secret was found.
349 | It should write an error only if an abnormal condition occurs.
350 |
351 | The `Get-SecretInfo` cmdlet writes an array of [Microsoft.PowerShell.SecretManagement.SecretInformation] type objects to the output pipeline or an empty array if no matches were found.
352 |
353 | The `Test-SecretVault` cmdlet should write all errors that occur during the test.
354 | But only a single true/false boolean should be written the the output pipeline indicating success.
355 |
356 | The `Unlock-SecretVault` cmdlet is optional and will be called on the extension vault if available.
357 | It's purpose is to unlock an extension vault for use without having to prompt the user, and is useful for unattended scripts where user interaction is not possible.
358 |
359 | In general, these cmdlets should write to the error stream only for abnormal conditions that prevent successful completion.
360 | And write to the output stream only the data as indicated above, and expected by SecretManagement.
361 |
362 | In addition, these cmdlets should perform proper authentication and provide errors, and instructions to authenticate, as appropriate.
363 | Or prompt the user if needed, for example if a passphrase is required.
364 |
365 | A vault extension doesn't need to provide full implementation of all required functions.
366 | For example, a vault extension does not need to provide a way to add or remove a secret through the SecretManagement cmdlets, and can just provide retrieval services.
367 | If a vault extension doesn't support some functionality, then it should write an appropriate error with a meaningful message.
368 |
369 | ## Vault registration cmdlets
370 |
371 | The following cmdlets are provided for vault extension registration.
372 |
373 | ```powershell
374 | Register-SecretVault
375 | Get-SecretVault
376 | Unregister-SecretVault
377 | Set-SecretVaultDefault
378 | Test-SecretVault
379 | ```
380 |
381 | ### Register-SecretVault
382 |
383 | Registers a PowerShell module as an extension vault for the current user context.
384 | Validation is performed to ensure the module provides the required functions.
385 |
386 | ### Get-SecretVault
387 |
388 | Returns a list of extension vaults currently registered in the user context.
389 |
390 | ### Unregister-SecretVault
391 |
392 | Un-registers an extension vault.
393 |
394 | ### Set-SecretVaultDefault
395 |
396 | Sets one registered extension vault as the default vault.
397 |
398 | ### Test-SecretVault
399 |
400 | Runs an extension vault 'Test-SecretVault' function and returns the test result.
401 |
402 | ### Unlock-SecretVault
403 |
404 | Unlocks the extension vault through a passed in SecureString password.
405 |
406 | ## Secrets cmdlets
407 |
408 | The following cmdlets are provided for manipulating secrets.
409 |
410 | ```powershell
411 | Set-Secret
412 | Get-Secret
413 | Get-SecretInfo
414 | Remove-Secret
415 | ```
416 |
417 | ### Set-Secret
418 |
419 | Adds a secret to a specified vault.
420 | Returns True or False to indicate success.
421 |
422 | ### Get-Secret
423 |
424 | Returns a single secret for a provided name.
425 |
426 | ### Get-SecretInfo
427 |
428 | Returns information about each secret stored in all registered vaults, but not the secret itself.
429 | The information is returned in a `Microsoft.PowerShell.SecretManagement.SecretInformation` type.
430 |
431 | ### Remove-Secret
432 |
433 | Removes a secret by name from a given vault.
434 | Returns True or False to indicate success.
435 |
436 | ## Security
437 |
438 | ### Extension vault security
439 |
440 | All extension vault module implementations are responsible for working securely.
441 | In addition each extension vault module is responsible for authentication within the current user context, and to provide appropriate informational and error messages to the user, including instructions for authenticating.
442 | Extension vaults are also responsible for prompting the user for a passphrase, if needed, in interactive sessions.
443 | If an extension vault supports optional secret metadata, the metadata is not sensitive information and does not need to be stored securely.
444 | If an extension vault requires a password before use, it can support the optional `Unlock-SecretVault` function to allow the vault to be unlocked from unattended script, without any user interaction.
445 |
446 | ### Intermediate secret objects
447 |
448 | The SecretManagement module makes a best effort to zero out any intermediate secret objects not returned to the user.
449 | For example byte arrays used in storing and retrieving SecureString blobs are zeroed out after use.
450 | But strings are immutable in C# and cannot be easily or reliably altered, and so must rely on the CLR garbage collection.
451 |
452 | ### Plain text secrets
453 |
454 | The SecretManagement module supports both `string` and `SecureString` secret data types.
455 | To avoid inadvertently exposing these secrets as plain text, either in a command shell or logs, these secret types are always returned by `Get-Secret` as `SecureString` objects by default.
456 | `Get-Secret` will return these data types as strings only if the `-AsPlainText` parameter switch is used.
457 |
458 | This behavior also extends to `hashtable` secret types.
459 | Since hashtable entries can include `string` and `SecureString` data types, these appear in the hashtable as `SecureString` unless `-AsPlainText` switch is used.
460 |
461 | On Windows platform, `SecureString` types contain an encrypted version of the text data, using Windows DPAPI, that is keyed to the current user context and local machine.
462 | But for all other platforms (Linux, macOS) this kind of default encryption is not possible so the dotNet `SecureString` type contains an unencrypted blob of the text.
463 | However, `SecureString` still serves a purpose on non-Windows platforms, since it will not expose the plain text directly, and another dotNet API is needed to return the string contents in plain text.
464 | So on non-Windows platforms `SecureString` still provides some security through obscurity (but not encryption).
465 |
466 | ### Extension vault module cross talk
467 |
468 | SecretManagement extension vault modules all run in a single PowerShell runspace session that is separate from the current user PowerShell session, although both sessions run within the same process.
469 | This means there is a layer of isolation between extension vault modules and the user session, but no significant isolation between each loaded extension vault.
470 | Since authentication is usually based on current session or user context, this means a malicious vault extension could harvest secrets from other registered vaults.
471 |
472 | This can easily be done by directly calling each registered vault secret management cmdlets.
473 |
474 | One possible mitigation is for an extension vault to require a passphrase.
475 | But usually the passphrase remains valid for a period of time (e.g., sudo), and the malicious extension vault can obtain secrets during that time.
476 |
477 | The best defense is to use known secure extension vaults from reputable sources, that are signed certified.
478 |
479 | ## Extension vault registry file location
480 |
481 | SecretManagement is designed to be installed and run within a user account on both Windows and non-Windows platforms.
482 | The extension vault registry file is located in a user account protected directory.
483 |
484 | For Windows platforms the location is:
485 | %LOCALAPPDATA%\Microsoft\PowerShell\secretmanagement
486 |
487 | For non-Windows platforms the location:
488 | $HOME/.secretmanagement
489 |
490 | ## Windows Managed Accounts
491 |
492 | SecretManagement does not currently work for Windows managed accounts.
493 |
494 | SecretManagement depends on both %LOCALAPPDATA% folders to store registry information, and Data Protection APIs for safely handling secrets with the .Net `SecureString` type.
495 | However, Windows managed accounts do not have profiles or %LOCALAPPDATA% folders, and Windows Data Protection APIs do not work for managed accounts.
496 | Consequently, SecretManagement will not run under managed accounts.
497 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/RolloutSpec.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutSpecification.json",
3 | "contentVersion": "1.0.0.0",
4 | "RolloutMetadata": {
5 | "ServiceModelPath": "ServiceModel.json",
6 | "ScopeBindingsPath": "ScopeBindings.json",
7 | "Name": "OneBranch-Demo-Container-Deployment",
8 | "RolloutType": "Major",
9 | "BuildSource": {
10 | "Parameters": {
11 | "VersionFile": "buildver.txt"
12 | }
13 | },
14 | "Notification": {
15 | "Email": {
16 | "To": "default"
17 | }
18 | }
19 | },
20 | "OrchestratedSteps": [
21 | {
22 | "Name": "UploadSecretManagementToACR",
23 | "TargetType": "ServiceResource",
24 | "TargetName": "SecretManagementToACR",
25 | "Actions": ["Shell/Run"]
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/ScopeBindings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/scopeBindings.json",
3 | "contentVersion": "0.0.0.1",
4 | "scopeBindings": [
5 | {
6 | "scopeTagName": "Global",
7 | "bindings": [
8 | {
9 | "find": "__SUBSCRIPTION_ID__",
10 | "replaceWith": "$azureSubscriptionId()"
11 | },
12 | {
13 | "find": "__RESOURCE_GROUP__",
14 | "replaceWith": "$azureResourceGroup()"
15 | },
16 | {
17 | "find": "__BUILD_VERSION__",
18 | "replaceWith": "$buildVersion()"
19 | }
20 | ]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/SecretManagementToACR.Rollout.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/rolloutParameters.json",
3 | "contentVersion": "1.0.0.0",
4 | "shellExtensions": [
5 | {
6 | "name": "Run",
7 | "type": "Run",
8 | "properties": {
9 | "maxExecutionTime": "PT2H"
10 | },
11 | "package": {
12 | "reference": {
13 | "path": "Shell/Run.tar"
14 | }
15 | },
16 | "launch": {
17 | "command": [
18 | "/bin/bash",
19 | "-c",
20 | "pwsh ./Run.ps1"
21 | ],
22 | "environmentVariables": [
23 | {
24 | "name": "SECRET_MANAGEMENT_MODULE",
25 | "reference":
26 | {
27 | "path": "SrcFiles\\Microsoft.PowerShell.SecretManagement.nupkg"
28 | }
29 | },
30 | {
31 | "name": "DESTINATION_ACR_NAME",
32 | "value": "default"
33 | },
34 | {
35 | "name": "MI_NAME",
36 | "value": "default"
37 | },
38 | {
39 | "name": "MI_CLIENTID",
40 | "value": "default"
41 | },
42 | {
43 | "name": "SECRET_MANAGEMENT_VERSION",
44 | "value": "default"
45 | },
46 | {
47 | "name": "DESTINATION_ACR_URI",
48 | "value": "default"
49 | }
50 | ],
51 | "identity": {
52 | "type": "userAssigned",
53 | "userAssignedIdentities": [
54 | "default"
55 | ]
56 | }
57 | }
58 | }
59 | ]
60 | }
61 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/ServiceModel.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ev2schema.azure.net/schemas/2020-01-01/serviceModel.json",
3 | "contentVersion": "1.0.0.0",
4 | "ServiceMetadata": {
5 | "ServiceGroup": "OneBranch-SecretManagement",
6 | "Environment": "Test"
7 | },
8 | "ServiceResourceGroupDefinitions": [
9 | {
10 | "Name": "OneBranch-SecretManagement-RGDef",
11 | "ServiceResourceDefinitions": [
12 | {
13 | "Name": "OneBranch-SecretManagement.Shell-SRDef",
14 | "composedOf": {
15 | "extension": {
16 | "shell": [
17 | {
18 | "type": "Run",
19 | "properties": {
20 | "imageName": "adm-mariner-20-l",
21 | "imageVersion": "v5"
22 | }
23 | }
24 | ]
25 | }
26 | }
27 | }
28 | ]
29 | }
30 | ],
31 | "ServiceResourceGroups": [
32 | {
33 | "AzureResourceGroupName": "default",
34 | "Location": "East US",
35 | "InstanceOf": "OneBranch-SecretManagement-RGDef",
36 | "AzureSubscriptionId": "default",
37 | "scopeTags": [
38 | {
39 | "name": "Global"
40 | }
41 | ],
42 | "ServiceResources": [
43 | {
44 | "Name": "SecretManagementToACR",
45 | "InstanceOf": "OneBranch-SecretManagement.Shell-SRDef",
46 | "RolloutParametersPath": "SecretManagementToACR.Rollout.json"
47 | }
48 | ]
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/Shell/Run/Run.ps1:
--------------------------------------------------------------------------------
1 | # ensure SAS variables were passed in
2 | if ($env:SECRET_MANAGEMENT_MODULE -eq $null)
3 | {
4 | Write-Verbose -Verbose "SECRET_MANAGEMENT_MODULE variable didn't get passed correctly"
5 | return 1
6 | }
7 |
8 | if ($env:SECRET_MANAGEMENT_VERSION -eq $null)
9 | {
10 | Write-Verbose -Verbose "SECRET_MANAGEMENT_VERSION variable didn't get passed correctly"
11 | return 1
12 | }
13 |
14 | if ($env:DESTINATION_ACR_NAME -eq $null)
15 | {
16 | Write-Verbose -Verbose "DESTINATION_ACR_NAME variable didn't get passed correctly"
17 | return 1
18 | }
19 |
20 | if ($env:DESTINATION_ACR_URI -eq $null)
21 | {
22 | Write-Verbose -Verbose "DESTINATION_ACR_URI variable didn't get passed correctly"
23 | return 1
24 | }
25 |
26 | if ($env:MI_CLIENTID -eq $null)
27 | {
28 | Write-Verbose -Verbose "MI_CLIENTID variable didn't get passed correctly"
29 | return 1
30 | }
31 |
32 |
33 | try {
34 | Write-Verbose -Verbose "SecretManagement: $env:SECRET_MANAGEMENT_MODULE"
35 | Write-Verbose -Verbose "Version: $env:SECRET_MANAGEMENT_VERSION"
36 | Write-Verbose -Verbose "acrname: $env:DESTINATION_ACR_NAME"
37 | Write-Verbose -Verbose "acruri: $env:DESTINATION_ACR_URI"
38 | Write-Verbose -Verbose "MI client Id: $env:MI_CLIENTID"
39 |
40 | $secretManagementFileName = "Microsoft.PowerShell.SecretManagement.$($env:SECRET_MANAGEMENT_VERSION).nupkg"
41 |
42 | Write-Verbose -Verbose "Download files"
43 | Invoke-WebRequest -Uri $env:SECRET_MANAGEMENT_MODULE -OutFile $secretManagementFileName
44 |
45 | $moduleExists = Test-Path $secretManagementFileName
46 | Write-Verbose -Verbose "Module $secretManagementFileName exists: $moduleExists"
47 |
48 | # Install PSResourceGet 1.1.1
49 | Write-Verbose "Download PSResourceGet version 1.1.1"
50 | Register-PSRepository -Name CFS -SourceLocation "https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/powershell/nuget/v2" -InstallationPolicy Trusted
51 | Install-Module -Repository CFS -Name Microsoft.PowerShell.PSResourceGet -RequiredVersion '1.1.1' -Verbose
52 | Import-Module Microsoft.PowerShell.PSResourceGet
53 | Get-Module
54 |
55 | # Login to Azure CLI using Managed Identity
56 | Write-Verbose -Verbose "Login cli using managed identity"
57 | az login --identity --username $env:MI_CLIENTID
58 |
59 | # Register the target ACR as a PSResourceGet repository
60 | Write-Verbose -Verbose "Register ARC as a PSResourceGet reposirory"
61 | Register-PSResourceRepository -Uri $env:DESTINATION_ACR_URI -Name $env:DESTINATION_ACR_NAME -Trusted -Verbose
62 |
63 | Get-PSResourceRepository
64 |
65 | #Publish SecretManagement to ACR
66 | Write-Verbose -Verbose "Publish SecretManagement $secretManagementFileName to ACR $env:DESTINATION_ACR_NAME"
67 |
68 | # public
69 | $prefix = "public/psresource"
70 | Publish-PSResource -Repository $env:DESTINATION_ACR_NAME -NupkgPath $secretManagementFileName -ModulePrefix $prefix -Confirm:$false
71 |
72 | # unlisted
73 | $prefix = "unlisted/psresource"
74 | Publish-PSResource -Repository $env:DESTINATION_ACR_NAME -NupkgPath $secretManagementFileName -ModulePrefix $prefix -Confirm:$false
75 | }
76 | catch {
77 |
78 | $_.Exception | Format-List -Force
79 |
80 | return 1
81 | }
82 |
83 | return 0
84 |
--------------------------------------------------------------------------------
/Ev2Specs/ServiceGroupRoot/buildver.txt:
--------------------------------------------------------------------------------
1 | 2.0.0
--------------------------------------------------------------------------------
/ExtensionModules/AKVaultScript/AKVaultScript.Extension/AKVaultScript.Extension.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | ModuleVersion = '1.0'
3 | RootModule = '.\AKVaultScript.Extension.psm1'
4 | FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
5 | }
6 |
--------------------------------------------------------------------------------
/ExtensionModules/AKVaultScript/AKVaultScript.Extension/AKVaultScript.Extension.psm1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT License.
3 |
4 | function Check-SubscriptionLogIn
5 | {
6 | param (
7 | [string] $SubscriptionId,
8 | [string] $AzKVaultName
9 | )
10 |
11 | Import-Module -Name Az.Accounts
12 |
13 | $azContext = Az.Accounts\Get-AzContext
14 | if (($azContext -eq $null) -or ($azContext.Subscription.Id -ne $SubscriptionId))
15 | {
16 | throw "To use ${AzKVaultName} Azure vault, the current user must be logged into Azure account subscription ${SubscriptionId}. Run 'Connect-AzAccount -SubscriptionId ${SubscriptionId}'."
17 | }
18 | }
19 |
20 | function Get-Secret
21 | {
22 | param (
23 | [string] $Name,
24 | [string] $VaultName,
25 | [hashtable] $AdditionalParameters
26 | )
27 |
28 | Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
29 |
30 | Import-Module -Name Az.KeyVault
31 |
32 | $secret = Az.KeyVault\Get-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName
33 | if ($secret -ne $null)
34 | {
35 | return $secret.SecretValue
36 | }
37 | }
38 |
39 | function Set-Secret
40 | {
41 | param (
42 | [string] $Name,
43 | [object] $Secret,
44 | [string] $VaultName,
45 | [hashtable] $Metadata,
46 | [hashtable] $AdditionalParameters
47 | )
48 |
49 | Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
50 |
51 | Import-Module -Name Az.KeyVault
52 |
53 | $null = Az.KeyVault\Set-AzKeyVaultSecret -Name $Name -SecretValue $Secret -VaultName $AdditionalParameters.AZKVaultName -Tag $Metadata
54 | return $?
55 | }
56 |
57 | function Remove-Secret
58 | {
59 | param (
60 | [string] $Name,
61 | [string] $VaultName,
62 | [hashtable] $AdditionalParameters
63 | )
64 |
65 | Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
66 |
67 | Import-Module -Name Az.KeyVault
68 |
69 | $null = Az.KeyVault\Remove-AzKeyVaultSecret -Name $Name -VaultName $AdditionalParameters.AZKVaultName -Force
70 | return $?
71 | }
72 |
73 | function Get-SecretInfo
74 | {
75 | param (
76 | [string] $Filter,
77 | [string] $VaultName,
78 | [hashtable] $AdditionalParameters
79 | )
80 |
81 | Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
82 |
83 | Import-Module -Name Az.KeyVault
84 |
85 | if ([string]::IsNullOrEmpty($Filter))
86 | {
87 | $Filter = "*"
88 | }
89 |
90 | $pattern = [WildcardPattern]::new($Filter)
91 | $vaultSecretInfos = Az.KeyVault\Get-AzKeyVaultSecret -VaultName $AdditionalParameters.AZKVaultName
92 | foreach ($vaultSecretInfo in $vaultSecretInfos)
93 | {
94 | if ($pattern.IsMatch($vaultSecretInfo.Name))
95 | {
96 | Write-Output (
97 | [Microsoft.PowerShell.SecretManagement.SecretInformation]::new(
98 | $vaultSecretInfo.Name,
99 | [Microsoft.PowerShell.SecretManagement.SecretType]::SecureString,
100 | $VaultName,
101 | $vaultSecretInfo.Tags)
102 | )
103 | }
104 | }
105 | }
106 |
107 | function Test-SecretVault
108 | {
109 | param (
110 | [string] $VaultName,
111 | [hashtable] $AdditionalParameters
112 | )
113 |
114 | try
115 | {
116 | Check-SubscriptionLogIn $AdditionalParameters.SubscriptionId $AdditionalParameters.AZKVaultName
117 | }
118 | catch
119 | {
120 | Write-Error $_
121 | return $false
122 | }
123 |
124 | return $true
125 | }
126 |
--------------------------------------------------------------------------------
/ExtensionModules/AKVaultScript/AKVaultScript.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | ModuleVersion = '1.0'
3 | NestedModules = ('.\AKVaultScript.Extension')
4 | CmdletsToExport = @()
5 | FunctionsToExport = @()
6 | }
7 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/Microsoft.PowerShell.CredManStore.Extension/Microsoft.PowerShell.CredManStore.Extension.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | ModuleVersion = '1.0'
3 | RootModule = './Microsoft.PowerShell.CredManStore.dll'
4 | FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
5 | }
6 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/README.md:
--------------------------------------------------------------------------------
1 | # PowerShell Secret Store module
2 |
3 | This module is an extension vault module for the PowerShell SecretManagement module.
4 | It stores secrets locally using Windows Credential Manager for the current interactive user account context.
5 | This module works only for Windows platforms.
6 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/Tests/Microsoft.PowerShell.CredManStore.Tests.ps1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT License.
3 |
4 | Describe "Test Microsoft.PowerShell.CredManStore module" -Skip:(-Not $IsWindows) {
5 | BeforeAll {
6 | $ProjectRoot = Split-Path $PSScriptRoot | Split-Path | Split-Path
7 | $ModuleRoot = Join-Path $ProjectRoot "artifacts/publish/Microsoft.PowerShell.CredManStore/release"
8 | Import-Module -Force -Name $ProjectRoot/module/Microsoft.PowerShell.SecretManagement.psd1
9 | Import-Module -Force -Name $ModuleRoot/Microsoft.PowerShell.CredManStore.psd1
10 | }
11 |
12 | AfterAll {
13 | Remove-Module -Name Microsoft.PowerShell.CredManStore -Force -ErrorAction Ignore
14 | Remove-Module -Name Microsoft.PowerShell.SecretManagement -Force -ErrorAction Ignore
15 | }
16 |
17 | Context "CredMan Store Vault Byte[] type" {
18 | BeforeAll {
19 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())
20 | $bytesToWrite = [System.Text.Encoding]::UTF8.GetBytes('TestStringForBytes')
21 | $errorCode = 0
22 | }
23 |
24 | It "Verifies byte[] write to store" {
25 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::WriteObject(
26 | $secretName,
27 | $bytesToWrite,
28 | [ref] $errorCode)
29 |
30 | $success | Should -BeTrue
31 | $errorCode | Should -Be 0
32 | }
33 |
34 | It "Verifes byte[] read from store" {
35 | $outBytes = $null
36 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::ReadObject(
37 | $secretName,
38 | [ref] $outBytes,
39 | [ref] $errorCode)
40 |
41 | $success | Should -BeTrue
42 | $errorCode | Should -Be 0
43 | [System.Text.Encoding]::UTF8.GetString($outBytes) | Should -BeExactly 'TestStringForBytes'
44 | }
45 |
46 | It "Verifies byte[] enumeration from store" {
47 | $outInfo = $null
48 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::EnumerateObjectInfo(
49 | $secretName,
50 | [ref] $outInfo,
51 | [ref] $errorCode)
52 |
53 | $success | Should -BeTrue
54 | $errorCode | Should -Be 0
55 | $outInfo.Key | Should -BeExactly $secretName
56 | $outInfo.Value | Should -BeExactly 'ByteArray'
57 | }
58 |
59 | It "Verifies Remove byte[] secret from store" {
60 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::DeleteObject(
61 | $secretName,
62 | [ref] $errorCode)
63 |
64 | $success | Should -BeTrue
65 | $errorCode | Should -Be 0
66 | }
67 | }
68 |
69 | Context "CredMan Store Vault String type" {
70 | BeforeAll {
71 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())
72 | $stringToWrite = 'TestStringForString'
73 | $errorCode = 0
74 | }
75 |
76 | It "Verifes string write to store" {
77 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::WriteObject(
78 | $secretName,
79 | $stringToWrite,
80 | [ref] $errorCode)
81 |
82 | $success | Should -BeTrue
83 | $errorCode | Should -Be 0
84 | }
85 |
86 | It "Verifies string read from store" {
87 | $outString = $null
88 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::ReadObject(
89 | $secretName,
90 | [ref] $outString,
91 | [ref] $errorCode)
92 |
93 | $success | Should -BeTrue
94 | $errorCode | Should -Be 0
95 | $outString | Should -BeExactly 'TestStringForString'
96 | }
97 |
98 | It "Verifies string enumeration from store" {
99 | $outInfo = $null
100 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::EnumerateObjectInfo(
101 | $secretName,
102 | [ref] $outInfo,
103 | [ref] $errorCode)
104 |
105 | $success | Should -BeTrue
106 | $errorCode | Should -Be 0
107 | $outInfo.Key | Should -BeExactly $secretName
108 | $outInfo.Value | Should -BeExactly 'String'
109 | }
110 |
111 | It "Verifies string remove from store" {
112 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::DeleteObject(
113 | $secretName,
114 | [ref] $errorCode)
115 |
116 | $success | Should -BeTrue
117 | $errorCode | Should -Be 0
118 | }
119 | }
120 |
121 | Context "CredMan Store Vault SecureString type" {
122 | BeforeAll {
123 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())
124 | $randomSecret = [System.IO.Path]::GetRandomFileName()
125 | $secureStringToWrite = ConvertTo-SecureString -String $randomSecret -AsPlainText -Force
126 | $errorCode = 0
127 | }
128 |
129 | It "Verifies SecureString write to store" {
130 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::WriteObject(
131 | $secretName,
132 | $secureStringToWrite,
133 | [ref] $errorCode)
134 |
135 | $success | Should -BeTrue
136 | $errorCode | Should -Be 0
137 | }
138 |
139 | It "Verifies SecureString read from store" {
140 | $outSecureString = $null
141 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::ReadObject(
142 | $secretName,
143 | [ref] $outSecureString,
144 | [ref] $errorCode)
145 |
146 | $success | Should -BeTrue
147 | $errorCode | Should -Be 0
148 | [System.Net.NetworkCredential]::new('',$outSecureString).Password | Should -BeExactly $randomSecret
149 | }
150 |
151 | It "Verifies SecureString enumeration from store" {
152 | $outInfo = $null
153 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::EnumerateObjectInfo(
154 | $secretName,
155 | [ref] $outInfo,
156 | [ref] $errorCode)
157 |
158 | $success | Should -BeTrue
159 | $errorCode | Should -Be 0
160 | $outInfo.Key | Should -BeExactly $secretName
161 | $outInfo.Value | Should -BeExactly 'SecureString'
162 | }
163 |
164 | It "Verifies SecureString remove from store" {
165 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::DeleteObject(
166 | $secretName,
167 | [ref] $errorCode)
168 |
169 | $success | Should -BeTrue
170 | $errorCode | Should -Be 0
171 | }
172 | }
173 |
174 | Context "CredMan Store Vault PSCredential type" {
175 | BeforeAll {
176 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())
177 | $randomSecret = [System.IO.Path]::GetRandomFileName()
178 | $errorCode = 0
179 | }
180 |
181 | It "Verifies PSCredential type write to store" {
182 | $cred = [pscredential]::new('UserL', (ConvertTo-SecureString $randomSecret -AsPlainText -Force))
183 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::WriteObject(
184 | $secretName,
185 | $cred,
186 | [ref] $errorCode)
187 |
188 | $success | Should -BeTrue
189 | $errorCode | Should -Be 0
190 | }
191 |
192 | It "Verifies PSCredential read from store" {
193 | $outCred = $null
194 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::ReadObject(
195 | $secretName,
196 | [ref] $outCred,
197 | [ref] $errorCode)
198 |
199 | $success | Should -BeTrue
200 | $errorCode | Should -Be 0
201 | $outCred.UserName | Should -BeExactly "UserL"
202 | [System.Net.NetworkCredential]::new('', ($outCred.Password)).Password | Should -BeExactly $randomSecret
203 | }
204 |
205 | It "Verifies PSCredential enumeration from store" {
206 | $outInfo = $null
207 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::EnumerateObjectInfo(
208 | $secretName,
209 | [ref] $outInfo,
210 | [ref] $errorCode)
211 |
212 | $success | Should -BeTrue
213 | $errorCode | Should -Be 0
214 | $outInfo.Key | Should -BeExactly $secretName
215 | $outInfo.Value | Should -BeExactly 'PSCredential'
216 | }
217 |
218 | It "Verifies PSCredential remove from store" {
219 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::DeleteObject(
220 | $secretName,
221 | [ref] $errorCode)
222 |
223 | $success | Should -BeTrue
224 | $errorCode | Should -Be 0
225 | }
226 | }
227 |
228 | Context "CredMan Store Vault Hashtable type" {
229 | BeforeAll {
230 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())
231 | $randomSecretA = [System.IO.Path]::GetRandomFileName()
232 | $randomSecretB = [System.IO.Path]::GetRandomFileName()
233 | $errorCode = 0
234 | }
235 |
236 | It "Verifies Hashtable type write to store" {
237 | $ht = @{
238 | Blob = ([byte[]] @(1,2))
239 | Str = "TestStoreString"
240 | SecureString = (ConvertTo-SecureString $randomSecretA -AsPlainText -Force)
241 | Cred = ([pscredential]::New("UserA", (ConvertTo-SecureString $randomSecretB -AsPlainText -Force)))
242 | }
243 |
244 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::WriteObject(
245 | $secretName,
246 | $ht,
247 | [ref] $errorCode)
248 |
249 | $success | Should -BeTrue
250 | $errorCode | Should -Be 0
251 | }
252 |
253 | It "Verifies Hashtable read from store" {
254 | $outHT = $null
255 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::ReadObject(
256 | $secretName,
257 | [ref] $outHT,
258 | [ref] $errorCode)
259 |
260 | $success | Should -BeTrue
261 | $errorCode | Should -Be 0
262 | $outHT.Blob.Count | Should -Be 2
263 | $outHT.Str | Should -BeExactly 'TestStoreString'
264 | [System.Net.NetworkCredential]::new('', ($outHT.SecureString)).Password | Should -BeExactly $randomSecretA
265 | $outHT.Cred.UserName | Should -BeExactly 'UserA'
266 | [System.Net.NetworkCredential]::New('', ($outHT.Cred.Password)).Password | Should -BeExactly $randomSecretB
267 | }
268 |
269 | It "Verifies Hashtable enumeration from store" {
270 | $outInfo = $null
271 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::EnumerateObjectInfo(
272 | $secretName,
273 | [ref] $outInfo,
274 | [ref] $errorCode)
275 |
276 | $success | Should -BeTrue
277 | $errorCode | Should -Be 0
278 | $outInfo.Key | Should -BeExactly $secretName
279 | $outInfo.Value | Should -BeExactly 'Hashtable'
280 | }
281 |
282 | It "Verifies Hashtable remove from store" {
283 | $success = [Microsoft.PowerShell.CredManStore.LocalCredManStore]::DeleteObject(
284 | $secretName,
285 | [ref] $errorCode)
286 |
287 | $success | Should -BeTrue
288 | $errorCode | Should -Be 0
289 | }
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/help/en-US/about_Microsoft.PowerShell.CredManStore.md:
--------------------------------------------------------------------------------
1 | # Secret Management local store extension vault module
2 | ## Microsoft.PowerShell.CredManStore
3 |
4 | # SHORT DESCRIPTION
5 | This is an extension vault module for the Microsoft.PowerShell.SecretManagement module.
6 | It stores secrets on the local machine in the current user account context using Windows Credential Manager.
7 | This extension vault module can be used only on Windows platforms.
8 |
9 | ```
10 | ABOUT TOPIC NOTE:
11 | About topics can be no longer than 80 characters wide when rendered to text.
12 | Any topics greater than 80 characters will be automatically wrapped.
13 | The generated about topic will be encoded UTF-8.
14 | ```
15 |
16 | # LONG DESCRIPTION
17 | {{ Long Description Placeholder }}
18 |
19 | ## Optional Subtopics
20 | {{ Optional Subtopic Placeholder }}
21 |
22 | # EXAMPLES
23 | {{ Code or descriptive examples of how to leverage the functions described. }}
24 |
25 | # NOTE
26 | {{ Note Placeholder - Additional information that a user needs to know.}}
27 |
28 | # TROUBLESHOOTING NOTE
29 | {{ Troubleshooting Placeholder - Warns users of bugs}}
30 |
31 | {{ Explains behavior that is likely to change with fixes }}
32 |
33 | # SEE ALSO
34 | {{ See also placeholder }}
35 |
36 | {{ You can also list related articles, blogs, and video URLs. }}
37 |
38 | # KEYWORDS
39 | {{List alternate names or titles for this topic that readers might use.}}
40 |
41 | - {{ Keyword Placeholder }}
42 | - {{ Keyword Placeholder }}
43 | - {{ Keyword Placeholder }}
44 | - {{ Keyword Placeholder }}
45 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/src/Microsoft.PowerShell.CredManStore.psd1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT License.
3 |
4 | @{
5 |
6 | NestedModules = @('.\Microsoft.PowerShell.CredManStore.Extension')
7 |
8 | # Version number of this module.
9 | ModuleVersion = '1.0.0'
10 |
11 | # Supported PSEditions
12 | CompatiblePSEditions = @('Desktop', 'Core')
13 |
14 | # ID used to uniquely identify this module
15 | GUID = '4b4bc3ec-190a-493f-a869-5ebdb239895d'
16 |
17 | # Author of this module
18 | Author = 'Microsoft Corporation'
19 |
20 | # Company or vendor of this module
21 | CompanyName = 'Microsoft Corporation'
22 |
23 | # Copyright statement for this module
24 | Copyright = '(c) Microsoft Corporation. All rights reserved.'
25 |
26 | # Description of the functionality provided by this module
27 | Description = "
28 | This PowerShell module is an extension vault module for the PowerShell SecretManagement module.
29 | As an extension vault, this module uses Windows Credential Manager to store secrets to the local machine based on the current interactive user account context.
30 | This extension vault module will run only on Windows platforms.
31 | "
32 |
33 | # Minimum version of the PowerShell engine required by this module
34 | PowerShellVersion = '5.1'
35 |
36 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
37 | CmdletsToExport = @()
38 |
39 | # This is critical to ensure no nested module functions are exposed publicly.
40 | FunctionsToExport = @()
41 |
42 | # HelpInfo URI of this module
43 | # HelpInfoURI = ''
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/src/code/CredManStore.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT License.
3 |
4 | using Microsoft.PowerShell.SecretManagement;
5 | using System;
6 | using System.Collections;
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using System.Management.Automation;
10 |
11 | namespace Microsoft.PowerShell.CredManStore
12 | {
13 | #region Get-Secret
14 |
15 | [Cmdlet(VerbsCommon.Get, "Secret")]
16 | public sealed class GetSecretCommand : PSCmdlet
17 | {
18 | #region Parameters
19 |
20 | [Parameter]
21 | public string Name { get; set; }
22 |
23 | [Parameter]
24 | public string VaultName { get; set; }
25 |
26 | [Parameter]
27 | public Hashtable AdditionalParameters { get; set; }
28 |
29 | #endregion
30 |
31 | #region Overrides
32 |
33 | protected override void EndProcessing()
34 | {
35 | if (LocalCredManStore.ReadObject(
36 | name: Name,
37 | outObject: out object outObject,
38 | out int errorCode))
39 | {
40 | WriteObject(
41 | sendToPipeline: outObject,
42 | enumerateCollection: false);
43 |
44 | return;
45 | }
46 |
47 | if (errorCode > 0 && errorCode != NativeUtils.ERROR_NOT_FOUND)
48 | {
49 | var message = string.Format(CultureInfo.InvariantCulture,
50 | @"Error while retrieving secret from vault {0} : {1}",
51 | VaultName,
52 | LocalCredManStore.GetErrorMessage(errorCode));
53 |
54 | WriteError(
55 | new ErrorRecord(
56 | new PSInvalidOperationException(message),
57 | "CredManVaultGetError",
58 | ErrorCategory.InvalidOperation,
59 | this));
60 | }
61 | }
62 |
63 | #endregion
64 | }
65 |
66 | #endregion
67 |
68 | #region Get-SecretInfo
69 |
70 | [Cmdlet(VerbsCommon.Get, "SecretInfo")]
71 | public sealed class GetSecretInfoCommand : PSCmdlet
72 | {
73 | #region Parameters
74 |
75 | [Parameter]
76 | public string Filter { get; set; }
77 |
78 | [Parameter]
79 | public string VaultName { get; set; }
80 |
81 | [Parameter]
82 | public Hashtable AdditionalParameters { get; set; }
83 |
84 | #endregion
85 |
86 | #region Overrides
87 |
88 | protected override void EndProcessing()
89 | {
90 | if (LocalCredManStore.EnumerateObjectInfo(
91 | filter: Filter,
92 | out KeyValuePair[] outObjectInfos,
93 | out int errorCode))
94 | {
95 | var secretInfoList = new List(outObjectInfos.Length);
96 | foreach (var item in outObjectInfos)
97 | {
98 | secretInfoList.Add(
99 | new SecretInformation(
100 | name: item.Key,
101 | type: item.Value,
102 | vaultName: VaultName));
103 | }
104 |
105 | WriteObject(
106 | sendToPipeline: secretInfoList.ToArray(),
107 | enumerateCollection: false);
108 |
109 | return;
110 | }
111 |
112 | if (errorCode > 0 && errorCode != NativeUtils.ERROR_NOT_FOUND)
113 | {
114 | var message = string.Format(CultureInfo.InvariantCulture,
115 | @"Error while retrieving secret information from vault {0} : {1}",
116 | VaultName,
117 | LocalCredManStore.GetErrorMessage(errorCode));
118 |
119 | WriteError(
120 | new ErrorRecord(
121 | new PSInvalidOperationException(message),
122 | "CredManVaultGetInfoError",
123 | ErrorCategory.InvalidOperation,
124 | this));
125 | }
126 | }
127 |
128 | #endregion
129 | }
130 |
131 | #endregion
132 |
133 | #region Set-Secret
134 |
135 | [Cmdlet(VerbsCommon.Set, "Secret")]
136 | public sealed class SetSecretCommand : PSCmdlet
137 | {
138 | #region Parameters
139 |
140 | [Parameter]
141 | public string Name { get; set; }
142 |
143 | [Parameter]
144 | public object Secret { get; set; }
145 |
146 | [Parameter]
147 | public string VaultName { get; set; }
148 |
149 | [Parameter]
150 | public Hashtable AdditionalParameters { get; set; }
151 |
152 | #endregion
153 |
154 | #region Overrides
155 |
156 | protected override void EndProcessing()
157 | {
158 | if (!LocalCredManStore.WriteObject(
159 | name: Name,
160 | objectToWrite: Secret,
161 | out int errorCode))
162 | {
163 | var message = string.Format(CultureInfo.InvariantCulture,
164 | @"Error while writing secret to vault {0} : {1}",
165 | VaultName,
166 | LocalCredManStore.GetErrorMessage(errorCode));
167 |
168 | WriteError(
169 | new ErrorRecord(
170 | new PSInvalidOperationException(message),
171 | "CredManVaultWriteError",
172 | ErrorCategory.InvalidOperation,
173 | this));
174 | }
175 | }
176 |
177 | #endregion
178 | }
179 |
180 | #endregion
181 |
182 | #region Remove-Secret
183 |
184 | [Cmdlet(VerbsCommon.Remove, "Secret")]
185 | public sealed class RemoveSecretCommand : PSCmdlet
186 | {
187 | #region Parameters
188 |
189 | [Parameter]
190 | public string Name { get; set; }
191 |
192 | [Parameter]
193 | public string VaultName { get; set; }
194 |
195 | [Parameter]
196 | public Hashtable AdditionalParameters { get; set; }
197 |
198 | #endregion
199 |
200 | #region Overrides
201 |
202 | protected override void EndProcessing()
203 | {
204 | if (!LocalCredManStore.DeleteObject(
205 | name: Name,
206 | out int errorCode))
207 | {
208 | var message = string.Format(CultureInfo.InvariantCulture,
209 | @"Error while deleting secret from vault {0} : {1}",
210 | VaultName,
211 | LocalCredManStore.GetErrorMessage(errorCode));
212 |
213 | WriteError(
214 | new ErrorRecord(
215 | new PSInvalidOperationException(message),
216 | "CredManVaultWriteError",
217 | ErrorCategory.InvalidOperation,
218 | this));
219 | }
220 | }
221 |
222 | #endregion
223 | }
224 |
225 | #endregion
226 |
227 | #region Test-SecretVault
228 |
229 | [Cmdlet(VerbsDiagnostic.Test, "SecretVault")]
230 | public sealed class TestSecretVaultCommand : PSCmdlet
231 | {
232 | #region Parameters
233 |
234 | [Parameter]
235 | public string VaultName { get; set; }
236 |
237 | [Parameter]
238 | public Hashtable AdditionalParameters { get; set; }
239 |
240 | #endregion
241 |
242 | #region Overrides
243 |
244 | protected override void EndProcessing()
245 | {
246 | var secretName = System.IO.Path.GetRandomFileName();
247 | var secret = System.IO.Path.GetRandomFileName();
248 |
249 | // Setting a secret
250 | var success = LocalCredManStore.WriteObject(
251 | name: secretName,
252 | objectToWrite: secret,
253 | out int errorCode);
254 | if (!success)
255 | {
256 | var message = string.Format(CultureInfo.InvariantCulture,
257 | @"Test-SecretVault failed to write secret on vault {0} with error: {1}",
258 | VaultName, LocalCredManStore.GetErrorMessage(errorCode));
259 | WriteError(
260 | new ErrorRecord(
261 | new PSInvalidOperationException(message),
262 | errorId: "CredManVaultTestFailWrite",
263 | errorCategory: ErrorCategory.InvalidOperation,
264 | this));
265 |
266 | WriteObject(success);
267 | return;
268 | }
269 |
270 | // Getting secret info
271 | success = LocalCredManStore.EnumerateObjectInfo(
272 | filter: secretName,
273 | out KeyValuePair[] outObjectInfos,
274 | out errorCode);
275 | if (!success)
276 | {
277 | var message = string.Format(CultureInfo.InvariantCulture,
278 | @"Test-SecretVault failed to get secret info on vault {0} with error: {1}",
279 | VaultName, LocalCredManStore.GetErrorMessage(errorCode));
280 | WriteError(
281 | new ErrorRecord(
282 | new PSInvalidOperationException(message),
283 | errorId: "CredManVaultTestFailReadInfo",
284 | errorCategory: ErrorCategory.InvalidOperation,
285 | this));
286 | }
287 |
288 | // Getting secret value
289 | success = LocalCredManStore.ReadObject(
290 | name: secretName,
291 | outObject: out object outObject,
292 | out errorCode);
293 | if (!success)
294 | {
295 | var message = string.Format(CultureInfo.InvariantCulture,
296 | @"Test-SecretVault failed to get secret value on vault {0} with error: {1}",
297 | VaultName, LocalCredManStore.GetErrorMessage(errorCode));
298 | WriteError(
299 | new ErrorRecord(
300 | new PSInvalidOperationException(message),
301 | errorId: "CredManVaultTestFailRead",
302 | errorCategory: ErrorCategory.InvalidOperation,
303 | this));
304 | }
305 |
306 | // Removing secret
307 | success = LocalCredManStore.DeleteObject(
308 | name: secretName,
309 | out errorCode);
310 | if (!success)
311 | {
312 | var message = string.Format(CultureInfo.InvariantCulture,
313 | @"Test-SecretVault failed to remove secret on vault {0} with error: {1}",
314 | VaultName, LocalCredManStore.GetErrorMessage(errorCode));
315 | WriteError(
316 | new ErrorRecord(
317 | new PSInvalidOperationException(message),
318 | errorId: "CredManVaultTestFailDelete",
319 | errorCategory: ErrorCategory.InvalidOperation,
320 | this));
321 | }
322 |
323 | WriteObject(success);
324 | }
325 |
326 | #endregion
327 |
328 | }
329 |
330 | #endregion
331 | }
332 |
--------------------------------------------------------------------------------
/ExtensionModules/CredManStore/src/code/Microsoft.PowerShell.CredManStore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Library
6 | Microsoft.PowerShell.CredManStore
7 | Microsoft.PowerShell.CredManStore
8 | 1.0.0.0
9 | 1.0.0
10 | 1.0.0
11 | netstandard2.0
12 |
13 |
14 |
15 | $(DefineConstants);UNIX
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ExtensionModules/TestLocalScript/TestLocalScript.Extension/TestLocalScript.Extension.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | ModuleVersion = '1.0'
3 | RootModule = '.\TestLocalScript.Extension.psm1'
4 | FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault','Unregister-SecretVault')
5 | }
6 |
--------------------------------------------------------------------------------
/ExtensionModules/TestLocalScript/TestLocalScript.Extension/TestLocalScript.Extension.psm1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation. All rights reserved.
2 | # Licensed under the MIT License.
3 |
4 | function Get-Path
5 | {
6 | param (
7 | [string] $VaultName
8 | )
9 |
10 | $path = Join-Path $env:TEMP $VaultName
11 | if (! (Test-Path -Path $path))
12 | {
13 | [System.IO.Directory]::CreateDirectory($path)
14 | }
15 |
16 | return $path
17 | }
18 |
19 | function Get-Secret
20 | {
21 | param (
22 | [string] $Name,
23 | [string] $VaultName,
24 | [hashtable] $AdditionalParameters
25 | )
26 |
27 | if ([WildcardPattern]::ContainsWildcardCharacters($Name))
28 | {
29 | throw "The Name parameter cannot contain wild card characters."
30 | }
31 |
32 | $filePath = Join-Path -Path (Get-Path $VaultName) -ChildPath "${Name}.xml"
33 | if (! (Test-Path -Path $filePath))
34 | {
35 | return
36 | }
37 |
38 | $secret = Import-Clixml -Path $filePath
39 |
40 | if ($secret.GetType().IsArray)
41 | {
42 | return @(,[byte[]] $secret)
43 | }
44 |
45 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
46 | Write-Verbose "[TestLocalScript.Extension]:Get-SecretVault successfully called for vault: $VaultName" -Verbose:$verboseEnabled
47 |
48 | return $secret
49 | }
50 |
51 | function Set-Secret
52 | {
53 | param (
54 | [string] $Name,
55 | [object] $Secret,
56 | [string] $VaultName,
57 | [hashtable] $AdditionalParameters
58 | )
59 |
60 | $filePath = Join-Path -Path (Get-Path $VaultName) -ChildPath "${Name}.xml"
61 | $Secret | Export-Clixml -Path $filePath -Force
62 |
63 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
64 | Write-Verbose "[TestLocalScript.Extension]:Set-SecretVault successfully called for vault: $VaultName" -Verbose:$verboseEnabled
65 |
66 | return $true
67 | }
68 |
69 | function Remove-Secret
70 | {
71 | param (
72 | [string] $Name,
73 | [string] $VaultName,
74 | [hashtable] $AdditionalParameters
75 | )
76 |
77 | $filePath = Join-Path -Path (Get-Path $VaultName) -ChildPath "${Name}.xml"
78 | if (! (Test-Path -Path $filePath))
79 | {
80 | Write-Error "The secret, $Name, does not exist."
81 | return $false
82 | }
83 |
84 | Remove-Item -Path $filePath
85 |
86 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
87 | Write-Verbose "[TestLocalScript.Extension]:Remove-SecretVault successfully called for vault: $VaultName" -Verbose:$verboseEnabled
88 |
89 | return $true
90 | }
91 |
92 | function Get-SecretInfo
93 | {
94 | param(
95 | [string] $Filter,
96 | [string] $VaultName,
97 | [hashtable] $AdditionalParameters
98 | )
99 |
100 | if ([string]::IsNullOrEmpty($Filter)) { $Filter = "*" }
101 |
102 | $files = Get-ChildItem -Path (Join-Path -Path (Get-Path $VaultName) -ChildPath "${Filter}.xml") 2>$null
103 |
104 | foreach ($file in $files)
105 | {
106 | $secretName = [System.IO.Path]::GetFileNameWithoutExtension((Split-Path -Path $file -Leaf))
107 | $secret = Import-Clixml -Path $file.FullName
108 | $type = if ($secret.gettype().IsArray) { [Microsoft.PowerShell.SecretManagement.SecretType]::ByteArray }
109 | elseif ($secret -is [string]) { [Microsoft.PowerShell.SecretManagement.SecretType]::String }
110 | elseif ($secret -is [securestring]) { [Microsoft.PowerShell.SecretManagement.SecretType]::SecureString }
111 | elseif ($secret -is [PSCredential]) { [Microsoft.PowerShell.SecretManagement.SecretType]::PSCredential }
112 | elseif ($secret -is [hashtable]) { [Microsoft.PowerShell.SecretManagement.SecretType]::Hashtable }
113 | else { [Microsoft.PowerShell.SecretManagement.SecretType]::Unknown }
114 |
115 | Write-Output (
116 | [Microsoft.PowerShell.SecretManagement.SecretInformation]::new(
117 | $secretName,
118 | $type,
119 | $VaultName)
120 | )
121 | }
122 |
123 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
124 | Write-Verbose "[TestLocalScript.Extension]:Get-SecretInfo successfully called for vault: $VaultName" -Verbose:$verboseEnabled
125 | Write-Warning "[TestLocalScript.Extension]::Get-SecretInfo bogus warning for vault: $VaultName"
126 | }
127 |
128 | function Test-SecretVault
129 | {
130 | param (
131 | [string] $VaultName,
132 | [hashtable] $AdditionalParameters
133 | )
134 |
135 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
136 | Write-Verbose "[TestLocalScript.Extension]:Test-SecretVault successfully called for vault: $VaultName" -Verbose:$verboseEnabled
137 |
138 | return $true
139 | }
140 |
141 | function Unregister-SecretVault
142 | {
143 | param (
144 | [string] $VaultName,
145 | [hashtable] $AdditionalParameters
146 | )
147 |
148 | $verboseEnabled = $AdditionalParameters.ContainsKey('Verbose') -and ($AdditionalParameters['Verbose'] -eq $true)
149 | Write-Verbose "[TestLocalScript.Extension]:Unregister-SecretVault successfully called for vault: $VaultName" -Verbose:$verboseEnabled
150 | }
151 |
--------------------------------------------------------------------------------
/ExtensionModules/TestLocalScript/TestLocalScript.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | ModuleVersion = '1.0'
3 | NestedModules = @('.\TestLocalScript.Extension')
4 | CmdletsToExport = @()
5 | FunctionsToExport = @()
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Microsoft Corporation.
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PowerShell SecretManagement module
2 |
3 | PowerShell SecretManagement module provides a convenient way for a user to store and retrieve secrets.
4 | The secrets are stored in SecretManagement extension vaults.
5 | An extension vault is a PowerShell module that has been registered to SecretManagement, and exports five module functions required by SecretManagement.
6 | An extension vault can store secrets locally or remotely.
7 | Extension vaults are registered to the current logged in user context, and will be available only to that user (unless also registered to other users).
8 |
9 | In addition to implementing the five required SecretManagement functions, extension vaults are responsible for any authentication, including prompting the user for passphrases, and providing error and informational messages specific to the vault implementation.
10 | Error and informational messages common to all extension vaults are provided by SecretManagement.
11 |
12 | PowerShell SecretManagement module is essentially an orchestrator for extension vaults which perform the actual secret storage and encryption.
13 | The extension vault may implement its own store, or wrap an existing secure store solution, such as Azure KeyVault, KeePass, Keyring, etc.
14 |
15 | PowerShell SecretManagement supports the following secret data types:
16 |
17 | - byte[]
18 | - string
19 | - SecureString
20 | - PSCredential
21 | - Hashtable
22 |
23 | All extension vault implementations must also support these data types.
24 |
25 | PowerShell SecretManagement module provides cmdlets for for accessing and manipulating secrets, and also cmdlets for registering and manipulating vault extensions.
26 |
27 | ## Installation
28 |
29 | You can install the `Microsoft.PowerShell.SecretManagement` module from the [PowerShell Gallery](https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretManagement).
30 |
31 | ```powershell
32 | Install-Module -Name Microsoft.PowerShell.SecretManagement -Repository PSGallery
33 | ```
34 |
35 | ## Secret metadata
36 |
37 | Extension vaults can optionally support storing and retrieving additional secret metadata, that is data associated with the secret.
38 | Secret metadata is not security sensitive and does not need to be stored securely in the extension vault.
39 |
40 | Secret metadata can be included by using the `-Metadata` parameter: `Set-Secret -Metadata @{ Name=Value }`.
41 | The `-Metadata` parameter takes a `Hashtable` type argument consisting of name/value pairs.
42 | Extension vaults should at minimum support the following value types:
43 |
44 | - string
45 |
46 | - int
47 |
48 | - DateTime
49 |
50 | The secret metadata is included in the `SecretInformation` type object returned by `Get-SecretInfo`, in a `Metadata` property.
51 | The `Metadata` property is a `ReadonlyDictionary` type.
52 |
53 | ## Vault extension registration cmdlets
54 |
55 | ### Register-SecretVault
56 |
57 | Registers a single extension vault to the current user
58 |
59 | ### Get-SecretVault
60 |
61 | Retrieves information about one or more registered extension vaults
62 |
63 | ### Unregister-SecretVault
64 |
65 | Unregisters a single extension vault
66 |
67 | ### Set-SecretVaultDefault
68 |
69 | Sets one registered extension vault as the default vault
70 |
71 | ### Test-SecretVault
72 |
73 | Runs the Test-SecretVault function provided by the extension vault
74 |
75 | ### Unlock-SecretVault
76 |
77 | Unlocks the extension vault through a passed in SecureString password
78 |
79 | ## Accessing secrets cmdlets
80 |
81 | ### Set-Secret
82 |
83 | Adds a secret to a specific extension vault, or to the default vault if no vault is specified
84 |
85 | ### Set-SecretInfo
86 |
87 | Adds or replaces additional secret metadata to an existing secret in the vault.
88 | Metadata is not stored securely.
89 |
90 | ### Get-Secret
91 |
92 | Retrieves a secret from a specific extension vault, or first found over all vaults
93 |
94 | ### Get-SecretInfo
95 |
96 | Retrieves information about one or more secrets, but not the secret itself
97 |
98 | ### Remove-Secret
99 |
100 | Removes a secret from a specific vault
101 |
102 | ## Vault extension registration
103 |
104 | Vault extensions are registered to the current user context.
105 | They are registered as PowerShell modules that expose required functions used by SecretManagement to manipulate secrets.
106 | The required functions are provided as PowerShell cmdlets, and can be implemented as script or binary cmdlets.
107 |
108 | Since each extension vault module exports the same five cmdlets, the module must conform to a directory structure that hides cmdlets from the user and PowerShell command discovery.
109 | Therefore the extension vault module itself does not export the five required cmdlets directly, but are instead exported from a nested module that resides within the extension vault module directory.
110 | This nested module must have a name that is the parent module name with '.Extension' appended to it.
111 |
112 | It is recommended that the parent module manifest file (.psd1) include the 'SecretManagement' tag in its PrivateData section.
113 | This allows [PowerShellGallery](https://www.powershellgallery.com) to associate it with the SecretManagement module.
114 |
115 | ### Example: Script module vault extension
116 |
117 | This is a minimal vault extension example to demonstrate the directory structure and functional requirements of an extension vault module.
118 | The extension vault module name is 'TestVault'.
119 |
120 | #### Module directory structure
121 |
122 | ./TestVault
123 | ./TestVault/TestVault.psd1
124 | ./TestVault/TestStoreImplementation.dll
125 | ./TestVault/TestVault.Extension
126 | ./TestVault/TestVault.Extension/TestVault.Extension.psd1
127 | ./TestVault/TestVault.Extension/TestVault.Extension.psm1
128 |
129 | #### TestVault.psd1 file
130 |
131 | ```powershell
132 | @{
133 | ModuleVersion = '1.0'
134 | RootModule = '.\TestStoreImplementation.dll'
135 | NestedModules = @('.\TestVault.Extension')
136 | CmdletsToExport = @('Set-TestStoreConfiguration','Get-TestStoreConfiguration')
137 | PrivateData = @{
138 | PSData = @{
139 | Tags = @('SecretManagement')
140 | }
141 | }
142 | }
143 | ```
144 |
145 | The TestVault extension module has a binary component (TestStoreImplementation.dll) which implements the vault. It publicly exports two cmdlets that are used to configure the store.
146 | It also declares the required nested module (TestVault.Extension) that exports the five functions required by SecretManagement registration.
147 |
148 | Note that the nested module conforms to the required naming format:
149 | '[ModuleName].Extension'
150 |
151 | Note that only the 'NestedModules' entry is required because it loads 'TestVault.Extension' into the module scope, and allows SecretManagement access to the required five functions.
152 | The 'RootModule' and 'CmdletsToExport' entries are only for configuring the TestStore in this specific case, and are not needed in general.
153 |
154 | #### TestVault.Extension.psd1 file
155 |
156 | ```powershell
157 | @{
158 | ModuleVersion = '1.0'
159 | RootModule = '.\TestVault.Extension.psm1'
160 | RequiredAssemblies = '..\TestStoreImplementation.dll'
161 | FunctionsToExport = @('Set-Secret','Get-Secret','Remove-Secret','Get-SecretInfo','Test-SecretVault')
162 | }
163 | ```
164 |
165 | This nested module implements and exports the five functions required by SecretManagement.
166 | It also specifies the TestStoreImplementation.dll binary as a 'RequiredAssemblies' because the five exported functions depend on it.
167 |
168 | #### TestVault.Extension.psm1 file
169 |
170 | ```powershell
171 | function Get-Secret
172 | {
173 | [CmdletBinding()]
174 | param (
175 | [string] $Name,
176 | [string] $VaultName,
177 | [hashtable] $AdditionalParameters
178 | )
179 |
180 | return [TestStore]::GetItem($Name, $AdditionalParameters)
181 | }
182 |
183 | function Get-SecretInfo
184 | {
185 | [CmdletBinding()]
186 | param (
187 | [string] $Filter,
188 | [string] $VaultName,
189 | [hashtable] $AdditionalParameters
190 | )
191 |
192 | return @(,[Microsoft.PowerShell.SecretManagement.SecretInformation]::new(
193 | "Name", # Name of secret
194 | "String", # Secret data type [Microsoft.PowerShell.SecretManagement.SecretType]
195 | $VaultName, # Name of vault
196 | $Metadata)) # Optional Metadata parameter
197 | }
198 |
199 | function Set-Secret
200 | {
201 | [CmdletBinding()]
202 | param (
203 | [string] $Name,
204 | [object] $Secret,
205 | [string] $VaultName,
206 | [hashtable] $AdditionalParameters
207 | )
208 |
209 | [TestStore]::SetItem($Name, $Secret)
210 | }
211 |
212 | # Optional function
213 | function Set-SecretInfo
214 | {
215 | [CmdletBinding()]
216 | param (
217 | [string] $Name,
218 | [hashtable] $Metadata,
219 | [string] $VaultName,
220 | [hashtable] $AdditionalParameters
221 | )
222 |
223 | [TestStore]::SetItemMetadata($Name, $Metadata)
224 | }
225 |
226 | function Remove-Secret
227 | {
228 | [CmdletBinding()]
229 | param (
230 | [string] $Name,
231 | [string] $VaultName,
232 | [hashtable] $AdditionalParameters
233 | )
234 |
235 | [TestStore]::RemoveItem($Name)
236 | }
237 |
238 | function Test-SecretVault
239 | {
240 | [CmdletBinding()]
241 | param (
242 | [string] $VaultName,
243 | [hashtable] $AdditionalParameters
244 | )
245 |
246 | return [TestStore]::TestVault()
247 | }
248 |
249 | # Optional function
250 | function Unregister-SecretVault
251 | {
252 | [CmdletBinding()]
253 | param (
254 | [string] $VaultName,
255 | [hashtable] $AdditionalParameters
256 | )
257 |
258 | [TestStore]::RunUnregisterCleanup()
259 | }
260 |
261 | # Optional function
262 | function Unlock-SecretVault
263 | {
264 | [CmdletBinding()]
265 | param (
266 | [SecureString] $Password,
267 | [string] $VaultName,
268 | [hashtable] $AdditionalParameters
269 | )
270 |
271 | [TestStore]::UnlockVault($Password)
272 | }
273 | ```
274 |
275 | This module script implements the five functions, as cmdlets, required by SecretManagement, plus some optional functions.
276 | It also implements an optional `Unregister-SecretVault` function that is called during vault extension un-registration.
277 | It also implements an optional `Set-SecretInfo` function that sets secret metadata to a specific secret in the vault.
278 | It also implements an optional `Unlock-SecretVault` function that unlocks the vault for the current session based on a provided password.
279 |
280 | The `Set-Secret`, `Set-SecretInfo`, `Remove-Secret`, `Unregister-SecretVault` functions do not write any data to the pipeline, i.e., they do not return any data.
281 |
282 | The `Get-Secret` cmdlet writes the retrieved secret value to the output pipeline on return, or null if no secret was found.
283 | It should write an error only if an abnormal condition occurs.
284 |
285 | The `Get-SecretInfo` cmdlet writes an array of `Microsoft.PowerShell.SecretManagement.SecretInformation` type objects to the output pipeline or an empty array if no matches were found.
286 |
287 | The `Test-SecretVault` cmdlet should write all errors that occur during the test.
288 | But only a single true/false boolean should be written the the output pipeline indicating success.
289 |
290 | The `Unregister-SecretVault` cmdlet is optional and will be called on the extension vault if available.
291 | It is called before the extension vault is unregistered to allow it to perform any needed clean up work.
292 |
293 | The `Unlock-SecretVault` cmdlet is optional and will be called on the extension vault if available.
294 | It's purpose is to unlock an extension vault for use without having to prompt the user, and is useful for unattended scripts where user interaction is not possible.
295 |
296 | In general, these cmdlets should write to the error stream only for abnormal conditions that prevent successful completion.
297 | And write to the output stream only the data as indicated above, and expected by SecretManagement.
298 |
299 | In addition, these cmdlets should perform proper authentication and provide errors, and instructions to authenticate, as appropriate.
300 | Or prompt the user if needed, for example if a passphrase is required.
301 |
302 | A vault extension doesn't need to provide full implementation of all required functions.
303 | For example, a vault extension does not need to provide a way to add or remove a secret through the SecretManagement cmdlets, and can just provide retrieval services.
304 | If a vault extension doesn't support some functionality, then it should write an appropriate error with a meaningful message.
305 |
306 | Be careful with module implementation with scripts, because any data returned by function or method calls are automatically written to the output pipeline (if not assigned to a variable).
307 | SecretManagement expects only specific data to appear in the output pipeline, and if other data is inadvertently written, that will cause SecretManagement to not function properly.
308 |
309 | ### Registering the vault
310 |
311 | Once the TestVault module is created, it is registered as follows:
312 |
313 | ```powershell
314 | Register-SecretVault -Name LocalStore -ModuleName ./TestVault -VaultParameters @{ None="ReallyNeeded" } -DefaultVault
315 |
316 | Get-SecretVault
317 |
318 | VaultName ModuleName IsDefaultVault
319 | --------- ---------- --------------
320 | LocalStore TestVault True
321 |
322 | ```
323 |
324 | ## Extension vault registry file location
325 |
326 | SecretManagement is designed to be installed and run within a user account on both Windows and non-Windows platforms.
327 | The extension vault registry file is located in a user account protected directory.
328 |
329 | For Windows platforms the location is: `%LOCALAPPDATA%\Microsoft\PowerShell\secretmanagement`
330 |
331 | For non-Windows platforms the location: `$HOME/.secretmanagement`
332 |
333 | ## Windows Managed Accounts
334 |
335 | SecretManagement does not currently work for Windows managed accounts.
336 |
337 | SecretManagement depends on both `%LOCALAPPDATA%` folders to store registry information, and Data Protection APIs for safely handling secrets with the .Net `SecureString` type.
338 | However, Windows managed accounts do not have profiles or `%LOCALAPPDATA%` folders, and Windows Data Protection APIs do not work for managed accounts.
339 | Consequently, SecretManagement will not run under managed accounts.
340 |
341 | ## Code of Conduct
342 |
343 | Please see our [Code of Conduct](.github/CODE_OF_CONDUCT.md) before participating in this project.
344 |
345 | ## Security Policy
346 |
347 | For any security issues, please see our [Security Policy](.github/SECURITY.md).
348 |
--------------------------------------------------------------------------------
/SecretManagement.build.ps1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation.
2 | # Licensed under the MIT License.
3 | [CmdletBinding()]
4 | param(
5 | [ValidateSet("Debug", "Release")]
6 | [string]$Configuration = "Debug"
7 | )
8 |
9 | #Requires -Modules @{ ModuleName = "InvokeBuild"; ModuleVersion = "5.0.0" }
10 |
11 | task FindDotNet -Before Clean, Build {
12 | Assert (Get-Command dotnet -ErrorAction SilentlyContinue) "The dotnet CLI was not found, please install it: https://aka.ms/dotnet-cli"
13 | $DotnetVersion = dotnet --version
14 | Assert ($?) "The required .NET SDK was not found, please install it: https://aka.ms/dotnet-cli"
15 | Write-Host "Using dotnet $DotnetVersion at path $((Get-Command dotnet).Source)" -ForegroundColor Green
16 | }
17 |
18 | task Clean {
19 | Remove-BuildItem ./artifacts, ./module, ./out
20 | Invoke-BuildExec { dotnet clean ./src/code }
21 | }
22 |
23 | task BuildDocs -If { Test-Path -LiteralPath ./help } {
24 | New-ExternalHelp -Path ./help -OutputPath ./module/en-US
25 | }
26 |
27 | task BuildModule {
28 | New-Item -ItemType Directory -Force ./module | Out-Null
29 |
30 | Invoke-BuildExec { dotnet publish ./src/code -c $Configuration }
31 |
32 | # Hard code building this in release config since we aren't actually developing it,
33 | # it's only for tests. The tests also hard code the path assuming release config.
34 | Invoke-BuildExec { dotnet publish ./ExtensionModules/CredManStore/src/code -c Release }
35 |
36 | $FullModuleName = "Microsoft.PowerShell.SecretManagement"
37 |
38 | $CSharpArtifacts = @(
39 | "$FullModuleName.dll",
40 | "$FullModuleName.pdb",
41 | "$FullModuleName.xml",
42 | "System.Runtime.InteropServices.RuntimeInformation.dll")
43 |
44 | $CSharpArtifacts | ForEach-Object {
45 | $item = "./artifacts/publish/$FullModuleName/$($Configuration.ToLower())/$_"
46 | Copy-Item -Force -LiteralPath $item -Destination ./module
47 | }
48 |
49 | $BaseArtifacts = @(
50 | "src/$FullModuleName.format.ps1xml",
51 | "README.md",
52 | "LICENSE",
53 | "ThirdPartyNotices.txt")
54 |
55 | $BaseArtifacts | ForEach-Object {
56 | $itemToCopy = Join-Path $PSScriptRoot $_
57 | Copy-Item -Force -LiteralPath $itemToCopy -Destination ./module
58 | }
59 |
60 | [xml]$xml = Get-Content Directory.Build.props
61 | $moduleVersion = $xml.Project.PropertyGroup.ModuleVersion
62 | $manifestContent = Get-Content -LiteralPath "./src/$FullModuleName.psd1" -Raw
63 | $newManifestContent = $manifestContent -replace '{{ModuleVersion}}', $moduleVersion
64 | Set-Content -LiteralPath "./module/$FullModuleName.psd1" -Encoding utf8 -Value $newManifestContent
65 | }
66 |
67 | task PackageModule {
68 | New-Item -ItemType Directory -Force ./out | Out-Null
69 |
70 | try {
71 | Register-PSResourceRepository -Name SecretManagement -Uri ./out -ErrorAction Stop
72 | Publish-PSResource -Path ./module -Repository SecretManagement -Verbose
73 | } finally {
74 | Unregister-PSResourceRepository -Name SecretManagement
75 | }
76 | }
77 |
78 | # AKA Microsoft.PowerShell.SecretManagement.Library
79 | task PackageLibrary -If { $Configuration -eq "Release" } {
80 | Invoke-BuildExec { dotnet pack ./src/code --no-build -c $Configuration -o ./out }
81 | }
82 |
83 | task Test {
84 | Invoke-Pester -CI
85 | }
86 |
87 | task Build BuildModule, BuildDocs
88 |
89 | task Package PackageModule, PackageLibrary
90 |
91 | task . Clean, Build
92 |
--------------------------------------------------------------------------------
/SecretManagement.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31903.59
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E65CF2A7-C44A-491E-989D-8EAFAC4497C8}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.PowerShell.SecretManagement", "src\code\Microsoft.PowerShell.SecretManagement.csproj", "{90AF98C9-E305-4B37-945E-D79E14E1E8B3}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(SolutionProperties) = preSolution
16 | HideSolutionNode = FALSE
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {90AF98C9-E305-4B37-945E-D79E14E1E8B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {90AF98C9-E305-4B37-945E-D79E14E1E8B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {90AF98C9-E305-4B37-945E-D79E14E1E8B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {90AF98C9-E305-4B37-945E-D79E14E1E8B3}.Release|Any CPU.Build.0 = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(NestedProjects) = preSolution
25 | {90AF98C9-E305-4B37-945E-D79E14E1E8B3} = {E65CF2A7-C44A-491E-989D-8EAFAC4497C8}
26 | EndGlobalSection
27 | EndGlobal
28 |
--------------------------------------------------------------------------------
/ThirdPartyNotices.txt:
--------------------------------------------------------------------------------
1 | NOTICES AND INFORMATION
2 | Do Not Translate or Localize
3 |
4 | This software incorporates material from third parties.
5 | Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com,
6 | or you may send a check or money order for US $5.00, including the product name,
7 | the open source component name, platform, and version number, to:
8 |
9 | Source Code Compliance Team
10 | Microsoft Corporation
11 | One Microsoft Way
12 | Redmond, WA 98052
13 | USA
14 |
15 | Notwithstanding any other terms, you may reverse engineer this software to the extent
16 | required to debug changes to any libraries licensed under the GNU Lesser General Public License.
17 |
18 | ---------------------------------------------------------
19 |
20 | PowerShellStandard.Library 5.1.0 - MIT
21 |
22 |
23 | (c) 2008 VeriSign, Inc.
24 | Copyright (c) Microsoft Corporation. All rights reserved.
25 |
26 | MIT License
27 |
28 | Copyright (c) Microsoft Corporation.
29 |
30 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
31 |
32 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
33 |
34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 |
36 | ---------------------------------------------------------
37 |
38 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "8.0.304",
4 | "rollForward": "latestFeature",
5 | "allowPrerelease": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/help/Get-Secret.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Get-Secret
9 |
10 | ## SYNOPSIS
11 | Finds and returns a secret by name from registered vaults.
12 |
13 | ## SYNTAX
14 |
15 | ### NameParameterSet (Default)
16 | ```
17 | Get-Secret [-Name] [[-Vault] ] [-AsPlainText] []
18 | ```
19 |
20 | ### InfoParameterSet
21 | ```
22 | Get-Secret [-InputObject] [-AsPlainText] []
23 | ```
24 |
25 | ## DESCRIPTION
26 | This cmdlet finds and returns the first secret that matches the provided name.
27 | If a vault name is specified, then only that vault will be searched.
28 | Otherwise, all vaults are searched and the first found result is returned.
29 | If a 'Default' vault is specified, then that vault is searched before any other registered vault.
30 | Secrets that are string or SecureString types are returned as SecureString objects by default.
31 | Unless the '-AsPlainText' parameter switch is used, in which case the secret is returned as a String type in plain text.
32 |
33 | ## EXAMPLES
34 |
35 | ### Example 1
36 | ```
37 | PS C:\> Get-Secret -Name Secret1 -Vault CredMan
38 | System.Security.SecureString
39 |
40 | PS C:\> Get-Secret -Name Secret1 -Vault CredMan -AsPlainText
41 | PlainTextSecretString
42 | ```
43 |
44 | This example searches for a secret with the name 'Secret1', which is a String type secret.
45 | The first time returns the secret as a SecureString object.
46 | The second time uses the '-AsPlainText' and so the secret string is returned as a string object, and is displayed in plain text.
47 |
48 | ### Example 2
49 | ```
50 | PS C:\> Get-SecretInfo -Name Secret2 -Vault SecretStore | Get-Secret -AsPlainText
51 | ```
52 |
53 | This example retrieves secret information for the secret named 'Secret2' and then pipe the result to 'Get-Secret'.
54 | The secret is then looked up in the SecretStore vault and returned as plain text.
55 |
56 | ## PARAMETERS
57 |
58 | ### -AsPlainText
59 | Switch parameter that when used returns either a string or SecureString secret type as a String type (in plain text).
60 | If the secret being retrieved is not of string or SecureString type, this switch parameter has no effect.
61 |
62 | ```yaml
63 | Type: SwitchParameter
64 | Parameter Sets: (All)
65 | Aliases:
66 |
67 | Required: False
68 | Position: Named
69 | Default value: False
70 | Accept pipeline input: False
71 | Accept wildcard characters: False
72 | ```
73 |
74 | ### -InputObject
75 | SecretInformation object that describes a vault secret.
76 |
77 | ```yaml
78 | Type: SecretInformation
79 | Parameter Sets: InfoParameterSet
80 | Aliases:
81 |
82 | Required: True
83 | Position: 0
84 | Default value: None
85 | Accept pipeline input: True (ByValue)
86 | Accept wildcard characters: False
87 | ```
88 |
89 | ### -Name
90 | Name of the secret to be retrieved.
91 | Wild card characters are not allowed.
92 |
93 | ```yaml
94 | Type: String
95 | Parameter Sets: NameParameterSet
96 | Aliases:
97 |
98 | Required: True
99 | Position: 0
100 | Default value: None
101 | Accept pipeline input: True (ByValue)
102 | Accept wildcard characters: False
103 | ```
104 |
105 | ### -Vault
106 | Optional name of the registered vault to retrieve the secret from.
107 | If no vault name is specified, then all registered vaults are searched.
108 |
109 | ```yaml
110 | Type: String
111 | Parameter Sets: NameParameterSet
112 | Aliases:
113 |
114 | Required: False
115 | Position: 1
116 | Default value: None
117 | Accept pipeline input: False
118 | Accept wildcard characters: False
119 | ```
120 |
121 | ### CommonParameters
122 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
123 |
124 | ## INPUTS
125 |
126 | ### System.String
127 | ### Microsoft.PowerShell.SecretManagement.SecretInformation
128 | ## OUTPUTS
129 |
130 | ### System.Object
131 | ## NOTES
132 |
133 | ## RELATED LINKS
134 |
--------------------------------------------------------------------------------
/help/Get-SecretInfo.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Get-SecretInfo
9 |
10 | ## SYNOPSIS
11 | Finds and returns secret metadata information of one or more secrets.
12 |
13 | ## SYNTAX
14 |
15 | ```
16 | Get-SecretInfo [[-Name] ] [[-Vault] ] []
17 | ```
18 |
19 | ## DESCRIPTION
20 | This cmdlet finds and returns secret metadata for secrets with names that match the provided 'Name'.
21 | The 'Name' parameter argument can include wildcards for the search.
22 | If no 'Name' parameter argument is provided then metadata for all secrets is returned.
23 | The search is performed over all registered vaults, unless a specific vault name is specified.
24 | Secret metadata consists of the secret name, secret type, vault name, and optional additional user data if supported by the extension vault.
25 |
26 | ## EXAMPLES
27 |
28 | ### Example 1
29 | ```powershell
30 | PS C:\> Get-SecretInfo -Name *
31 |
32 | Name Type VaultName
33 | ---- ---- ---------
34 | Secret1 String LocalStore
35 | Secret2 ByteArray LocalStore
36 | Secret3 SecureString LocalStore
37 | Secret4 PSCredential LocalStore
38 | Secret5 Hashtable LocalStore
39 | Secret6 ByteArray CredMan
40 | ```
41 |
42 | This example runs the command with the 'Name' parameter argument being a single wildcard character.
43 | So all metadata for all stored secrets is returned.
44 | There are two registered vaults, LocalStore and CredMan.
45 | There are six secrets metadata information returned over the two vaults.
46 |
47 | ### Example 2
48 | ```powershell
49 | PS C:\> Get-SecretInfo -Name APIKey | Select-Object Name,VaultName,Metadata
50 |
51 | Name VaultName Metadata
52 | ---- --------- --------
53 | APIKey SecretStore {[Target, PSGallery]}
54 | ```
55 |
56 | This example runs the command for a single secret name and displays the secret name, the vault name, and any metadata associated with the secret.
57 |
58 | ## PARAMETERS
59 |
60 | ### -Name
61 | This parameter takes a String argument, including wildcard characters.
62 | It is used to filter the search results that match on secret names the provided name pattern.
63 | If no 'Name' parameter argument is provided, then all stored secret metadata is returned.
64 |
65 | ```yaml
66 | Type: String
67 | Parameter Sets: (All)
68 | Aliases:
69 |
70 | Required: False
71 | Position: 0
72 | Default value: None
73 | Accept pipeline input: False
74 | Accept wildcard characters: True
75 | ```
76 |
77 | ### -Vault
78 | Optional parameter which takes a String argument that specifies a single vault to search.
79 |
80 | ```yaml
81 | Type: String
82 | Parameter Sets: (All)
83 | Aliases:
84 |
85 | Required: False
86 | Position: 1
87 | Default value: None
88 | Accept pipeline input: False
89 | Accept wildcard characters: False
90 | ```
91 |
92 | ### CommonParameters
93 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
94 |
95 | ## INPUTS
96 |
97 | ### None
98 | ## OUTPUTS
99 |
100 | ### Microsoft.PowerShell.SecretManagement.SecretInformation
101 | ## NOTES
102 |
103 | ## RELATED LINKS
104 |
--------------------------------------------------------------------------------
/help/Get-SecretVault.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Get-SecretVault
9 |
10 | ## SYNOPSIS
11 | Finds and returns registered vault information.
12 |
13 | ## SYNTAX
14 |
15 | ```
16 | Get-SecretVault [[-Name] ] []
17 | ```
18 |
19 | ## DESCRIPTION
20 | This cmdlet finds and returns information of registered vaults.
21 | It takes an array of vault name strings, which can contain wildcard characters.
22 | If no 'Name' parameter is specified, all registered vault information is returned.
23 | The registered vault information includes the vault name, vault implementing module name, and optional default parameters.
24 |
25 | ## EXAMPLES
26 |
27 | ### Example 1
28 | ```
29 | PS C:\> Get-SecretVault
30 |
31 | VaultName ModuleName IsDefaultVault
32 | --------- ---------- --------------
33 | CredMan Microsoft.PowerShell.CredManStore False
34 | LocalStore Microsoft.PowerShell.SecretStore True
35 | ```
36 |
37 | This example runs the command without any parameter arguments, and so returns information on all registered vaults.
38 | The 'LocalStore' vault is shown to be set as the default vault.
39 |
40 | ## PARAMETERS
41 |
42 | ### -Name
43 | This parameter takes a String argument, including wildcard characters.
44 | It is used to filter the search results on vault names that match the provided name pattern.
45 |
46 | ```yaml
47 | Type: String[]
48 | Parameter Sets: (All)
49 | Aliases:
50 |
51 | Required: False
52 | Position: 0
53 | Default value: None
54 | Accept pipeline input: False
55 | Accept wildcard characters: True
56 | ```
57 |
58 | ### CommonParameters
59 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
60 |
61 | ## INPUTS
62 |
63 | ### None
64 | ## OUTPUTS
65 |
66 | ### Microsoft.PowerShell.SecretManagement.SecretVaultInfo
67 | ## NOTES
68 |
69 | ## RELATED LINKS
70 |
--------------------------------------------------------------------------------
/help/Register-SecretVault.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Register-SecretVault
9 |
10 | ## SYNOPSIS
11 | Registers a SecretManagement extension vault module for the current user.
12 |
13 | ## SYNTAX
14 |
15 | ```
16 | Register-SecretVault [-ModuleName] [[-Name] ] [-VaultParameters ] [-DefaultVault]
17 | [-AllowClobber] [-PassThru] [-Description ] [-WhatIf] [-Confirm] []
18 | ```
19 |
20 | ## DESCRIPTION
21 | This cmdlet adds a provided SecretManagement extension vault module to the current user vault registry.
22 | An extension vault module is a PowerShell module that conforms to the required extension vault format.
23 | This cmdlet will first verify that the provided module meets conformance requirements, and then add it to the extension vault registry.
24 | Extension vaults are registered to the current user and do not affect other user vault registrations.
25 |
26 | ## EXAMPLES
27 |
28 | ### Example 1
29 | ```powershell
30 | PS C:\> Register-SecretVault -Name LocalStore -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
31 | PS C:\> Get-SecretVault
32 |
33 | VaultName ModuleName IsDefaultVault
34 | --------- ---------- --------------
35 | CredMan Microsoft.PowerShell.CredManStore False
36 | LocalStore Microsoft.PowerShell.SecretStore True
37 | ```
38 |
39 | This example registers the Microsoft.PowerShell.SecretStore extension vault module for the current user.
40 | The 'Microsoft.PowerShell.SecretStore' is installed in a known PowerShell module path, so just the module name is needed.
41 | It uses the 'DefaultVault' parameter switch to make it the default module for the user.
42 | The 'Get-SecretVault' command is run next to list all registered vaults for the user, and verifies the vault was registered and set as the default vault.
43 |
44 | ## PARAMETERS
45 |
46 | ### -AllowClobber
47 | When used this parameter will overwrite an existing registered extension vault with the same name.
48 |
49 | ```yaml
50 | Type: SwitchParameter
51 | Parameter Sets: (All)
52 | Aliases:
53 |
54 | Required: False
55 | Position: Named
56 | Default value: False
57 | Accept pipeline input: False
58 | Accept wildcard characters: False
59 | ```
60 |
61 | ### -DefaultVault
62 | This parameter switch makes the new extension vault the default vault for the current user.
63 |
64 | ```yaml
65 | Type: SwitchParameter
66 | Parameter Sets: (All)
67 | Aliases:
68 |
69 | Required: False
70 | Position: Named
71 | Default value: False
72 | Accept pipeline input: False
73 | Accept wildcard characters: False
74 | ```
75 |
76 | ### -Description
77 | This parameter takes a description string that is included in the vault registry information.
78 |
79 | ```yaml
80 | Type: String
81 | Parameter Sets: (All)
82 | Aliases:
83 |
84 | Required: False
85 | Position: Named
86 | Default value: None
87 | Accept pipeline input: False
88 | Accept wildcard characters: False
89 | ```
90 |
91 | ### -ModuleName
92 | Name of the PowerShell module that implements the extension vault.
93 | It can be a simple name, in which case PowerShell will search for it in its known module paths.
94 | Alternatively, a pathname can be provided and PowerShell will look in the specific path for the module.
95 |
96 | ```yaml
97 | Type: String
98 | Parameter Sets: (All)
99 | Aliases:
100 |
101 | Required: True
102 | Position: 1
103 | Default value: None
104 | Accept pipeline input: False
105 | Accept wildcard characters: False
106 | ```
107 |
108 | ### -Name
109 | Name of the extension vault to be registered.
110 | If no name is provide, the module name will be used.
111 |
112 | ```yaml
113 | Type: String
114 | Parameter Sets: (All)
115 | Aliases:
116 |
117 | Required: False
118 | Position: 0
119 | Default value: None
120 | Accept pipeline input: False
121 | Accept wildcard characters: False
122 | ```
123 |
124 | ### -PassThru
125 | When used this parameter will return the SecretVaultInfo object for the successfully registered extension vault.
126 |
127 | ```yaml
128 | Type: SwitchParameter
129 | Parameter Sets: (All)
130 | Aliases:
131 |
132 | Required: False
133 | Position: Named
134 | Default value: False
135 | Accept pipeline input: False
136 | Accept wildcard characters: False
137 | ```
138 |
139 | ### -VaultParameters
140 | This takes a hashtable object that contains optional parameter name-value pairs needed by the extension vault.
141 | These optional parameters are provided to the extension vault when invoked.
142 |
143 | ```yaml
144 | Type: Hashtable
145 | Parameter Sets: (All)
146 | Aliases:
147 |
148 | Required: False
149 | Position: Named
150 | Default value: None
151 | Accept pipeline input: False
152 | Accept wildcard characters: False
153 | ```
154 |
155 | ### -Confirm
156 | Prompts you for confirmation before running the cmdlet.
157 |
158 | ```yaml
159 | Type: SwitchParameter
160 | Parameter Sets: (All)
161 | Aliases: cf
162 |
163 | Required: False
164 | Position: Named
165 | Default value: False
166 | Accept pipeline input: False
167 | Accept wildcard characters: False
168 | ```
169 |
170 | ### -WhatIf
171 | Shows what would happen if the cmdlet runs.
172 | The cmdlet is not run.
173 |
174 | ```yaml
175 | Type: SwitchParameter
176 | Parameter Sets: (All)
177 | Aliases: wi
178 |
179 | Required: False
180 | Position: Named
181 | Default value: False
182 | Accept pipeline input: False
183 | Accept wildcard characters: False
184 | ```
185 |
186 | ### CommonParameters
187 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
188 |
189 | ## INPUTS
190 |
191 | ### None
192 | ## OUTPUTS
193 |
194 | ## NOTES
195 |
196 | ## RELATED LINKS
197 |
--------------------------------------------------------------------------------
/help/Remove-Secret.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Remove-Secret
9 |
10 | ## SYNOPSIS
11 | Removes a secret from a specified registered extension vault.
12 |
13 | ## SYNTAX
14 |
15 | ### NameParameterSet
16 | ```
17 | Remove-Secret [-Name] [-Vault] [-WhatIf] [-Confirm] []
18 | ```
19 |
20 | ### InfoParameterSet
21 | ```
22 | Remove-Secret [-InputObject] [-WhatIf] [-Confirm] []
23 | ```
24 |
25 | ## DESCRIPTION
26 | This cmdlet will remove a secret by name from a registered extension vault.
27 | Both the secret name and extension vault name must be provided.
28 |
29 | ## EXAMPLES
30 |
31 | ### Example 1
32 | ```powershell
33 | PS C:\> Remove-Secret -Name secretTest -Vault CredMan
34 | PS C:\> Get-Secret -Name secretTest -Vault CredMan
35 | Get-Secret: The secret secretTest was not found.
36 | ```
37 |
38 | This example runs the command to remove the secret 'secretTest' from the CredMan vault.
39 | The 'Get-Secret' command is next run to verify the secret no longer exists in the vault.
40 |
41 | ### Example 2
42 | ```
43 | PS C:\> Get-SecretInfo -Name Secret2 -Vault CredMan | Remove-Secret
44 | PS C:\> Get-Secret -Name Secret2 -Vault CredMan
45 | Get-Secret: The secret Secret2 was not found.
46 | ```
47 |
48 | This example first obtains secret information for the 'Secret2' secret and pipes the results to this command.
49 | Remove-Secret then removes the secret from the vault using the piped in secret information.
50 |
51 | ## PARAMETERS
52 |
53 | ### -InputObject
54 | SecretInformation object that describes a vault secret.
55 |
56 | ```yaml
57 | Type: SecretInformation
58 | Parameter Sets: InfoParameterSet
59 | Aliases:
60 |
61 | Required: True
62 | Position: 0
63 | Default value: None
64 | Accept pipeline input: True (ByValue)
65 | Accept wildcard characters: False
66 | ```
67 |
68 | ### -Name
69 | Name of the secret to remove.
70 |
71 | ```yaml
72 | Type: String
73 | Parameter Sets: NameParameterSet
74 | Aliases:
75 |
76 | Required: True
77 | Position: 0
78 | Default value: None
79 | Accept pipeline input: True (ByValue)
80 | Accept wildcard characters: False
81 | ```
82 |
83 | ### -Vault
84 | Name of the vault from which the secret is to be removed.
85 |
86 | ```yaml
87 | Type: String
88 | Parameter Sets: NameParameterSet
89 | Aliases:
90 |
91 | Required: True
92 | Position: 1
93 | Default value: None
94 | Accept pipeline input: False
95 | Accept wildcard characters: False
96 | ```
97 |
98 | ### -Confirm
99 | Prompts you for confirmation before running the cmdlet.
100 |
101 | ```yaml
102 | Type: SwitchParameter
103 | Parameter Sets: (All)
104 | Aliases: cf
105 |
106 | Required: False
107 | Position: Named
108 | Default value: False
109 | Accept pipeline input: False
110 | Accept wildcard characters: False
111 | ```
112 |
113 | ### -WhatIf
114 | Shows what would happen if the cmdlet runs.
115 | The cmdlet is not run.
116 |
117 | ```yaml
118 | Type: SwitchParameter
119 | Parameter Sets: (All)
120 | Aliases: wi
121 |
122 | Required: False
123 | Position: Named
124 | Default value: False
125 | Accept pipeline input: False
126 | Accept wildcard characters: False
127 | ```
128 |
129 | ### CommonParameters
130 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
131 |
132 | ## INPUTS
133 |
134 | ### System.String
135 | ### Microsoft.PowerShell.SecretManagement.SecretInformation
136 | ## OUTPUTS
137 |
138 | ## NOTES
139 |
140 | ## RELATED LINKS
141 |
--------------------------------------------------------------------------------
/help/Set-Secret.md:
--------------------------------------------------------------------------------
1 | ---
2 | external help file: Microsoft.PowerShell.SecretManagement.dll-Help.xml
3 | Module Name: Microsoft.PowerShell.SecretManagement
4 | online version:
5 | schema: 2.0.0
6 | ---
7 |
8 | # Set-Secret
9 |
10 | ## SYNOPSIS
11 | Adds a secret to a SecretManagement registered vault.
12 |
13 | ## SYNTAX
14 |
15 | ### SecureStringParameterSet (Default)
16 | ```
17 | Set-Secret [-Name] -SecureStringSecret [[-Vault] ] [[-Metadata] ]
18 | [-NoClobber] [-WhatIf] [-Confirm] []
19 | ```
20 |
21 | ### ObjectParameterSet
22 | ```
23 | Set-Secret [-Name] -Secret