From 45e71c093c878aa05da5086a3fffbdb923dc4b3c Mon Sep 17 00:00:00 2001 From: Torsten Brendgen Date: Mon, 6 Jul 2026 22:50:39 +0200 Subject: [PATCH] Refactor secret management providers and introduce unified handling - Removed KeePass and SecretStore provider implementations. - Integrated KeePass and SecretStore as vaults under the SecretManagement provider. - Added new functions: Get-DSCConfigurationDataCredentialProvider and Set-DSCConfigurationDataCredentialProvider for managing credential providers. - Implemented Unlock-ConfigurationDataSecretManagementVault to handle vault unlocking with master passwords. - Updated README to reflect changes in provider usage and examples. - Enhanced error handling and validation for vault registration and settings. --- ...ConfigurationDataSecretManagementVault.ps1 | 49 ++++ Providers/Provider.AzureKeyVault.ps1 | 94 ------- Providers/Provider.KeePass.ps1 | 88 ------ Providers/Provider.SecretStore.ps1 | 57 ---- ...DSCConfigurationDataCredentialProvider.ps1 | 119 ++++++++ ...DSCConfigurationDataCredentialProvider.ps1 | 247 +++++++---------- Public/Resolve-DSCConfigurationData.ps1 | 1 + ...DSCConfigurationDataCredentialProvider.ps1 | 258 ++++++++++++++++++ ...DSCConfigurationDataCredentialProvider.ps1 | 48 +--- Readme.md | 191 +++++-------- Resolve-DSCConfigurationData.psd1 | 4 +- Resolve-DSCConfigurationData.psm1 | 2 + 12 files changed, 608 insertions(+), 550 deletions(-) create mode 100644 Private/Unlock-ConfigurationDataSecretManagementVault.ps1 delete mode 100644 Providers/Provider.AzureKeyVault.ps1 delete mode 100644 Providers/Provider.KeePass.ps1 delete mode 100644 Providers/Provider.SecretStore.ps1 create mode 100644 Public/Get-DSCConfigurationDataCredentialProvider.ps1 create mode 100644 Public/Set-DSCConfigurationDataCredentialProvider.ps1 diff --git a/Private/Unlock-ConfigurationDataSecretManagementVault.ps1 b/Private/Unlock-ConfigurationDataSecretManagementVault.ps1 new file mode 100644 index 0000000..7d50345 --- /dev/null +++ b/Private/Unlock-ConfigurationDataSecretManagementVault.ps1 @@ -0,0 +1,49 @@ +function Unlock-ConfigurationDataSecretManagementVault { + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false)] + [hashtable] + $ProviderSettings = @{} + ) + + if(-not $ProviderSettings.ContainsKey("SecretManagement")){ + return + } + + $SecretManagementSettings = $ProviderSettings.SecretManagement + if(-not ($SecretManagementSettings -is [System.Collections.IDictionary])){ + return + } + + if(-not (Test-ConfigurationDataMapContainsKey -Map $SecretManagementSettings -Key "MasterPassword")){ + return + } + + $Vault = [string](Get-ConfigurationDataMapValue -Map $SecretManagementSettings -Key "DefaultVault" -DefaultValue "") + if([string]::IsNullOrWhiteSpace($Vault)){ + throw "SecretManagement provider settings define [MasterPassword], but [DefaultVault] is not defined." + } + + $UnlockSecretVaultCommand = Get-Command -Name Unlock-SecretVault -ErrorAction SilentlyContinue + if($null -eq $UnlockSecretVaultCommand){ + throw "Command [Unlock-SecretVault] was not found. Install module [Microsoft.PowerShell.SecretManagement]." + } + + $MasterPassword = Resolve-ConfigurationDataProviderSecureString -Value $SecretManagementSettings.MasterPassword + & $UnlockSecretVaultCommand -Name $Vault -Password $MasterPassword + + $TestSecretVaultCommand = Get-Command -Name Test-SecretVault -ErrorAction SilentlyContinue + if($null -ne $TestSecretVaultCommand){ + $IsUnlocked = $false + try { + $IsUnlocked = [bool](& $TestSecretVaultCommand -Name $Vault -ErrorAction Stop) + } + catch { + throw "SecretManagement vault [$Vault] could not be unlocked. $($_.Exception.Message)" + } + + if(-not $IsUnlocked){ + throw "SecretManagement vault [$Vault] could not be unlocked. Verify the KeePass database path, KeePass key file, and protected master password in the provider settings." + } + } +} diff --git a/Providers/Provider.AzureKeyVault.ps1 b/Providers/Provider.AzureKeyVault.ps1 deleted file mode 100644 index 65452d7..0000000 --- a/Providers/Provider.AzureKeyVault.ps1 +++ /dev/null @@ -1,94 +0,0 @@ -$AzureKeyVaultProvider = @{ - Name = "AzureKeyVault" - SupportedTypes = @( - "credential", - "securestring", - "string" - ) - Resolver = { - Param( - [Parameter(Mandatory=$true)] - [System.Collections.IDictionary] - $Reference, - - [Parameter(Mandatory=$true)] - [ValidateSet("credential", "securestring", "string")] - [string] - $ExpectedType, - - [Parameter(Mandatory=$false)] - [hashtable] - $ProviderSettings = @{} - ) - - $GetSecretCommand = Get-Command -Name Get-AzKeyVaultSecret -ErrorAction SilentlyContinue - if($null -eq $GetSecretCommand){ - throw "AzureKeyVault provider requires the module [Az.KeyVault] and command [Get-AzKeyVaultSecret]." - } - - $Vault = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Vault" -DefaultValue "") - $Name = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Name") - $UserName = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "UserName" -DefaultValue "") - $Options = Get-ConfigurationDataMapValue -Map $Reference -Key "Options" -DefaultValue @{} - - if([string]::IsNullOrWhiteSpace($Vault) -and $ProviderSettings.ContainsKey("DefaultVault")){ - $Vault = [string]$ProviderSettings.DefaultVault - } - - if([string]::IsNullOrWhiteSpace($Vault)){ - throw "AzureKeyVault secret [$Name] requires [Vault] or provider setting [DefaultVault]." - } - - if($ProviderSettings.ContainsKey("SubscriptionId") -or $ProviderSettings.ContainsKey("TenantId")){ - $SetContextCommand = Get-Command -Name Set-AzContext -ErrorAction SilentlyContinue - if($null -eq $SetContextCommand){ - throw "AzureKeyVault provider settings define Azure context values, but command [Set-AzContext] was not found. Install [Az.Accounts] or remove SubscriptionId/TenantId from provider settings." - } - - $ContextParameters = @{} - if($ProviderSettings.ContainsKey("SubscriptionId") -and -not [string]::IsNullOrWhiteSpace([string]$ProviderSettings.SubscriptionId)){ - $ContextParameters["SubscriptionId"] = [string]$ProviderSettings.SubscriptionId - } - - if($ProviderSettings.ContainsKey("TenantId") -and -not [string]::IsNullOrWhiteSpace([string]$ProviderSettings.TenantId)){ - $ContextParameters["Tenant"] = [string]$ProviderSettings.TenantId - } - - if($ContextParameters.Count -gt 0){ - & $SetContextCommand @ContextParameters | Out-Null - } - } - - $CommandParameters = @{ - VaultName = $Vault - Name = $Name - } - - if($Options -is [System.Collections.IDictionary]){ - foreach($Key in $Options.Keys){ - $CommandParameters[$Key] = $Options[$Key] - } - } - - if($ExpectedType -eq "string" -and $GetSecretCommand.Parameters.ContainsKey("AsPlainText") -and -not $CommandParameters.ContainsKey("AsPlainText")){ - $CommandParameters["AsPlainText"] = $true - } - - $Secret = & $GetSecretCommand @CommandParameters - if($null -eq $Secret){ - throw "Azure Key Vault secret [$Name] was not found in vault [$Vault]." - } - - if($ExpectedType -eq "string" -and $Secret -is [string]){ - return $Secret - } - - if($Secret.PSObject.Properties["SecretValue"]){ - return ConvertFrom-ConfigurationDataSecretValue -Secret $Secret.SecretValue -ExpectedType $ExpectedType -Name $Name -UserName $UserName - } - - return ConvertFrom-ConfigurationDataSecretValue -Secret $Secret -ExpectedType $ExpectedType -Name $Name -UserName $UserName - } -} - -Register-ConfigurationDataSecretProvider @AzureKeyVaultProvider diff --git a/Providers/Provider.KeePass.ps1 b/Providers/Provider.KeePass.ps1 deleted file mode 100644 index 4ebdf94..0000000 --- a/Providers/Provider.KeePass.ps1 +++ /dev/null @@ -1,88 +0,0 @@ -$KeePassProvider = @{ - Name = "KeePass" - SupportedTypes = @( - "credential", - "securestring", - "string" - ) - Resolver = { - Param( - [Parameter(Mandatory=$true)] - [System.Collections.IDictionary] - $Reference, - - [Parameter(Mandatory=$true)] - [ValidateSet("credential", "securestring", "string")] - [string] - $ExpectedType, - - [Parameter(Mandatory=$false)] - [hashtable] - $ProviderSettings = @{} - ) - - $KeePassCommand = Get-Command -Name Get-KeePassEntry -ErrorAction SilentlyContinue - if($null -eq $KeePassCommand){ - throw "KeePass provider requires the [PoShKeePass] module command [Get-KeePassEntry]." - } - - $Vault = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Vault" -DefaultValue "") - $Name = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Name") - $Options = Get-ConfigurationDataMapValue -Map $Reference -Key "Options" -DefaultValue @{} - - if([string]::IsNullOrWhiteSpace($Vault) -and $ProviderSettings.ContainsKey("DefaultVault")){ - $Vault = [string]$ProviderSettings.DefaultVault - } - - $CommandParameters = @{} - if(-not [string]::IsNullOrWhiteSpace($Vault)){ - $CommandParameters["DatabaseProfileName"] = $Vault - } - - if($Options -is [System.Collections.IDictionary]){ - foreach($Key in $Options.Keys){ - $CommandParameters[$Key] = $Options[$Key] - } - } - - if($ProviderSettings.ContainsKey("MasterKey")){ - $CommandParameters["MasterKey"] = Resolve-ConfigurationDataProviderSecureString -Value $ProviderSettings.MasterKey - } - - if(-not $CommandParameters.ContainsKey("Title") -and -not $CommandParameters.ContainsKey("Path")){ - $CommandParameters["Title"] = $Name - } - - $Entry = & $KeePassCommand @CommandParameters - if($null -eq $Entry){ - throw "KeePass entry [$Name] was not found." - } - - $Entry = @($Entry)[0] - $UserName = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "UserName" -DefaultValue "") - if([string]::IsNullOrWhiteSpace($UserName)){ - $UserName = [string]$Entry.UserName - } - - $Password = $Entry.Password - if($ExpectedType -eq "credential"){ - if([string]::IsNullOrWhiteSpace($UserName)){ - throw "KeePass entry [$Name] does not provide a username and no [UserName] override was defined." - } - - return ConvertTo-ConfigurationDataCredential -UserName $UserName -Password $Password - } - - if($Password -is [System.Security.SecureString]){ - return $Password - } - - if($ExpectedType -eq "securestring"){ - return ConvertTo-SecureString -String ([string]$Password) -AsPlainText -Force - } - - return [string]$Password - } -} - -Register-ConfigurationDataSecretProvider @KeePassProvider diff --git a/Providers/Provider.SecretStore.ps1 b/Providers/Provider.SecretStore.ps1 deleted file mode 100644 index e94fa94..0000000 --- a/Providers/Provider.SecretStore.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -$SecretStoreProvider = @{ - Name = "SecretStore" - SupportedTypes = @( - "credential", - "securestring", - "string" - ) - Resolver = { - Param( - [Parameter(Mandatory=$true)] - [System.Collections.IDictionary] - $Reference, - - [Parameter(Mandatory=$true)] - [ValidateSet("credential", "securestring", "string")] - [string] - $ExpectedType, - - [Parameter(Mandatory=$false)] - [hashtable] - $ProviderSettings = @{} - ) - - $GetSecretCommand = Get-Command -Name Get-Secret -ErrorAction SilentlyContinue - if($null -eq $GetSecretCommand){ - throw "SecretStore provider requires the module [Microsoft.PowerShell.SecretManagement] and command [Get-Secret]." - } - - $Vault = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Vault" -DefaultValue "") - $Name = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Name") - $UserName = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "UserName" -DefaultValue "") - $Options = Get-ConfigurationDataMapValue -Map $Reference -Key "Options" -DefaultValue @{} - - if([string]::IsNullOrWhiteSpace($Vault) -and $ProviderSettings.ContainsKey("DefaultVault")){ - $Vault = [string]$ProviderSettings.DefaultVault - } - - $CommandParameters = @{ - Name = $Name - } - - if(-not [string]::IsNullOrWhiteSpace($Vault)){ - $CommandParameters["Vault"] = $Vault - } - - if($Options -is [System.Collections.IDictionary]){ - foreach($Key in $Options.Keys){ - $CommandParameters[$Key] = $Options[$Key] - } - } - - $Secret = & $GetSecretCommand @CommandParameters - return ConvertFrom-ConfigurationDataSecretValue -Secret $Secret -ExpectedType $ExpectedType -Name $Name -UserName $UserName - } -} - -Register-ConfigurationDataSecretProvider @SecretStoreProvider diff --git a/Public/Get-DSCConfigurationDataCredentialProvider.ps1 b/Public/Get-DSCConfigurationDataCredentialProvider.ps1 new file mode 100644 index 0000000..04d367e --- /dev/null +++ b/Public/Get-DSCConfigurationDataCredentialProvider.ps1 @@ -0,0 +1,119 @@ +function Get-DSCConfigurationDataCredentialProvider { + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false)] + [string] + $Vault, + + [Parameter(Mandatory=$false)] + [string] + $SettingsPath, + + [Parameter(Mandatory=$false)] + [switch] + $TestVault + ) + + 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 ', ')." + } + } + + $ResolvedSettingsPath = Resolve-ConfigurationDataProviderSettingsPath -Provider $Provider -SettingsPath $SettingsPath + } + + process { + $Settings = @{} + $SettingsExists = Test-Path -LiteralPath $ResolvedSettingsPath -PathType Leaf + if($SettingsExists){ + $Settings = Import-PowerShellDataFile -LiteralPath $ResolvedSettingsPath + } + + $ProviderSettings = @{} + if($Settings -is [System.Collections.IDictionary] -and $Settings.ContainsKey($Provider)){ + $ProviderSettings = $Settings[$Provider] + } + + $DefaultVault = "" + if($ProviderSettings -is [System.Collections.IDictionary] -and $ProviderSettings.ContainsKey("DefaultVault")){ + $DefaultVault = [string]$ProviderSettings.DefaultVault + } + + if([string]::IsNullOrWhiteSpace($Vault)){ + $Vault = $DefaultVault + } + + $Vaults = @() + $GetSecretVaultCommand = Get-Command -Name Get-SecretVault -ErrorAction SilentlyContinue + if($null -ne $GetSecretVaultCommand){ + if([string]::IsNullOrWhiteSpace($Vault)){ + $Vaults = @(& $GetSecretVaultCommand) + }else{ + $Vaults = @(& $GetSecretVaultCommand -Name $Vault -ErrorAction SilentlyContinue) + } + } + + $TestResult = $null + $TestError = $null + if($TestVault -and -not [string]::IsNullOrWhiteSpace($Vault)){ + $TestSecretVaultCommand = Get-Command -Name Test-SecretVault -ErrorAction SilentlyContinue + if($null -eq $TestSecretVaultCommand){ + $TestError = "Command [Test-SecretVault] was not found." + }else{ + try { + $TestResult = [bool](& $TestSecretVaultCommand -Name $Vault -ErrorAction Stop) + } + catch { + $TestResult = $false + $TestError = $_.Exception.Message + } + } + } + + [PSCustomObject]@{ + Provider = $Provider + SettingsPath = $ResolvedSettingsPath + SettingsExists = $SettingsExists + DefaultVault = $DefaultVault + RequestedVault = $Vault + ProviderSettings = $ProviderSettings + RegisteredVaults = $Vaults + TestVault = $TestResult + TestError = $TestError + } + } +} diff --git a/Public/Register-DSCConfigurationDataCredentialProvider.ps1 b/Public/Register-DSCConfigurationDataCredentialProvider.ps1 index c918dcb..9369773 100644 --- a/Public/Register-DSCConfigurationDataCredentialProvider.ps1 +++ b/Public/Register-DSCConfigurationDataCredentialProvider.ps1 @@ -1,10 +1,19 @@ function Register-DSCConfigurationDataCredentialProvider { [CmdletBinding(SupportsShouldProcess=$true)] Param( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory=$true, Position=1)] [string] $Vault, + [Parameter(Mandatory=$false)] + [ValidateSet("Generic", "KeePass")] + [string] + $VaultType = "Generic", + + [Parameter(Mandatory=$false)] + [string] + $DatabasePath, + [Parameter(Mandatory=$false)] [string] $KeyPath, @@ -13,10 +22,6 @@ function Register-DSCConfigurationDataCredentialProvider { [string] $SettingsPath, - [Parameter(Mandatory=$false)] - [System.Security.SecureString] - $MasterKey, - [Parameter(Mandatory=$false)] [string] $ModuleName, @@ -25,14 +30,6 @@ function Register-DSCConfigurationDataCredentialProvider { [hashtable] $VaultParameters = @{}, - [Parameter(Mandatory=$false)] - [string] - $SubscriptionId, - - [Parameter(Mandatory=$false)] - [string] - $TenantId, - [Parameter(Mandatory=$false)] [switch] $RegisterVault, @@ -47,25 +44,17 @@ function Register-DSCConfigurationDataCredentialProvider { [Parameter(Mandatory=$false)] [switch] - $ConfigureSecretStore, - - [Parameter(Mandatory=$false)] - [ValidateSet("None", "Password")] - [string] - $Authentication = "None", - - [Parameter(Mandatory=$false)] - [ValidateSet("None", "Prompt")] - [string] - $Interaction = "None", + $UseMasterPassword, [Parameter(Mandatory=$false)] + [Alias("MasterKey")] [System.Security.SecureString] - $Password, + $MasterPassword, [Parameter(Mandatory=$false)] - [int] - $PasswordTimeout, + [Alias("MasterKeyPath")] + [string] + $MasterPasswordKeyPath, [Parameter(Mandatory=$false)] [switch] @@ -120,63 +109,98 @@ function Register-DSCConfigurationDataCredentialProvider { 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($VaultType -eq "KeePass"){ + $ModuleName = "SecretManagement.KeePass" + }else{ + $ModuleName = "Microsoft.PowerShell.SecretStore" + } } - if($RegisterVault -or $PSBoundParameters.ContainsKey("ModuleName")){ - $CommandParameters = @{ - Name = $Vault - ModuleName = $ModuleName + $ShouldRegisterVault = $RegisterVault -or $PSBoundParameters.ContainsKey("ModuleName") + + if($VaultType -eq "KeePass" -and $ShouldRegisterVault){ + if([string]::IsNullOrWhiteSpace($DatabasePath) -and -not $VaultParameters.ContainsKey("Path")){ + throw "SecretManagement KeePass vault registration requires [DatabasePath] or VaultParameters['Path']." } - if($VaultParameters.Count -gt 0){ - $CommandParameters["VaultParameters"] = $VaultParameters + if(-not [string]::IsNullOrWhiteSpace($DatabasePath)){ + $VaultParameters["Path"] = $DatabasePath } - if($DefaultVault){ - $CommandParameters["DefaultVault"] = $true + if(-not [string]::IsNullOrWhiteSpace($KeyPath)){ + $VaultParameters["KeyPath"] = $KeyPath } - if($AllowClobber){ - $CommandParameters["AllowClobber"] = $true + if($UseMasterPassword){ + $VaultParameters["UseMasterPassword"] = $true } + } - if($PSCmdlet.ShouldProcess($Vault, "Register SecretManagement vault [$ModuleName]")){ - Register-SecretVault @CommandParameters + if($ShouldRegisterVault){ + if($VaultType -eq "KeePass"){ + $KeePassModule = Get-Module -Name SecretManagement.KeePass -ListAvailable | Sort-Object -Property Version -Descending | Select-Object -First 1 + if($null -eq $KeePassModule){ + throw "SecretManagement KeePass vault registration requires module [SecretManagement.KeePass]." + } + + $ModuleReference = $KeePassModule.Name + if(-not [string]::IsNullOrWhiteSpace($KeePassModule.Path)){ + $ModuleReference = $KeePassModule.Path + } + + $CommandParameters = @{ + Name = $Vault + ModuleName = $ModuleReference + VaultParameters = @{ + Path = $VaultParameters["Path"] + UseMasterPassword = $false + UseWindowsAccount = $false + KeyPath = $null + ShowFullTitle = $false + ShowRecycleBin = $false + } + } + + foreach($Key in @("KeyPath", "UseMasterPassword", "UseWindowsAccount", "ShowFullTitle", "ShowRecycleBin", "SkipValidate")){ + if($VaultParameters.ContainsKey($Key)){ + $CommandParameters.VaultParameters[$Key] = $VaultParameters[$Key] + } + } + + if($DefaultVault){ + $CommandParameters["DefaultVault"] = $true + } + + if($AllowClobber){ + $CommandParameters["AllowClobber"] = $true + } + + if($PSCmdlet.ShouldProcess($Vault, "Register KeePass SecretManagement vault [$ModuleReference]")){ + Register-SecretVault @CommandParameters + } + }else{ + $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 + } } } @@ -186,80 +210,21 @@ function Register-DSCConfigurationDataCredentialProvider { } } - if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){ - Export-PowerShellDataFile -InputObject $ProviderSettings -Path $SettingsPath -Force:$Force + if($VaultType -ne "Generic"){ + $ProviderSettings.SecretManagement["VaultType"] = $VaultType } - if($PassThru){ - return $ProviderSettings - } - } - "SecretStore" { - if($ConfigureSecretStore){ - $CommandParameters = @{ - Authentication = $Authentication - Interaction = $Interaction + if($null -ne $MasterPassword){ + if([string]::IsNullOrWhiteSpace($MasterPasswordKeyPath)){ + throw "MasterPassword requires [MasterPasswordKeyPath]." } - if($null -ne $Password){ - $CommandParameters["Password"] = $Password + $Key = New-ConfigurationDataAesKeyFile -Path $MasterPasswordKeyPath -Force:$Force + $ProtectedValue = $MasterPassword | ConvertFrom-SecureString -Key $Key + $ProviderSettings.SecretManagement["MasterPassword"] = [ordered]@{ + ProtectedValue = $ProtectedValue + KeyPath = $MasterPasswordKeyPath } - - 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 - } - } - "AzureKeyVault" { - $ProviderSettings = [ordered]@{ - AzureKeyVault = [ordered]@{ - DefaultVault = $Vault - } - } - - if(-not [string]::IsNullOrWhiteSpace($SubscriptionId)){ - $ProviderSettings["AzureKeyVault"]["SubscriptionId"] = $SubscriptionId - } - - if(-not [string]::IsNullOrWhiteSpace($TenantId)){ - $ProviderSettings["AzureKeyVault"]["TenantId"] = $TenantId } if($PSCmdlet.ShouldProcess($SettingsPath, "Create provider settings for [$Provider]")){ diff --git a/Public/Resolve-DSCConfigurationData.ps1 b/Public/Resolve-DSCConfigurationData.ps1 index 7363775..06b2000 100644 --- a/Public/Resolve-DSCConfigurationData.ps1 +++ b/Public/Resolve-DSCConfigurationData.ps1 @@ -28,6 +28,7 @@ function Resolve-DSCConfigurationData { } if(-not $SkipSecrets){ + Unlock-ConfigurationDataSecretManagementVault -ProviderSettings $ProviderSettings $ConfigurationData = Resolve-ConfigurationDataParameterSecrets -ConfigurationData $ConfigurationData -ProviderSettings $ProviderSettings } diff --git a/Public/Set-DSCConfigurationDataCredentialProvider.ps1 b/Public/Set-DSCConfigurationDataCredentialProvider.ps1 new file mode 100644 index 0000000..1c87ce2 --- /dev/null +++ b/Public/Set-DSCConfigurationDataCredentialProvider.ps1 @@ -0,0 +1,258 @@ +function Set-DSCConfigurationDataCredentialProvider { + [CmdletBinding(SupportsShouldProcess=$true)] + Param( + [Parameter(Mandatory=$false)] + [string] + $Vault, + + [Parameter(Mandatory=$false)] + [AllowEmptyString()] + [ValidateSet("", "Generic", "KeePass")] + [string] + $VaultType = "", + + [Parameter(Mandatory=$false)] + [string] + $DatabasePath, + + [Parameter(Mandatory=$false)] + [string] + $KeyPath, + + [Parameter(Mandatory=$false)] + [switch] + $DisableKeePassKeyFile, + + [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)] + [Alias("UseMasterKey")] + [switch] + $UseMasterPassword, + + [Parameter(Mandatory=$false)] + [Alias("NoMasterKey", "NoMasterPassword")] + [switch] + $DisableMasterPassword, + + [Parameter(Mandatory=$false)] + [Alias("MasterKey")] + [System.Security.SecureString] + $MasterPassword, + + [Parameter(Mandatory=$false)] + [Alias("MasterKeyPath")] + [string] + $MasterPasswordKeyPath, + + [Parameter(Mandatory=$false)] + [switch] + $UseWindowsAccount, + + [Parameter(Mandatory=$false)] + [switch] + $ShowFullTitle, + + [Parameter(Mandatory=$false)] + [switch] + $ShowRecycleBin, + + [Parameter(Mandatory=$false)] + [switch] + $SkipValidate, + + [Parameter(Mandatory=$false)] + [string] + $SettingsPath, + + [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 ', ')." + } + } + + $ProviderInfo = Get-DSCConfigurationDataCredentialProvider -Provider $Provider -Vault $Vault -SettingsPath $SettingsPath + if([string]::IsNullOrWhiteSpace($Vault)){ + $Vault = [string]$ProviderInfo.DefaultVault + } + + if([string]::IsNullOrWhiteSpace($Vault)){ + throw "Vault is required. Pass [Vault] or define [DefaultVault] in the provider settings file." + } + } + + process { + $ExistingVault = @($ProviderInfo.RegisteredVaults | Select-Object -First 1) + $ExistingVaultParameters = @{} + if($ExistingVault.Count -gt 0 -and $ExistingVault[0].PSObject.Properties["VaultParameters"] -and $ExistingVault[0].VaultParameters -is [System.Collections.IDictionary]){ + foreach($Key in $ExistingVault[0].VaultParameters.Keys){ + $ExistingVaultParameters[$Key] = $ExistingVault[0].VaultParameters[$Key] + } + } + + $EffectiveVaultType = $VaultType + if([string]::IsNullOrWhiteSpace($EffectiveVaultType) -and $ProviderInfo.ProviderSettings -is [System.Collections.IDictionary] -and $ProviderInfo.ProviderSettings.ContainsKey("VaultType")){ + $EffectiveVaultType = [string]$ProviderInfo.ProviderSettings.VaultType + } + + if([string]::IsNullOrWhiteSpace($EffectiveVaultType) -and $ExistingVault.Count -gt 0 -and $ExistingVault[0].PSObject.Properties["ModuleName"]){ + if([string]$ExistingVault[0].ModuleName -match "SecretManagement\.KeePass"){ + $EffectiveVaultType = "KeePass" + } + } + + if([string]::IsNullOrWhiteSpace($EffectiveVaultType)){ + $EffectiveVaultType = "Generic" + } + + $EffectiveVaultParameters = @{} + foreach($Key in $ExistingVaultParameters.Keys){ + $EffectiveVaultParameters[$Key] = $ExistingVaultParameters[$Key] + } + + foreach($Key in $VaultParameters.Keys){ + $EffectiveVaultParameters[$Key] = $VaultParameters[$Key] + } + + if(-not [string]::IsNullOrWhiteSpace($DatabasePath)){ + $EffectiveVaultParameters["Path"] = $DatabasePath + } + + if(-not [string]::IsNullOrWhiteSpace($KeyPath)){ + $EffectiveVaultParameters["KeyPath"] = $KeyPath + } + + if($DisableKeePassKeyFile){ + $EffectiveVaultParameters["KeyPath"] = $null + } + + if($UseMasterPassword -and $DisableMasterPassword){ + throw "Use either [UseMasterPassword] or [DisableMasterPassword], not both." + } + + foreach($SwitchName in @("UseMasterPassword", "UseWindowsAccount", "ShowFullTitle", "ShowRecycleBin", "SkipValidate")){ + if($PSBoundParameters.ContainsKey($SwitchName)){ + $EffectiveVaultParameters[$SwitchName] = [bool]$PSBoundParameters[$SwitchName] + } + } + + if($DisableMasterPassword){ + $EffectiveVaultParameters["UseMasterPassword"] = $false + } + + if($PSCmdlet.ShouldProcess($Vault, "Update DSC configuration data credential provider settings")){ + $EffectiveMasterPasswordKeyPath = $MasterPasswordKeyPath + if([string]::IsNullOrWhiteSpace($EffectiveMasterPasswordKeyPath) -and + $ProviderInfo.ProviderSettings -is [System.Collections.IDictionary] -and + $ProviderInfo.ProviderSettings.ContainsKey("MasterPassword") -and + $ProviderInfo.ProviderSettings.MasterPassword -is [System.Collections.IDictionary] -and + $ProviderInfo.ProviderSettings.MasterPassword.ContainsKey("KeyPath")){ + $EffectiveMasterPasswordKeyPath = [string]$ProviderInfo.ProviderSettings.MasterPassword.KeyPath + } + + $CommandParameters = @{ + Provider = $Provider + Vault = $Vault + VaultType = $EffectiveVaultType + SettingsPath = $SettingsPath + VaultParameters = $EffectiveVaultParameters + Force = $Force + PassThru = $true + } + + if(-not [string]::IsNullOrWhiteSpace($ModuleName)){ + $CommandParameters["ModuleName"] = $ModuleName + } + + if($RegisterVault){ + $CommandParameters["RegisterVault"] = $true + } + + if($DefaultVault){ + $CommandParameters["DefaultVault"] = $true + } + + if($AllowClobber){ + $CommandParameters["AllowClobber"] = $true + } + + if($null -ne $MasterPassword){ + $CommandParameters["MasterPassword"] = $MasterPassword + } + + if(-not [string]::IsNullOrWhiteSpace($EffectiveMasterPasswordKeyPath)){ + $CommandParameters["MasterPasswordKeyPath"] = $EffectiveMasterPasswordKeyPath + } + + $Result = Register-DSCConfigurationDataCredentialProvider @CommandParameters + } + + if($PassThru){ + if($null -ne $Result){ + return $Result + } + + return (Get-DSCConfigurationDataCredentialProvider -Provider $Provider -Vault $Vault -SettingsPath $SettingsPath) + } + } +} diff --git a/Public/Unregister-DSCConfigurationDataCredentialProvider.ps1 b/Public/Unregister-DSCConfigurationDataCredentialProvider.ps1 index c921e46..a1863d2 100644 --- a/Public/Unregister-DSCConfigurationDataCredentialProvider.ps1 +++ b/Public/Unregister-DSCConfigurationDataCredentialProvider.ps1 @@ -5,10 +5,6 @@ function Unregister-DSCConfigurationDataCredentialProvider { [string] $Vault, - [Parameter(Mandatory=$false)] - [string] - $KeyPath, - [Parameter(Mandatory=$false)] [string] $SettingsPath, @@ -17,18 +13,10 @@ function Unregister-DSCConfigurationDataCredentialProvider { [switch] $RemoveSettings, - [Parameter(Mandatory=$false)] - [switch] - $RemoveKeyFile, - [Parameter(Mandatory=$false)] [switch] $UnregisterVault, - [Parameter(Mandatory=$false)] - [switch] - $ResetSecretStore, - [Parameter(Mandatory=$false)] [switch] $Force, @@ -86,9 +74,7 @@ function Unregister-DSCConfigurationDataCredentialProvider { Vault = $Vault SettingsPath = $SettingsPath RemovedSettings = $false - RemovedKeyFile = $false UnregisteredVault = $false - ResetSecretStore = $false } if($RemoveSettings -or (-not $PSBoundParameters.ContainsKey("RemoveSettings"))){ @@ -100,38 +86,10 @@ function Unregister-DSCConfigurationDataCredentialProvider { } } - if($RemoveKeyFile){ - if([string]::IsNullOrWhiteSpace($KeyPath)){ - throw "RemoveKeyFile requires [KeyPath]." - } - - if(Test-Path -Path $KeyPath -PathType Leaf){ - if($PSCmdlet.ShouldProcess($KeyPath, "Remove provider key file")){ - Remove-Item -Path $KeyPath -Force:$Force - $Result.RemovedKeyFile = $true - } - } - } - if($UnregisterVault){ - if($Provider -notin @("SecretManagement", "SecretStore")){ - Write-Verbose "Provider [$Provider] does not register a SecretManagement vault." - }else{ - if($PSCmdlet.ShouldProcess($Vault, "Unregister SecretManagement vault")){ - Unregister-SecretVault -Name $Vault - $Result.UnregisteredVault = $true - } - } - } - - if($ResetSecretStore){ - if($Provider -ne "SecretStore"){ - Write-Verbose "ResetSecretStore is only applicable to provider [SecretStore]." - }else{ - if($PSCmdlet.ShouldProcess("SecretStore", "Reset local SecretStore and delete all contained secrets")){ - Reset-SecretStore -Force -Confirm:$false - $Result.ResetSecretStore = $true - } + if($PSCmdlet.ShouldProcess($Vault, "Unregister SecretManagement vault")){ + Unregister-SecretVault -Name $Vault + $Result.UnregisteredVault = $true } } diff --git a/Readme.md b/Readme.md index da33582..ddda271 100644 --- a/Readme.md +++ b/Readme.md @@ -108,9 +108,9 @@ Supported parameter types: FarmPassphrase = @{ Type = 'secureString' Required = $true - Sensitive = $true - Value = @{ - Provider = 'KeePass' + Sensitive = $true + Value = @{ + Provider = 'SecretManagement' Vault = 'Contoso' Name = 'SharePoint/FarmPassphrase' } @@ -119,9 +119,9 @@ FarmPassphrase = @{ SetupCredential = @{ Type = 'credential' Required = $true - Sensitive = $true - Value = @{ - Provider = 'KeePass' + Sensitive = $true + Value = @{ + Provider = 'SecretManagement' Vault = 'Contoso' Name = 'Application/SetupAccount' UserName = 'CONTOSO\svc-app-setup' @@ -133,7 +133,7 @@ Secret references are validated and resolved by `Resolve-DSCConfigurationData` b ```powershell $resolved = Resolve-DSCConfigurationData -ConfigurationData $merged -ProviderSettings @{ - KeePass = @{ + SecretManagement = @{ DefaultVault = 'Contoso' } } @@ -141,28 +141,43 @@ $resolved = Resolve-DSCConfigurationData -ConfigurationData $merged -ProviderSet Use `-SkipSecrets` when you only want structural validation/resolution without loading provider secrets. -For unattended KeePass access, pass the KeePass master key through `ProviderSettings`, not through the PSD1 parameter definition: +SecretManagement is the only built-in secret resolver provider. KeePass, SecretStore, Azure Key Vault, and other backends should be registered as SecretManagement vaults. -```powershell -$resolved = Resolve-DSCConfigurationData -ConfigurationData $merged -ProviderSettings @{ - KeePass = @{ - DefaultVault = 'Contoso' - MasterKey = (Get-Secret -Name 'KeePass-Contoso-MasterKey') - } -} -``` - -You can generate the provider settings file with: +KeePass can be registered through the `SecretManagement.KeePass` vault extension: ```powershell Register-DSCConfigurationDataCredentialProvider ` - -Provider KeePass ` + -Provider SecretManagement ` -Vault Contoso ` - -KeyPath 'C:\DSC\Contoso\KeePass-Contoso.key' ` + -VaultType KeePass ` + -DatabasePath 'C:\DSC\Contoso\Secrets.kdbx' ` + -KeyPath 'C:\DSC\Contoso\Secrets.key' ` + -UseMasterPassword ` + -RegisterVault ` + -DefaultVault ` -SettingsPath 'C:\DSC\Contoso' ``` -SecretManagement can be initialized through the same entry point: +For unattended KeePass vaults that still require a master password, store the master password as a protected SecureString in the provider settings. The password is encrypted with an AES key file and the vault is unlocked automatically during `Resolve-DSCConfigurationData`: + +```powershell +$masterPassword = Read-Host -Prompt 'KeePass Master Password' -AsSecureString + +Register-DSCConfigurationDataCredentialProvider ` + -Provider SecretManagement ` + -Vault Contoso ` + -VaultType KeePass ` + -DatabasePath 'C:\DSC\Contoso\Secrets.kdbx' ` + -KeyPath 'C:\DSC\Contoso\Secrets.key' ` + -UseMasterPassword ` + -MasterPassword $masterPassword ` + -MasterPasswordKeyPath 'C:\DSC\Contoso\KeePass-MasterPassword.key' ` + -RegisterVault ` + -DefaultVault ` + -SettingsPath 'C:\DSC\Contoso' +``` + +Generic SecretManagement vaults can be registered through the same entry point: ```powershell Register-DSCConfigurationDataCredentialProvider ` @@ -174,131 +189,59 @@ Register-DSCConfigurationDataCredentialProvider ` -SettingsPath 'C:\DSC\Contoso' ``` -SecretStore can also be configured for unattended local usage: - -```powershell -Register-DSCConfigurationDataCredentialProvider ` - -Provider SecretStore ` - -Vault LocalStore ` - -ConfigureSecretStore ` - -Authentication None ` - -Interaction None ` - -RegisterVault ` - -DefaultVault ` - -SettingsPath 'C:\DSC\Contoso' -``` - -Azure Key Vault can be registered as a settings file without storing Azure credentials. Authentication is expected to come from the active Az context, managed identity, service principal login, or another external Azure authentication flow: - -```powershell -Register-DSCConfigurationDataCredentialProvider ` - -Provider AzureKeyVault ` - -Vault contoso-kv ` - -SubscriptionId '00000000-0000-0000-0000-000000000000' ` - -TenantId '11111111-1111-1111-1111-111111111111' ` - -SettingsPath 'C:\DSC\Contoso' -``` - Provider setup can be removed again: ```powershell Unregister-DSCConfigurationDataCredentialProvider ` - -Provider KeePass ` + -Provider SecretManagement ` -Vault Contoso ` -SettingsPath 'C:\DSC\Contoso' ` - -KeyPath 'C:\DSC\Contoso\KeePass-Contoso.key' ` - -RemoveKeyFile -``` - -For SecretManagement or SecretStore vault registration: - -```powershell -Unregister-DSCConfigurationDataCredentialProvider ` - -Provider SecretStore ` - -Vault LocalStore ` - -SettingsPath 'C:\DSC\Contoso' ` -UnregisterVault ``` -Use `-ResetSecretStore` only when you intentionally want to delete all secrets from the local SecretStore. - Then use it directly: ```powershell $resolved = Resolve-DSCConfigurationData ` -ConfigurationData $merged ` - -ProviderSettingsPath 'C:\DSC\Contoso\ProviderSettings.KeePass.psd1' + -ProviderSettingsPath 'C:\DSC\Contoso\ProviderSettings.SecretManagement.psd1' ``` -For portable unattended tests, use an AES key file with `ConvertFrom-SecureString -Key`: +Inspect the configured provider and registered vault: ```powershell -$resolved = Resolve-DSCConfigurationData -ConfigurationData $merged -ProviderSettings @{ - KeePass = @{ - DefaultVault = 'Test' - MasterKey = @{ - ProtectedValue = '76492d1116743f0423413b16050a5345...' - KeyPath = 'F:\Secrets\KeePass-Test.key' - } - } -} +Get-DSCConfigurationDataCredentialProvider ` + -Provider SecretManagement ` + -SettingsPath 'C:\DSC\Contoso' ` + -TestVault ``` -`MasterKey` also supports: +Update an existing KeePass-backed SecretManagement provider registration, for example to enable master-password based unlocks: ```powershell -MasterKey = @{ - EnvironmentVariable = 'KEEPASS_TEST_MASTERKEY' -} +$masterPassword = Read-Host -Prompt 'KeePass Master Password' -AsSecureString + +Set-DSCConfigurationDataCredentialProvider ` + -Provider SecretManagement ` + -SettingsPath 'C:\DSC\Contoso' ` + -UseMasterPassword ` + -MasterPassword $masterPassword ` + -MasterPasswordKeyPath 'C:\DSC\Contoso\KeePass-MasterPassword.key' ` + -VaultParameters @{ + ShowFullTitle = $true + } ` + -RegisterVault ` + -AllowClobber ` + -Force ``` -### Secret Provider Files +### Secret Provider -Secret providers are loaded automatically from the module folder `Providers`. -The naming convention is: +Only one built-in provider is registered: -```text -Providers\Provider..ps1 -``` - -Each provider registers itself with the same schema: - -```powershell -$MyProvider = @{ - Name = 'MyProvider' - SupportedTypes = @( - 'credential', - 'securestring', - 'string' - ) - Resolver = { - param( - [System.Collections.IDictionary] $Reference, - [string] $ExpectedType, - [hashtable] $ProviderSettings - ) - - # Return a PSCredential for ExpectedType = credential, - # a SecureString for ExpectedType = securestring, - # or a string for ExpectedType = string. - } -} - -Register-ConfigurationDataSecretProvider @MyProvider -``` - -The KeePass provider is implemented in: - -```text -Providers\Provider.KeePass.ps1 -``` - -Built-in providers: - -- `KeePass`: uses `PoShKeePass` / `Get-KeePassEntry` - `SecretManagement`: uses `Microsoft.PowerShell.SecretManagement` / `Get-Secret` -- `SecretStore`: convenience provider for local SecretStore vaults through `Get-Secret` -- `AzureKeyVault`: uses `Az.KeyVault` / `Get-AzKeyVaultSecret` + +Backend-specific behavior belongs to the registered SecretManagement vault extension. For example, KeePass is handled by `SecretManagement.KeePass`, SecretStore by `Microsoft.PowerShell.SecretStore`, and Azure Key Vault by the matching SecretManagement vault extension. SecretManagement example: @@ -315,7 +258,7 @@ SetupCredential = @{ } ``` -SecretStore example: +SecretStore example through SecretManagement: ```powershell FarmPassphrase = @{ @@ -323,14 +266,14 @@ FarmPassphrase = @{ Required = $true Sensitive = $true Value = @{ - Provider = 'SecretStore' + Provider = 'SecretManagement' Vault = 'LocalStore' Name = 'SharePointFarmPassphrase' } } ``` -Azure Key Vault example: +Azure Key Vault example through SecretManagement: ```powershell SetupCredential = @{ @@ -338,7 +281,7 @@ SetupCredential = @{ Required = $true Sensitive = $true Value = @{ - Provider = 'AzureKeyVault' + Provider = 'SecretManagement' Vault = 'contoso-kv' Name = 'app-setup-password' UserName = 'CONTOSO\svc-app-setup' @@ -350,7 +293,7 @@ FarmPassphrase = @{ Required = $true Sensitive = $true Value = @{ - Provider = 'AzureKeyVault' + Provider = 'SecretManagement' Vault = 'contoso-kv' Name = 'farm-passphrase' } diff --git a/Resolve-DSCConfigurationData.psd1 b/Resolve-DSCConfigurationData.psd1 index 6a16e4f..9af3fff 100644 --- a/Resolve-DSCConfigurationData.psd1 +++ b/Resolve-DSCConfigurationData.psd1 @@ -1,14 +1,16 @@ @{ RootModule = "Resolve-DSCConfigurationData.psm1" - ModuleVersion = "1.0.1" + ModuleVersion = "1.0.2" GUID = "1d6ba0d4-93d5-4b0f-94c7-bf10a30fe0e8" Author = "Torsten Brendgen" Copyright = "(c) Torsten Brendgen. All rights reserved." Description = "Resolves parameters, variables, and expressions in DSC configuration data." PowerShellVersion = "5.1" FunctionsToExport = @( + "Get-DSCConfigurationDataCredentialProvider", "Resolve-DSCConfigurationData", "Register-DSCConfigurationDataCredentialProvider", + "Set-DSCConfigurationDataCredentialProvider", "Unregister-DSCConfigurationDataCredentialProvider" ) CmdletsToExport = @() diff --git a/Resolve-DSCConfigurationData.psm1 b/Resolve-DSCConfigurationData.psm1 index 6f8861a..3f4dd8f 100644 --- a/Resolve-DSCConfigurationData.psm1 +++ b/Resolve-DSCConfigurationData.psm1 @@ -14,7 +14,9 @@ foreach($File in @($Private + $Providers + $Public)){ } Export-ModuleMember -Function @( + "Get-DSCConfigurationDataCredentialProvider", "Resolve-DSCConfigurationData", "Register-DSCConfigurationDataCredentialProvider", + "Set-DSCConfigurationDataCredentialProvider", "Unregister-DSCConfigurationDataCredentialProvider" )