SecretManagement.KeePass.Extension/SecretManagement.KeePass.Extension.psm1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. using namespace Microsoft.PowerShell.SecretManagement function GetKeepassParams ([String]$VaultName, [Hashtable]$AdditionalParameters) { $KeepassParams = @{} if ($VaultName) { $KeepassParams.DatabaseProfileName = $VaultName } $SecureVaultPW = (Get-Variable -Scope Script -Name "Vault_$VaultName" -ErrorAction SilentlyContinue).Value.Password if (-not $SecureVaultPW) {throw "${VaultName}: Error retrieving the master key from cache"} $KeePassParams.MasterKey = $SecureVaultPW return $KeepassParams } function Get-Secret { param ( [string]$Name, [string]$VaultName, [hashtable]$AdditionalParameters = (Get-SecretVault -Name $VaultName).VaultParameters ) $ErrorActionPreference = 'Stop' if (-not (Test-SecretVault -VaultName $vaultName)) {throw "Vault ${VaultName}: Not a valid vault configuration"} $KeepassParams = GetKeepassParams $VaultName $AdditionalParameters if ($Name) { $KeePassParams.Title = $Name } $keepassGetResult = Get-KeePassEntry @KeepassParams | Where-Object ParentGroup -NotMatch 'RecycleBin' if ($keepassGetResult.count -gt 1) { throw "Multiple ambiguous entries found for $Name, please remove the duplicate entry" } if (-not $keepassGetResult.Username) { $keepassGetResult.Password } else { [PSCredential]::new($KeepassGetResult.UserName, $KeepassGetResult.Password) } } function Set-Secret { param ( [string]$Name, [object]$Secret, [string]$VaultName, [hashtable]$AdditionalParameters = (Get-SecretVault -Name $VaultName).VaultParameters ) if (-not (Test-SecretVault -VaultName $vaultName)) {throw "Vault ${VaultName}: Not a valid vault configuration"} $KeepassParams = GetKeepassParams $VaultName $AdditionalParameters #Set default group [String]$KeepassParams.KeePassEntryGroupPath = Get-KeePassGroup @KeepassParams | Where-Object fullpath -NotMatch '/' | ForEach-Object fullpath | Select-Object -First 1 switch ($Secret.GetType()) { ([String]) { $KeepassParams.Username = $null $KeepassParams.KeepassPassword = $Secret } ([PSCredential]) { $KeepassParams.Username = $Secret.Username $KeepassParams.KeepassPassword = $Secret.Password } default { throw 'This vault provider only accepts string and PSCredential secrets' } } return [Bool](New-KeePassEntry @KeepassParams -Title $Name -PassThru) } function Remove-Secret { param ( [string]$Name, [string]$VaultName, [hashtable]$AdditionalParameters = (Get-SecretVault -Name $VaultName).VaultParameters ) if (-not (Test-SecretVault -VaultName $vaultName)) {throw "Vault ${VaultName}: Not a valid vault configuration"} $KeepassParams = GetKeepassParams $VaultName $AdditionalParameters $GetKeePassResult = Get-KeePassEntry @KeepassParams -Title $Name if (-not $GetKeePassResult) { throw "No Keepass Entry named $Name found" } Remove-KeePassEntry @KeepassParams -KeePassEntry $GetKeePassResult -ErrorAction stop -Confirm:$false return $true } function Get-SecretInfo { param( [string]$Filter, [string]$VaultName = (Get-SecretVault).VaultName, [hashtable]$AdditionalParameters = (Get-SecretVault -Name $VaultName).VaultParameters ) if (-not (Test-SecretVault -VaultName $vaultName)) {throw "Vault ${VaultName}: Not a valid vault configuration"} $KeepassParams = GetKeepassParams -VaultName $VaultName -AdditionalParameters $AdditionalParameters $KeepassGetResult = Get-KeePassEntry @KeepassParams | Where-Object {$_ -notmatch '^.+?/Recycle Bin/'} [Object[]]$secretInfoResult = $KeepassGetResult.where{ $PSItem.Title -like $filter }.foreach{ [SecretInformation]::new( $PSItem.Title, #string name [SecretType]::PSCredential, #SecretType type $VaultName #string vaultName ) } [Object[]]$sortedInfoResult = $secretInfoResult | Sort-Object -Unique Name if ($sortedInfoResult.count -lt $secretInfoResult.count) { $filteredRecords = (Compare-Object $sortedInfoResult $secretInfoResult | Where-Object SideIndicator -eq '=>').InputObject Write-Warning "Vault ${VaultName}: Entries with non-unique titles were detected, the duplicates were filtered out. Duplicate titles are currently not supported with this extension, ensure your entry titles are unique in the database." Write-Warning "Vault ${VaultName}: Filtered Non-Unique Titles: $($filteredRecords -join ', ')" } $sortedInfoResult } function Test-SecretVault { [CmdletBinding()] param ( [Parameter(ValueFromPipelineByPropertyName,Mandatory)] [string]$VaultName, [Parameter(ValueFromPipelineByPropertyName)] [hashtable]$AdditionalParameters = (Get-SecretVault -Name $vaultName).VaultParameters ) $VaultParameters = $AdditionalParameters $ErrorActionPreference = 'Stop' Write-Verbose "SecretManagement: Testing Vault ${VaultName}" if (-not $VaultName) { throw 'Keepass: You must specify a Vault Name to test' } if (-not $VaultParameters.Path) { #TODO: Add ThrowUser to throw outside of module scope throw "Vault ${VaultName}: You must specify the Path vault parameter as a path to your KeePass Database" } if (-not (Test-Path $VaultParameters.Path)) { throw "Vault ${VaultName}: Could not find the keepass database $($VaultParameters.Path). Please verify the file exists or re-register the vault" } try { $VaultMasterKey = (Get-Variable -Name "Vault_$VaultName" -Scope Script -ErrorAction Stop).Value Write-Verbose "Vault ${VaultName}: Master Key found in Cache, skipping user prompt" } catch { $GetCredentialParams = @{ Username = 'VaultMasterKey' Message = "Enter the Vault Master Password for Vault $VaultName" } $VaultMasterKey = (Get-Credential @GetCredentialParams) if (-not $VaultMasterKey.Password) { throw 'You must specify a vault master key to unlock the vault' } Set-Variable -Name "Vault_$VaultName" -Scope Script -Value $VaultMasterKey } if (-not (Get-KeePassDatabaseConfiguration -DatabaseProfileName $VaultName)) { New-KeePassDatabaseConfiguration -DatabaseProfileName $VaultName -DatabasePath $AdditionalParameters.Path -UseMasterKey Write-Verbose "Vault ${VaultName}: A PoshKeePass database configuration was not found but was created." return $true } try { Get-KeePassEntry -DatabaseProfileName $VaultName -MasterKey $VaultMasterKey -Title '__SECRETMANAGEMENT__TESTSECRET_SHOULDNOTEXIST' -ErrorAction Stop } catch { Clear-Variable -Name "Vault_$VaultName" -Scope Script -ErrorAction SilentlyContinue throw $PSItem } #If the above doesn't throw an error, we are good return $true } |