EnhancedSecretsAO.psm1
#Region '.\Public\Add-KeePassAttachment.ps1' -1 function Add-KeePassAttachment { <# .SYNOPSIS Adds an attachment to a specific entry in a KeePass database. .PARAMETER DatabasePath The full path to the KeePass database file. .PARAMETER EntryName The name of the entry to which the attachment will be added. .PARAMETER AttachmentName The name of the attachment being added. .PARAMETER AttachmentPath The full path to the attachment file. .PARAMETER KeyFilePath The full path to the key file for the KeePass database. .EXAMPLE Add-KeePassAttachment -DatabasePath "C:\code\secrets\myDatabase.kdbx" -EntryName "example_entry" -AttachmentName "certificate" -AttachmentPath "C:\code\secrets\cert.cer" -KeyFilePath "C:\code\secrets\myKeyFile.keyx" Adds the certificate as an attachment to the "example_entry" in the KeePass database. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the KeePass database file.")] [ValidateNotNullOrEmpty()] [string]$DatabasePath, [Parameter(Mandatory = $true, HelpMessage = "The name of the entry to which the attachment will be added.")] [ValidateNotNullOrEmpty()] [string]$EntryName, [Parameter(Mandatory = $true, HelpMessage = "The name of the attachment being added.")] [ValidateNotNullOrEmpty()] [string]$AttachmentName, [Parameter(Mandatory = $true, HelpMessage = "The full path to the attachment file.")] [ValidateNotNullOrEmpty()] [string]$AttachmentPath, [Parameter(Mandatory = $true, HelpMessage = "The full path to the key file for the KeePass database.")] [ValidateNotNullOrEmpty()] [string]$KeyFilePath ) Begin { Write-EnhancedLog -Message "Starting Add-KeePassAttachment function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Validate paths if (-not (Test-Path -Path $DatabasePath)) { Write-EnhancedLog -Message "The database file does not exist: $DatabasePath" -Level "ERROR" throw "The database file does not exist: $DatabasePath" } if (-not (Test-Path -Path $KeyFilePath)) { Write-EnhancedLog -Message "The key file does not exist: $KeyFilePath" -Level "ERROR" throw "The key file does not exist: $KeyFilePath" } if (-not (Test-Path -Path $AttachmentPath)) { Write-EnhancedLog -Message "The attachment file does not exist: $AttachmentPath" -Level "ERROR" throw "The attachment file does not exist: $AttachmentPath" } # Construct command for KeePassXC CLI $command = "keepassxc-cli attachment-import `"$DatabasePath`" `"$EntryName`" `"$AttachmentName`" `"$AttachmentPath`" --key-file `"$KeyFilePath`" --no-password" Write-EnhancedLog -Message "Running command: $command" -Level "INFO" # Execute the command Invoke-Expression $command Write-Host "Attachment '$AttachmentName' added successfully to the entry '$EntryName' in the database." -ForegroundColor Green Write-EnhancedLog -Message "Attachment '$AttachmentName' added successfully to '$EntryName'." -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to add attachment: $($_.Exception.Message)" -Level "ERROR" throw "Failed to add attachment to the entry: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Add-KeePassAttachment function" -Level "Notice" } } # $addAttachmentParams = @{ # DatabasePath = "C:\code\secrets\myDatabase.kdbx" # EntryName = "example_entry" # AttachmentName = "certificate" # AttachmentPath = "C:\code\secrets\cert.pfx" # KeyFilePath = "C:\code\secrets\myKeyFile.keyx" # } # Add-KeePassAttachment @addAttachmentParams #EndRegion '.\Public\Add-KeePassAttachment.ps1' 106 #Region '.\Public\Add-KeePassEntry.ps1' -1 function Add-KeePassEntry { <# .SYNOPSIS Adds a new entry to the KeePass database. .PARAMETER DatabasePath The full path to the KeePass database file. .PARAMETER KeyFilePath The full path to the key file for the KeePass database. .PARAMETER Username The username for the entry being added. .PARAMETER EntryName The name of the entry being added. .EXAMPLE Add-KeePassEntry -DatabasePath "C:\code\secrets\myDatabase.kdbx" -KeyFilePath "C:\code\secrets\myKeyFile.keyx" -Username "john_doe" -EntryName "example_entry" Adds the username "john_doe" to the "example_entry" in the KeePass database. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the KeePass database file.")] [ValidateNotNullOrEmpty()] [string]$DatabasePath, [Parameter(Mandatory = $true, HelpMessage = "The full path to the key file for the KeePass database.")] [ValidateNotNullOrEmpty()] [string]$KeyFilePath, [Parameter(Mandatory = $true, HelpMessage = "The username for the entry being added.")] [ValidateNotNullOrEmpty()] [string]$Username, [Parameter(Mandatory = $true, HelpMessage = "The name of the entry being added.")] [ValidateNotNullOrEmpty()] [string]$EntryName ) Begin { Write-EnhancedLog -Message "Starting Add-KeePassEntry function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Validate paths if (-not (Test-Path -Path $DatabasePath)) { Write-EnhancedLog -Message "The database file does not exist: $DatabasePath" -Level "ERROR" throw "The database file does not exist: $DatabasePath" } if (-not (Test-Path -Path $KeyFilePath)) { Write-EnhancedLog -Message "The key file does not exist: $KeyFilePath" -Level "ERROR" throw "The key file does not exist: $KeyFilePath" } # Construct command for KeePassXC CLI $command = "keepassxc-cli add `"$DatabasePath`" -u `"$Username`" -g `"$EntryName`" --key-file `"$KeyFilePath`" --no-password" Write-EnhancedLog -Message "Running command: $command" -Level "INFO" # Execute the command Invoke-Expression $command Write-EnhancedLog -Message "Entry '$EntryName' added successfully to the database." -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to add entry: $($_.Exception.Message)" -Level "ERROR" throw "Failed to add entry to the database: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Add-KeePassEntry function" -Level "Notice" } } # Add a new entry to the KeePass database # Define the parameters for adding a new entry # $entryParams = @{ # DatabasePath = "C:\code\secrets\myDatabase.kdbx" # KeyFilePath = "C:\code\secrets\myKeyFile.keyx" # Username = "john_doe" # EntryName = "example_entry" # } # Add a new entry to the KeePass database # Add-KeePassEntry @entryParams #EndRegion '.\Public\Add-KeePassEntry.ps1' 97 #Region '.\Public\Decrypt-FileWithCert.ps1' -1 function Decrypt-FileWithCert { <# .SYNOPSIS Decrypts a file using a certificate and AES encryption by restoring the certificate, decrypting the AES key, and decrypting the original file. .PARAMETER CertBase64Path The file path to the Base64-encoded certificate. .PARAMETER CertPasswordPath The file path to the certificate password. .PARAMETER KeyBase64Path The file path to the Base64-encoded AES key. .PARAMETER EncryptedFilePath The path to the encrypted file to be decrypted. .PARAMETER DecryptedFilePath The path where the decrypted file will be saved. .PARAMETER CertsDir The directory where the certificate files will be stored temporarily. .EXAMPLE $params = @{ CertBase64Path = "C:\temp\certs\cert.pfx.base64" CertPasswordPath = "C:\temp\certpassword.txt" KeyBase64Path = "C:\temp\certs\secret.key.encrypted.base64" EncryptedFilePath = "C:\temp\myDatabase.zip.encrypted" DecryptedFilePath = "C:\temp\myDatabase.zip" CertsDir = "C:\temp\certs" } Decrypt-FileWithCert @params Decrypts the file using the given certificate and paths. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The file path to the Base64-encoded certificate.")] [ValidateNotNullOrEmpty()] [string]$CertBase64Path, [Parameter(Mandatory = $true, HelpMessage = "The file path to the certificate password.")] [ValidateNotNullOrEmpty()] [string]$CertPasswordPath, [Parameter(Mandatory = $true, HelpMessage = "The file path to the Base64-encoded AES key.")] [ValidateNotNullOrEmpty()] [string]$KeyBase64Path, [Parameter(Mandatory = $true, HelpMessage = "The path to the encrypted file.")] [ValidateNotNullOrEmpty()] [string]$EncryptedFilePath, [Parameter(Mandatory = $true, HelpMessage = "The path where the decrypted file will be saved.")] [ValidateNotNullOrEmpty()] [string]$DecryptedFilePath, [Parameter(Mandatory = $true, HelpMessage = "The directory where the certificate files will be temporarily stored.")] [ValidateNotNullOrEmpty()] [string]$CertsDir ) Begin { Write-EnhancedLog -Message "Starting Decrypt-FileWithCert function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Step 1: Create necessary directories if not exist if (-not (Test-Path -Path $CertsDir)) { New-Item -Path $CertsDir -ItemType Directory | Out-Null Write-EnhancedLog -Message "Created directory: $CertsDir" -Level "INFO" } } Process { try { # Step 2: Decode Base64-encoded certificate and save as .pfx $base64Cert = Get-Content -Path $CertBase64Path $certBytes = [Convert]::FromBase64String($base64Cert) $certPath = Join-Path $CertsDir "cert.pfx" [System.IO.File]::WriteAllBytes($certPath, $certBytes) Write-EnhancedLog -Message "Certificate restored at: $certPath" -Level "INFO" # Step 3: Get the certificate password from the file $certPassword = Get-Content -Path $CertPasswordPath # Step 4: Import the certificate with the private key $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($certPath, $certPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::UserKeySet) if ($cert.HasPrivateKey) { Write-EnhancedLog -Message "The certificate's private key is accessible." -Level "INFO" } else { Write-EnhancedLog -Message "The certificate's private key is not accessible." -Level "ERROR" throw "The certificate's private key is not accessible." } # Step 5: Decode Base64-encoded AES key and IV $base64Key = Get-Content -Path $KeyBase64Path $keyBytes = [Convert]::FromBase64String($base64Key) $aesKeyFilePath = Join-Path $CertsDir "secret.key.encrypted" [System.IO.File]::WriteAllBytes($aesKeyFilePath, $keyBytes) Write-EnhancedLog -Message "AES key and IV restored at: $aesKeyFilePath" -Level "INFO" # Step 6: Read encrypted AES key and IV $encryptedAESPackage = [System.IO.File]::ReadAllBytes($aesKeyFilePath) # Step 7: Extract IV (first 16 bytes) and encrypted AES key (remaining bytes) $iv = $encryptedAESPackage[0..15] $encryptedAESKey = $encryptedAESPackage[16..($encryptedAESPackage.Length - 1)] # Step 8: Decrypt the AES key using the certificate's private key with RSA-OAEP padding $rsaProvider = $cert.PrivateKey -as [System.Security.Cryptography.RSACryptoServiceProvider] if (-not $rsaProvider) { Write-EnhancedLog -Message "Unable to retrieve RSA private key from certificate." -Level "ERROR" throw "Unable to retrieve RSA private key from certificate." } $aesKey = $rsaProvider.Decrypt($encryptedAESKey, $true) # Use $true for OAEP padding Write-EnhancedLog -Message "AES Key successfully decrypted." -Level "INFO" # Step 9: Decrypt the original file using AES $encryptedContent = [System.IO.File]::ReadAllBytes($EncryptedFilePath) $aes = [System.Security.Cryptography.AesCryptoServiceProvider]::Create() $aes.Key = $aesKey $aes.IV = $iv $decryptor = $aes.CreateDecryptor($aes.Key, $aes.IV) $decryptedBytes = $decryptor.TransformFinalBlock($encryptedContent, 0, $encryptedContent.Length) # Write the decrypted content to a new file [System.IO.File]::WriteAllBytes($DecryptedFilePath, $decryptedBytes) Write-EnhancedLog -Message "Decrypted file saved to: $DecryptedFilePath" -Level "INFO" } catch { Write-EnhancedLog -Message "Decryption failed: $($_.Exception.Message)" -Level "ERROR" Handle-Error -ErrorRecord $_ throw "Decryption process failed: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Decrypt-FileWithCert function" -Level "Notice" } } #Example Usage # # Define the parameters for the Decrypt-FileWithCert function using splatting # $params = @{ # # Path to the Base64-encoded certificate file. # # This file should contain the Base64-encoded contents of the .pfx certificate that you want to use for decryption. # CertBase64Path = "C:\temp\certs\cert.pfx.base64" # # Path to the text file that contains the password for the .pfx certificate. # # This is the password that will be used to unlock the certificate and access the private key. # CertPasswordPath = "C:\temp\certpassword.txt" # # Path to the Base64-encoded AES key file. # # This file contains the encrypted AES key that will be used to decrypt the target file. # KeyBase64Path = "C:\temp\certs\secret.key.encrypted.base64" # # Path to the file that is encrypted and needs to be decrypted. # # This is the target file that was encrypted using the AES key, and it will be decrypted using the AES key and IV. # EncryptedFilePath = "C:\temp\myDatabase.zip.encrypted" # # Path where the decrypted file will be saved after decryption. # # This is the output path where the function will store the decrypted version of the file. # DecryptedFilePath = "C:\temp\myDatabase.zip" # # Directory where temporary files such as the certificate and the AES key will be stored during the process. # # This is a working directory where the function can safely write temporary files during the decryption. # CertsDir = "C:\temp\certs" # } # # Call the Decrypt-FileWithCert function and pass the parameters via splatting. # # This function will use the provided certificate, key, and encrypted file to perform the decryption and save the decrypted file. # Decrypt-FileWithCert @params #EndRegion '.\Public\Decrypt-FileWithCert.ps1' 183 #Region '.\Public\Download-GitHubReleaseAsset.ps1' -1 function Download-GitHubReleaseAsset { <# .SYNOPSIS Downloads a release asset from a GitHub repository based on the release tag and asset name. .PARAMETER Token The personal access token (PAT) for GitHub authentication. .PARAMETER RepoOwner The owner of the GitHub repository. .PARAMETER RepoName The name of the GitHub repository. .PARAMETER ReleaseTag The release tag to identify the specific release. .PARAMETER FileName The name of the asset file to download. .PARAMETER DestinationPath The path where the downloaded file will be saved. .EXAMPLE $params = @{ Token = "mypat" RepoOwner = "aollivierre" RepoName = "Vault" ReleaseTag = "0.1" FileName = "ICTC_Project_2_Aug_29_2024.zip.aes.zip" DestinationPath = "C:\temp\ICTC_Project_2_Aug_29_2024.zip.aes.zip" } Download-GitHubReleaseAsset @params Downloads the specified asset from the GitHub release. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The personal access token (PAT) for GitHub authentication.")] [ValidateNotNullOrEmpty()] [string]$Token, [Parameter(Mandatory = $true, HelpMessage = "The owner of the GitHub repository.")] [ValidateNotNullOrEmpty()] [string]$RepoOwner, [Parameter(Mandatory = $true, HelpMessage = "The name of the GitHub repository.")] [ValidateNotNullOrEmpty()] [string]$RepoName, [Parameter(Mandatory = $true, HelpMessage = "The release tag to identify the specific release.")] [ValidateNotNullOrEmpty()] [string]$ReleaseTag, [Parameter(Mandatory = $true, HelpMessage = "The name of the asset file to download.")] [ValidateNotNullOrEmpty()] [string]$FileName, [Parameter(Mandatory = $true, HelpMessage = "The path where the downloaded file will be saved.")] [ValidateNotNullOrEmpty()] [string]$DestinationPath ) Begin { Write-EnhancedLog -Message "Starting Download-GitHubReleaseAsset function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Set headers for GitHub authentication $headers = @{ Authorization = "token $Token" Accept = "application/vnd.github+json" } # GitHub API URL to get release details $releaseUrl = "https://api.github.com/repos/$RepoOwner/$RepoName/releases" # Fetch the list of releases $releases = Invoke-RestMethod -Uri $releaseUrl -Headers $headers # Find the release with the specified tag $release = $releases | Where-Object { $_.tag_name -eq $ReleaseTag } if ($release) { # Find the asset by name $asset = $release.assets | Where-Object { $_.name -eq $FileName } if ($asset) { $downloadUrl = $asset.url # Get the asset's download URL Write-EnhancedLog -Message "Asset found, starting download..." -Level "INFO" # Set the download headers $downloadHeaders = @{ Authorization = "token $Token" Accept = "application/octet-stream" } # Download the file Invoke-WebRequest -Uri $downloadUrl -Headers $downloadHeaders -OutFile $DestinationPath Write-EnhancedLog -Message "File downloaded successfully: $FileName to Destination $DestinationPath" -Level "INFO" } else { Write-EnhancedLog -Message "Asset $FileName not found in the release." -Level "ERROR" throw "Asset $FileName not found in the release." } } else { Write-EnhancedLog -Message "Release with tag $ReleaseTag not found." -Level "ERROR" throw "Release with tag $ReleaseTag not found." } } catch { Write-EnhancedLog -Message "Error during GitHub asset download: $($_.Exception.Message)" -Level "ERROR" throw "GitHub asset download failed: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Download-GitHubReleaseAsset function" -Level "Notice" } } #EndRegion '.\Public\Download-GitHubReleaseAsset.ps1' 122 #Region '.\Public\Encrypt-FileWithCert.ps1' -1 function Encrypt-FileWithCert { <# .SYNOPSIS Encrypts a file using a self-signed certificate and AES encryption, and stores the certificate, encrypted file, and AES key. .PARAMETER SecretFilePath The path to the file that will be encrypted. .PARAMETER CertsDir The directory where the certificate and related files will be stored. .PARAMETER EncryptedFilePath The path where the encrypted file will be saved. .PARAMETER EncryptedKeyFilePath The path where the encrypted AES key and IV will be saved. .EXAMPLE $params = @{ SecretFilePath = "C:\code\secrets\myDatabase.zip" CertsDir = "C:\temp\certs" EncryptedFilePath = "C:\temp\myDatabase.zip.encrypted" EncryptedKeyFilePath = "C:\temp\secret.key.encrypted" } Encrypt-FileWithCert @params Encrypts the file and stores the necessary encryption artifacts. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The path to the file that will be encrypted.")] [ValidateNotNullOrEmpty()] [string]$SecretFilePath, [Parameter(Mandatory = $true, HelpMessage = "The directory where the certificate and related files will be stored.")] [ValidateNotNullOrEmpty()] [string]$CertsDir, [Parameter(Mandatory = $true, HelpMessage = "The path where the encrypted file will be saved.")] [ValidateNotNullOrEmpty()] [string]$EncryptedFilePath, [Parameter(Mandatory = $true, HelpMessage = "The path where the encrypted AES key and IV will be saved.")] [ValidateNotNullOrEmpty()] [string]$EncryptedKeyFilePath ) Begin { Write-EnhancedLog -Message "Starting Encrypt-FileWithCert function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Step 1: Create necessary directories if not exist if (-not (Test-Path -Path $CertsDir)) { New-Item -Path $CertsDir -ItemType Directory | Out-Null Write-EnhancedLog -Message "Created directory: $CertsDir" -Level "INFO" } } Process { try { # Step 2: Generate a random password for the certificate Add-Type -AssemblyName 'System.Web' $certPassword = [System.Web.Security.Membership]::GeneratePassword(128, 2) $passwordFilePath = Join-Path $CertsDir "certPassword.txt" $certPassword | Out-File -FilePath $passwordFilePath -Encoding UTF8 Write-EnhancedLog -Message "Generated certificate password saved to: $passwordFilePath" -Level "INFO" # Step 3: Create a self-signed certificate and export it $cert = New-SelfSignedCertificate -CertStoreLocation "Cert:\CurrentUser\My" -Subject "CN=FileEncryptionCert" -KeyLength 2048 -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" $certThumbprint = $cert.Thumbprint $certFile = Join-Path $CertsDir "cert.pfx" Export-PfxCertificate -Cert "Cert:\CurrentUser\My\$($certThumbprint)" -FilePath $certFile -Password (ConvertTo-SecureString $certPassword -AsPlainText -Force) Write-EnhancedLog -Message "Certificate generated and exported to: $certFile" -Level "INFO" # Step 4: Encrypt the file with AES $aes = [System.Security.Cryptography.AesCryptoServiceProvider]::Create() $aes.KeySize = 256 $aes.GenerateKey() $aes.GenerateIV() # Read the file content and encrypt with AES $plainTextBytes = [System.IO.File]::ReadAllBytes($SecretFilePath) $encryptor = $aes.CreateEncryptor($aes.Key, $aes.IV) $encryptedBytes = $encryptor.TransformFinalBlock($plainTextBytes, 0, $plainTextBytes.Length) [System.IO.File]::WriteAllBytes($EncryptedFilePath, $encryptedBytes) Write-EnhancedLog -Message "File encrypted and saved to: $EncryptedFilePath" -Level "INFO" # Step 5: Encrypt the AES key with RSA using the certificate $rsa = [System.Security.Cryptography.RSACryptoServiceProvider]::new() $rsa.ImportParameters($cert.PublicKey.Key.ExportParameters($false)) $encryptedAESKey = $rsa.Encrypt($aes.Key, $true) # Encrypt the AES key with RSA # Save the encrypted AES key and IV to file $encryptedAESPackage = $aes.IV + $encryptedAESKey [System.IO.File]::WriteAllBytes($EncryptedKeyFilePath, $encryptedAESPackage) Write-EnhancedLog -Message "AES key encrypted and saved to: $EncryptedKeyFilePath" -Level "INFO" # Step 6: Convert certificate and encrypted AES key to Base64 for further use $certBytes = [System.IO.File]::ReadAllBytes($certFile) $base64Cert = [Convert]::ToBase64String($certBytes) $base64CertFile = Join-Path $CertsDir "cert.pfx.base64" [System.IO.File]::WriteAllText($base64CertFile, $base64Cert) Write-EnhancedLog -Message "Certificate Base64 encoded and saved to: $base64CertFile" -Level "INFO" $keyBytes = [System.IO.File]::ReadAllBytes($EncryptedKeyFilePath) $base64Key = [Convert]::ToBase64String($keyBytes) $base64KeyFile = Join-Path $CertsDir "secret.key.encrypted.base64" [System.IO.File]::WriteAllText($base64KeyFile, $base64Key) Write-EnhancedLog -Message "AES key and IV Base64 encoded and saved to: $base64KeyFile" -Level "INFO" } catch { Write-EnhancedLog -Message "Encryption process failed: $($_.Exception.Message)" -Level "ERROR" throw "Encryption process failed: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Encrypt-FileWithCert function" -Level "Notice" } } # # Define the parameters for the Encrypt-FileWithCert function using splatting # $params = @{ # SecretFilePath = "C:\code\secrets\myDatabase.zip" # File to be encrypted # CertsDir = "C:\temp\certs" # Directory to store certs and related files # EncryptedFilePath = "C:\temp\myDatabase.zip.encrypted" # Output path for encrypted file # EncryptedKeyFilePath = "C:\temp\secret.key.encrypted" # Output path for encrypted AES key and IV # } # # Call the function with splatted parameters # Encrypt-FileWithCert @params #EndRegion '.\Public\Encrypt-FileWithCert.ps1' 137 #Region '.\Public\Export-KeePassAttachment.ps1' -1 function Export-KeePassAttachment { <# .SYNOPSIS Exports an attachment from an entry in a KeePass database. .PARAMETER DatabasePath The full path to the KeePass database file. .PARAMETER EntryName The name of the entry containing the attachment. .PARAMETER AttachmentName The name of the attachment to be exported. .PARAMETER ExportPath The path where the attachment will be exported. .PARAMETER KeyFilePath The full path to the key file for the KeePass database. .EXAMPLE Export-KeePassAttachment -DatabasePath "C:\code\secrets\myDatabase.kdbx" -EntryName "example_entry" -AttachmentName "certificate" -ExportPath "C:\code\secrets\cert-fromdb.crt" -KeyFilePath "C:\code\secrets\myKeyFile.keyx" Exports the "certificate" attachment from the "example_entry" to the specified export path. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the KeePass database file.")] [ValidateNotNullOrEmpty()] [string]$DatabasePath, [Parameter(Mandatory = $true, HelpMessage = "The name of the entry containing the attachment.")] [ValidateNotNullOrEmpty()] [string]$EntryName, [Parameter(Mandatory = $true, HelpMessage = "The name of the attachment to be exported.")] [ValidateNotNullOrEmpty()] [string]$AttachmentName, [Parameter(Mandatory = $true, HelpMessage = "The path where the attachment will be exported.")] [ValidateNotNullOrEmpty()] [string]$ExportPath, [Parameter(Mandatory = $true, HelpMessage = "The full path to the key file for the KeePass database.")] [ValidateNotNullOrEmpty()] [string]$KeyFilePath ) Begin { Write-EnhancedLog -Message "Starting Export-KeePassAttachment function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Validate paths if (-not (Test-Path -Path $DatabasePath)) { Write-EnhancedLog -Message "The database file does not exist: $DatabasePath" -Level "ERROR" throw "The database file does not exist: $DatabasePath" } if (-not (Test-Path -Path $KeyFilePath)) { Write-EnhancedLog -Message "The key file does not exist: $KeyFilePath" -Level "ERROR" throw "The key file does not exist: $KeyFilePath" } # Construct command for KeePassXC CLI $command = "keepassxc-cli attachment-export `"$DatabasePath`" `"$EntryName`" `"$AttachmentName`" `"$ExportPath`" --key-file `"$KeyFilePath`" --no-password" Write-EnhancedLog -Message "Running command: $command" -Level "INFO" # Execute the command Invoke-Expression $command Write-EnhancedLog -Message "Attachment '$AttachmentName' exported successfully to '$ExportPath'." -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to export attachment: $($_.Exception.Message)" -Level "ERROR" throw "Failed to export attachment from the entry: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Export-KeePassAttachment function" -Level "Notice" } } # $exportAttachmentParams = @{ # DatabasePath = "C:\code\secrets\myDatabase.kdbx" # EntryName = "example_entry" # AttachmentName = "certificate" # ExportPath = "C:\code\secrets\cert-fromdb.pfx" # KeyFilePath = "C:\code\secrets\myKeyFile.keyx" # } # Export-KeePassAttachment @exportAttachmentParams #EndRegion '.\Public\Export-KeePassAttachment.ps1' 97 #Region '.\Public\Install-Keepass.ps1' -1 function Install-KeePass { <# .SYNOPSIS Installs KeePass if it is not already installed and validates the installation before and after. .PARAMETER KeePassDownloadUrl The URL to download the KeePass installer. .PARAMETER KeePassInstallPath The installation path for KeePass. .PARAMETER MaxRetries The maximum number of retries for the file download if the first attempt fails. .EXAMPLE Install-KeePass Installs KeePass if it is not already installed. #> [CmdletBinding()] param ( [Parameter(Mandatory = $false, HelpMessage = "The URL to download the KeePass installer.")] [ValidateNotNullOrEmpty()] [string]$KeePassDownloadUrl = "https://sourceforge.net/projects/keepass/files/KeePass%202.x/2.57/KeePass-2.57-Setup.exe/download", [Parameter(Mandatory = $false, HelpMessage = "The installation path for KeePass.")] [ValidateNotNullOrEmpty()] [string]$KeePassInstallPath = "$env:ProgramFiles\KeePassPasswordSafe2", [Parameter(Mandatory = $false, HelpMessage = "Maximum number of retries for the download if it fails.")] [ValidateRange(1, 10)] [int]$MaxRetries = 3 ) Begin { Write-EnhancedLog -Message "Starting Install-KeePass function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Validate if KeePass is already installed $validateParams = @{ SoftwareName = "KeePass" RegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KeePassPasswordSafe2_is1" ExePath = "$KeePassInstallPath\KeePass.exe" MinVersion = [version]"2.57" LatestVersion = [version]"2.57" } } Process { try { Write-EnhancedLog -Message "Validating KeePass installation before attempting installation..." -Level "INFO" $validationResult = Validate-SoftwareInstallation @validateParams if ($validationResult.IsInstalled) { Write-EnhancedLog -Message "KeePass is already installed and meets the minimum version requirement." -Level "INFO" return $true } # KeePass is not installed, proceed with downloading and installing Write-EnhancedLog -Message "KeePass is not installed or does not meet the version requirement. Proceeding with installation." -Level "WARNING" Write-Host "Downloading KeePass installer..." -ForegroundColor Cyan $installerPath = "$env:TEMP\KeePassSetup.exe" # Use the Start-FileDownloadWithRetry function to download the installer $downloadParams = @{ Source = $KeePassDownloadUrl Destination = $installerPath MaxRetries = $MaxRetries } Start-FileDownloadWithRetry @downloadParams Write-Host "Installing KeePass..." -ForegroundColor Cyan Start-Process -FilePath $installerPath -ArgumentList "/VERYSILENT", "/NORESTART" -Wait -NoNewWindow -ErrorAction Stop # Remove the installer after installation Remove-Item -Path $installerPath # Validate the installation again after the installation Write-EnhancedLog -Message "Validating KeePass installation after installation..." -Level "INFO" $postInstallValidation = Validate-SoftwareInstallation @validateParams if ($postInstallValidation.IsInstalled) { Write-Host "KeePass installed successfully." -ForegroundColor Green Write-EnhancedLog -Message "KeePass installed successfully. Version: $($postInstallValidation.InstalledVersion)" -Level "INFO" } else { Write-EnhancedLog -Message "KeePass installation failed or does not meet the version requirement after installation." -Level "ERROR" throw "KeePass installation validation failed." } } catch { Write-EnhancedLog -Message "Error during KeePass installation: $($_.Exception.Message)" -Level "ERROR" Handle-Error -ErrorRecord $_ throw } finally { Write-EnhancedLog -Message "Exiting Install-KeePass function" -Level "Notice" } } End { # No additional actions in the End block. } } # Install-KeePass #EndRegion '.\Public\Install-Keepass.ps1' 108 #Region '.\Public\Install-KeePassXCCli.ps1' -1 function Install-KeePassXCCli { <# .SYNOPSIS Installs KeePassXC CLI based on the operating system and validates the installation before and after. .PARAMETER OS The operating system where KeePassXC CLI will be installed. Valid values are 'Windows' or 'Linux'. .PARAMETER MaxRetries The maximum number of retries for the file download if the first attempt fails. .EXAMPLE Install-KeePassXCCli -OS 'Windows' Installs KeePassXC CLI on a Windows system. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The operating system where KeePassXC CLI will be installed.")] [ValidateSet('Windows', 'Linux')] [string]$OS, [Parameter(Mandatory = $false, HelpMessage = "Maximum number of retries for the download if it fails.")] [ValidateRange(1, 10)] [int]$MaxRetries = 3 ) Begin { Write-EnhancedLog -Message "Starting Install-KeePassXCCli function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Validate parameters for the software based on OS if ($OS -eq 'Windows') { $validateParams = @{ SoftwareName = "KeePassXC CLI" RegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\KeePassXC_is1" ExePath = "$env:ProgramFiles\KeePassXC\KeePassXC.exe" MinVersion = [version]"2.7.9" LatestVersion = [version]"2.7.9" } } elseif ($OS -eq 'Linux') { $validateParams = @{ SoftwareName = "KeePassXC CLI" ExePath = "/usr/local/bin/keepassxc-cli" MinVersion = [version]"2.7.9" LatestVersion = [version]"2.7.9" } } } Process { try { Write-EnhancedLog -Message "Validating KeePassXC CLI installation before attempting installation..." -Level "INFO" $validationResult = Validate-SoftwareInstallation @validateParams if ($validationResult.IsInstalled) { Write-EnhancedLog -Message "KeePassXC CLI is already installed and meets the minimum version requirement." -Level "INFO" return $true } # KeePassXC CLI is not installed, proceed with downloading and installing Write-EnhancedLog -Message "KeePassXC CLI is not installed or does not meet the version requirement. Proceeding with installation." -Level "WARNING" if ($OS -eq 'Windows') { Write-Host "Downloading KeePassXC CLI installer for Windows..." -ForegroundColor Cyan $installerUrl = "https://github.com/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-Win64.msi" $installerPath = "$env:TEMP\KeePassXC.msi" # Use the Start-FileDownloadWithRetry function to download the installer $downloadParams = @{ Source = $installerUrl Destination = $installerPath MaxRetries = $MaxRetries } Start-FileDownloadWithRetry @downloadParams # Install KeePassXC CLI using msiexec Write-Host "Installing KeePassXC CLI..." -ForegroundColor Cyan Start-Process msiexec.exe -ArgumentList "/i $installerPath /quiet /norestart" -Wait -NoNewWindow -ErrorAction Stop # Remove the installer after installation Remove-Item -Path $installerPath } elseif ($OS -eq 'Linux') { Write-Host "Downloading KeePassXC CLI for Linux..." -ForegroundColor Cyan $appImageUrl = "https://github.com/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-x86_64.AppImage" $appImagePath = "/usr/local/bin/keepassxc-cli" # Use the Start-FileDownloadWithRetry function to download the AppImage $downloadParams = @{ Source = $appImageUrl Destination = $appImagePath MaxRetries = $MaxRetries } Start-FileDownloadWithRetry @downloadParams # Make the AppImage executable Write-Host "Setting permissions for KeePassXC CLI AppImage..." -ForegroundColor Cyan sudo chmod +x $appImagePath } # Validate the installation again after the installation Write-EnhancedLog -Message "Validating KeePassXC CLI installation after installation..." -Level "INFO" $postInstallValidation = Validate-SoftwareInstallation @validateParams if ($postInstallValidation.IsInstalled) { Write-Host "KeePassXC CLI installed successfully." -ForegroundColor Green Write-EnhancedLog -Message "KeePassXC CLI installed successfully. Version: $($postInstallValidation.InstalledVersion)" -Level "INFO" } else { Write-EnhancedLog -Message "KeePassXC CLI installation failed or does not meet the version requirement after installation." -Level "ERROR" throw "KeePassXC CLI installation validation failed." } } catch { Write-EnhancedLog -Message "Error during KeePassXC CLI installation: $($_.Exception.Message)" -Level "ERROR" Handle-Error -ErrorRecord $_ throw } finally { Write-EnhancedLog -Message "Exiting Install-KeePassXCCli function" -Level "Notice" } } End { # No additional actions in the End block. } } # if ($PSVersionTable.PSVersion.Major -ge 6) { # # PowerShell 7+ (cross-platform) # if ($IsWindows) { # $OS = 'Windows' # } elseif ($IsLinux) { # $OS = 'Linux' # } else { # throw "Unsupported operating system." # } # } else { # # PowerShell 5 (Windows-only) # $OS = 'Windows' # } # Write-Host "Operating system detected: $OS" # # Install KeePassXC CLI if it's not already installed # if (-not (Get-Command keepassxc-cli -ErrorAction SilentlyContinue)) { # Install-KeePassXCCli -OS $OS # } #EndRegion '.\Public\Install-KeePassXCCli.ps1' 158 #Region '.\Public\New-KeePassDatabase.ps1' -1 function New-KeePassDatabase { <# .SYNOPSIS Creates a new KeePass database with a specified path and key file. .PARAMETER DatabasePath The full path to the KeePass database file. .PARAMETER KeyFilePath The full path to the key file for the KeePass database. .EXAMPLE New-KeePassDatabase -DatabasePath "C:\code\secrets\myDatabase.kdbx" -KeyFilePath "C:\code\secrets\myKeyFile.keyx" Creates a new KeePass database at the specified path with the given key file. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the KeePass database file.")] [ValidateNotNullOrEmpty()] [string]$DatabasePath = "C:\code\secrets\myDatabase.kdbx", [Parameter(Mandatory = $true, HelpMessage = "The full path to the key file for the KeePass database.")] [ValidateNotNullOrEmpty()] [string]$KeyFilePath = "C:\code\secrets\myKeyFile.keyx" ) Begin { Write-EnhancedLog -Message "Starting New-KeePassDatabase function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Extract directories from paths $databaseDirectory = Split-Path -Path $DatabasePath $keyFileDirectory = Split-Path -Path $KeyFilePath # Check if the directory exists, and create it if it doesn't if (-not (Test-Path -Path $databaseDirectory)) { Write-Host "Directory does not exist. Creating directory: $databaseDirectory" -Level "Warning" New-Item -Path $databaseDirectory -ItemType Directory | Out-Null } else { Write-EnhancedLog -Message "Directory already exists: $databaseDirectory" -Level "Notice" } } Process { # Check if the directory for the database exists if (-not (Test-Path -Path $databaseDirectory)) { Write-EnhancedLog -Message "The directory for the database path does not exist: $databaseDirectory" -Level "ERROR" throw "The directory for the database path does not exist." } # Check if the directory for the key file exists if (-not (Test-Path -Path $keyFileDirectory)) { Write-EnhancedLog -Message "The directory for the key file path does not exist: $keyFileDirectory" -Level "ERROR" throw "The directory for the key file path does not exist." } # Command to create KeePass database with the specified key file $command = "keepassxc-cli db-create `"$DatabasePath`" --set-key-file `"$KeyFilePath`"" try { Invoke-Expression $command Write-EnhancedLog -Message "Database '$DatabasePath' created successfully with key file '$KeyFilePath'." -Level "INFO" } catch { Write-EnhancedLog -Message "Failed to create the KeePass database: $($_.Exception.Message)" -Level "ERROR" throw "Failed to create the database. $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting New-KeePassDatabase function" -Level "Notice" } } # # Define the path to the database and key file # $databaseParams = @{ # DatabasePath = "C:\code\secrets\myDatabase.kdbx" # KeyFilePath = "C:\code\secrets\myKeyFile.keyx" # } # # Now you can safely create the database # New-KeePassDatabase @databaseParams # Wait-Debugger #EndRegion '.\Public\New-KeePassDatabase.ps1' 88 #Region '.\Public\Unzip-Directory.ps1' -1 function Unzip-Directory { <# .SYNOPSIS Extracts the contents of a zip archive to a specified directory. .PARAMETER ZipFilePath The full path to the zip file that you want to extract. .PARAMETER DestinationDirectory The directory where the contents of the zip file will be extracted. .EXAMPLE $params = @{ ZipFilePath = "C:\code\secrets\vault.zip" DestinationDirectory = "C:\code\secrets\vault" } Unzip-Directory @params Unzips the archive to the specified directory. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the zip file.")] [ValidateNotNullOrEmpty()] [string]$ZipFilePath, [Parameter(Mandatory = $true, HelpMessage = "The directory where the contents will be extracted.")] [ValidateNotNullOrEmpty()] [string]$DestinationDirectory ) Begin { Write-EnhancedLog -Message "Starting Unzip-Directory function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Check if the zip file exists if (-not (Test-Path -Path $ZipFilePath)) { Write-EnhancedLog -Message "Zip file does not exist: $ZipFilePath" -Level "ERROR" throw "Zip file does not exist: $ZipFilePath" } # Ensure the destination directory exists if (-not (Test-Path -Path $DestinationDirectory)) { New-Item -Path $DestinationDirectory -ItemType Directory | Out-Null Write-EnhancedLog -Message "Created directory: $DestinationDirectory" -Level "INFO" } # Extract the zip archive to the destination directory [System.IO.Compression.ZipFile]::ExtractToDirectory($ZipFilePath, $DestinationDirectory) Write-EnhancedLog -Message "Successfully unzipped the archive to: $DestinationDirectory" -Level "INFO" } catch { Write-EnhancedLog -Message "Error during unzipping: $($_.Exception.Message)" -Level "ERROR" throw "Unzipping process failed: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Unzip-Directory function" -Level "Notice" } } #EndRegion '.\Public\Unzip-Directory.ps1' 65 #Region '.\Public\Upload-GitHubReleaseAsset.ps1' -1 function Upload-GitHubReleaseAsset { <# .SYNOPSIS Uploads an asset to a GitHub release using the GitHub CLI. .PARAMETER repoOwner The owner of the GitHub repository. .PARAMETER repoName The name of the GitHub repository. .PARAMETER releaseTag The tag of the release where the asset will be uploaded. .PARAMETER filePath The path of the file to be uploaded as an asset. .EXAMPLE $params = @{ repoOwner = "aollivierre" repoName = "Vault" releaseTag = "0.1" filePath = "C:\temp2\vault.GH.Asset.zip" } Upload-GitHubReleaseAsset @params #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The owner of the GitHub repository.")] [ValidateNotNullOrEmpty()] [string]$repoOwner, [Parameter(Mandatory = $true, HelpMessage = "The name of the GitHub repository.")] [ValidateNotNullOrEmpty()] [string]$repoName, [Parameter(Mandatory = $true, HelpMessage = "The tag of the release where the asset will be uploaded.")] [ValidateNotNullOrEmpty()] [string]$releaseTag, [Parameter(Mandatory = $true, HelpMessage = "The path of the file to be uploaded as an asset.")] [ValidateNotNullOrEmpty()] [string]$filePath ) Begin { Write-EnhancedLog -Message "Starting GitHub Asset Upload Script" -Level "NOTICE" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters } Process { try { # Check if the file exists Write-EnhancedLog -Message "Checking if file exists: $filePath" -Level "INFO" if (-not (Test-Path -Path $filePath)) { Write-EnhancedLog -Message "File does not exist: $filePath" -Level "ERROR" throw "File does not exist: $filePath" } Write-EnhancedLog -Message "File exists: $filePath" -Level "INFO" # Upload the file using GitHub CLI Write-EnhancedLog -Message "Uploading asset $filePath to release $releaseTag..." -Level "INFO" $command = "gh release upload $releaseTag $filePath --repo $repoOwner/$repoName" Invoke-Expression $command Write-EnhancedLog -Message "File uploaded successfully: $filePath" -Level "INFO" } catch { Handle-Error -Message "Error during upload: $($_.Exception.Message)" -ErrorRecord $_ throw } } End { Write-EnhancedLog -Message "Script finished." -Level "NOTICE" } } #EndRegion '.\Public\Upload-GitHubReleaseAsset.ps1' 79 #Region '.\Public\Zip-Directory.ps1' -1 function Zip-Directory { <# .SYNOPSIS Zips the contents of a specified directory into a zip archive. .PARAMETER SourceDirectory The full path to the directory that you want to zip. .PARAMETER ZipFilePath The path where the zip archive will be saved. .EXAMPLE $params = @{ SourceDirectory = "C:\code\secrets\vault" ZipFilePath = "C:\code\secrets\vault.zip" } Zip-Directory @params Zips the contents of the directory into an archive. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = "The full path to the directory that you want to zip.")] [ValidateNotNullOrEmpty()] [string]$SourceDirectory, [Parameter(Mandatory = $true, HelpMessage = "The path where the zip archive will be saved.")] [ValidateNotNullOrEmpty()] [string]$ZipFilePath ) Begin { Write-EnhancedLog -Message "Starting Zip-Directory function" -Level "Notice" Log-Params -Params $PSCmdlet.MyInvocation.BoundParameters # Determine the destination directory and create it if necessary $destinationDir = Split-Path -Path $ZipFilePath -Parent if (-not (Test-Path -Path $destinationDir)) { New-Item -Path $destinationDir -ItemType Directory | Out-Null Write-EnhancedLog -Message "Created destination directory: $destinationDir" -Level "INFO" } } Process { try { # Check if the source directory exists if (-not (Test-Path -Path $SourceDirectory)) { Write-EnhancedLog -Message "Source directory does not exist: $SourceDirectory" -Level "ERROR" throw "Source directory does not exist: $SourceDirectory" } # Create the zip archive from the directory [System.IO.Compression.ZipFile]::CreateFromDirectory($SourceDirectory, $ZipFilePath, [System.IO.Compression.CompressionLevel]::Optimal, $false) Write-EnhancedLog -Message "Successfully zipped the directory to: $ZipFilePath" -Level "INFO" } catch { Write-EnhancedLog -Message "Error during zipping: $($_.Exception.Message)" -Level "ERROR" throw "Zipping process failed: $($_.Exception.Message)" } } End { Write-EnhancedLog -Message "Exiting Zip-Directory function" -Level "Notice" } } #EndRegion '.\Public\Zip-Directory.ps1' 66 |