Add support for SecretManagement and SecretStore providers, enhance configuration data handling, and introduce new utility functions

This commit is contained in:
Torsten Brendgen
2026-07-02 23:57:14 +02:00
parent 115b8be385
commit 9b36693444
16 changed files with 979 additions and 7 deletions

View File

@@ -0,0 +1,247 @@
function Register-DSCConfigurationDataCredentialProvider {
[CmdletBinding(SupportsShouldProcess=$true)]
Param(
[Parameter(Mandatory=$true)]
[string]
$Vault,
[Parameter(Mandatory=$false)]
[string]
$KeyPath,
[Parameter(Mandatory=$false)]
[string]
$SettingsPath,
[Parameter(Mandatory=$false)]
[System.Security.SecureString]
$MasterKey,
[Parameter(Mandatory=$false)]
[string]
$ModuleName,
[Parameter(Mandatory=$false)]
[hashtable]
$VaultParameters = @{},
[Parameter(Mandatory=$false)]
[switch]
$RegisterVault,
[Parameter(Mandatory=$false)]
[switch]
$DefaultVault,
[Parameter(Mandatory=$false)]
[switch]
$AllowClobber,
[Parameter(Mandatory=$false)]
[switch]
$ConfigureSecretStore,
[Parameter(Mandatory=$false)]
[ValidateSet("None", "Password")]
[string]
$Authentication = "None",
[Parameter(Mandatory=$false)]
[ValidateSet("None", "Prompt")]
[string]
$Interaction = "None",
[Parameter(Mandatory=$false)]
[System.Security.SecureString]
$Password,
[Parameter(Mandatory=$false)]
[int]
$PasswordTimeout,
[Parameter(Mandatory=$false)]
[switch]
$Force,
[Parameter(Mandatory=$false)]
[switch]
$PassThru
)
DynamicParam {
$ProviderNames = @(Get-ConfigurationDataSecretProviderName)
if($ProviderNames.Count -eq 0){
$ProviderNames = @("__NoProvidersRegistered__")
}
$ParameterAttribute = [System.Management.Automation.ParameterAttribute]::new()
$ParameterAttribute.Mandatory = $false
$ParameterAttribute.Position = 0
$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList (,[string[]]$ProviderNames)
$Attributes = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$Attributes.Add($ParameterAttribute)
$Attributes.Add($ValidateSetAttribute)
$RuntimeParameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
"Provider",
[string],
$Attributes
)
$Dictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$Dictionary.Add("Provider", $RuntimeParameter)
return $Dictionary
}
begin {
$Provider = [string]$PSBoundParameters["Provider"]
if([string]::IsNullOrWhiteSpace($Provider)){
$ProviderNames = @(Get-ConfigurationDataSecretProviderName)
if($ProviderNames.Count -eq 1){
$Provider = $ProviderNames[0]
}elseif($ProviderNames.Count -eq 0){
throw "No configuration data secret providers are registered."
}else{
throw "Provider is required. Registered providers: $($ProviderNames -join ', ')."
}
}
$SettingsPath = Resolve-ConfigurationDataProviderSettingsPath -Provider $Provider -SettingsPath $SettingsPath
}
process {
switch($Provider){
"KeePass" {
if([string]::IsNullOrWhiteSpace($KeyPath)){
throw "Provider [KeePass] requires [KeyPath]."
}
if($null -eq $MasterKey){
$MasterKey = Read-Host -Prompt "KeePass MasterKey for vault [$Vault]" -AsSecureString
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
$Key = New-ConfigurationDataAesKeyFile -Path $KeyPath -Force:$Force
$ProtectedValue = $MasterKey | ConvertFrom-SecureString -Key $Key
$ProviderSettings = [ordered]@{
KeePass = [ordered]@{
DefaultVault = $Vault
MasterKey = [ordered]@{
ProtectedValue = $ProtectedValue
KeyPath = $KeyPath
}
}
}
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
if($PassThru){
return $ProviderSettings
}
Write-Verbose "Provider settings written to [$SettingsPath]."
}
}
"SecretManagement" {
if([string]::IsNullOrWhiteSpace($ModuleName)){
$ModuleName = "Microsoft.PowerShell.SecretStore"
}
if($RegisterVault -or $PSBoundParameters.ContainsKey("ModuleName")){
$CommandParameters = @{
Name = $Vault
ModuleName = $ModuleName
}
if($VaultParameters.Count -gt 0){
$CommandParameters["VaultParameters"] = $VaultParameters
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
}
if($PSCmdlet.ShouldProcess($Vault, "Register SecretManagement vault [$ModuleName]")){
Register-SecretVault @CommandParameters
}
}
$ProviderSettings = [ordered]@{
SecretManagement = [ordered]@{
DefaultVault = $Vault
}
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
}
if($PassThru){
return $ProviderSettings
}
}
"SecretStore" {
if($ConfigureSecretStore){
$CommandParameters = @{
Authentication = $Authentication
Interaction = $Interaction
}
if($null -ne $Password){
$CommandParameters["Password"] = $Password
}
if($PasswordTimeout -gt 0){
$CommandParameters["PasswordTimeout"] = $PasswordTimeout
}
if($PSCmdlet.ShouldProcess("SecretStore", "Configure local SecretStore")){
Set-SecretStoreConfiguration @CommandParameters -Confirm:$false
}
}
if($RegisterVault){
$CommandParameters = @{
Name = $Vault
ModuleName = "Microsoft.PowerShell.SecretStore"
}
if($DefaultVault){
$CommandParameters["DefaultVault"] = $true
}
if($AllowClobber){
$CommandParameters["AllowClobber"] = $true
}
if($PSCmdlet.ShouldProcess($Vault, "Register SecretStore vault")){
Register-SecretVault @CommandParameters
}
}
$ProviderSettings = [ordered]@{
SecretStore = [ordered]@{
DefaultVault = $Vault
}
}
if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){
Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force
}
if($PassThru){
return $ProviderSettings
}
}
default {
throw "Provider [$Provider] does not provide an initialization implementation."
}
}
}
}