PSPGP is a PowerShell module that provides PGP functionality in PowerShell. It allows encrypting and decrypting files/folders and strings using PGP. PSPGP uses the following .NET library:
- PgpCore - licensed MIT
PSPGP uses PgpCore 8.0. New operations therefore default to AES-256 encryption, SHA-256 hashing, ZIP compression, and 3072-bit keys with a certainty of 24. Existing encrypted data remains readable; set the algorithm parameters explicitly only when an older integration requires legacy output.
CI for this branch runs in GitHub Actions via the .github/workflows/test-dotnet.yml and .github/workflows/test-powershell.yml workflows.
Exported cmdlets:
Get-PGPInspectGet-PGPKeyGet-PGPKeyInfoNew-PGPKeyProtect-PGPTest-PGPUnprotect-PGP
No script functions or aliases are exported.
Current capabilities:
- Encrypt and decrypt files, folders, and strings with public/private keys
- Encrypt and decrypt strings, files, and folders symmetrically with a passphrase
- Create signed, detached-signature, and clear-signed content and verify it with one or more public keys
- Write verified clear content from signed files to an output path
- Inspect signed, encrypted, and armored message metadata with
Get-PGPInspect, including encrypted recipient key IDs when available - Download public keys from a key server and inspect local key IDs, fingerprints, size, creation and expiration dates, and key state
- Generate new key pairs and optionally upload the public key
The checked-in sample assets under Examples\Keys use the PublicPGP1.asc / PrivatePGP1.asc naming pattern.
Install-Module -Name PSPGP -AllowClobber -ForceForce and AllowClobber aren't necessary, but they do skip errors in case some appear.
Update-Module -Name PSPGPThat's it. Whenever there's a new version, you run the command, and you can enjoy it. Remember that you may need to close, reopen PowerShell session if you have already used module before updating it.
The essential thing is if something works for you on production, keep using it till you test the new version on a test computer. I do changes that may not be big, but big enough that auto-update may break your code. For example, a small rename to a parameter, and your code stops working! Be responsible!
PSPGP supports Windows PowerShell 5.1 and PowerShell 7+.
On Windows PowerShell 5.1, the module requires .NET Framework 4.7.2 or newer. On PowerShell 7+, the module works cross-platform on Windows, Linux, and macOS.
PgpCore 8 also provides typed errors for invalid key material, wrong passphrases, missing keys, unsupported input, and integrity failures. PSPGP maps these to PowerShell error categories such as InvalidData, AuthenticationError, ObjectNotFound, and SecurityError, making try/catch and $Error inspection more useful.
New-PGPKey -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc -UserName 'przemyslaw.klys' -Password 'ZielonaMila9!'
New-PGPKey -FilePathPublic $PSScriptRoot\Keys\ExpiringPublic.asc -FilePathPrivate $PSScriptRoot\Keys\ExpiringPrivate.asc -UserName 'user@example.com' -Password 'secret' -Strength 4096 -Certainty 24 -KeyExpirationInSeconds 31536000 -PreferredHashAlgorithm Sha256,Sha512 -PreferredSymmetricKeyAlgorithm Aes256Protect-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -FolderPath $PSScriptRoot\Test -OutputFolderPath $PSScriptRoot\EncodedUnprotect-PGP -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc -Password 'ZielonaMila9!' -FolderPath $PSScriptRoot\Encoded -OutputFolderPath $PSScriptRoot\DecodedDecrypting can also be done using multiple private keys:
Unprotect-PGP -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc,$PSScriptRoot\Keys\PrivatePGP2.asc -Password 'ZielonaMila9!' -String $ProtectedString$ProtectedString = Protect-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -String "This is string to encrypt"
Unprotect-PGP -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc -Password 'ZielonaMila9!' -String $ProtectedString$ProtectedString = Protect-PGP -SymmetricPassphrase 'SymmetricPass123!' -String 'This is string to encrypt'
Unprotect-PGP -SymmetricPassphrase 'SymmetricPass123!' -String $ProtectedString$Signature = Protect-PGP -SignOnly -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Signed text'
# Verify using one or more public keys
$Result = Test-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc,$PSScriptRoot\Keys\PublicPGP2.asc -String $Signature
$Result.ClearText$Signature = Protect-PGP -SignOnly -Detached -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Detached signed text'
Test-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -String 'Detached signed text' -Signature $Signature
Protect-PGP -SignOnly -Detached -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -FilePath $PSScriptRoot\Test\Test1.txt -OutFilePath $PSScriptRoot\Test\Test1.txt.sig
Test-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -FilePath $PSScriptRoot\Test\Test1.txt -SignaturePath $PSScriptRoot\Test\Test1.txt.sig$ClearSigned = Protect-PGP -ClearSign -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Signed text'
Test-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -String $ClearSigned -ClearSigned$Signature = Protect-PGP -SignOnly -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Signed text'
Get-PGPInspect -String $SignatureGet-PGPInspect returns metadata for signed content, armored messages, and encrypted messages that can be inspected without decrypting the payload. For encrypted content it also reports recipient key IDs when the packet exposes them.
$Signature = Protect-PGP -SignOnly -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Signed text'
Test-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -String $Signature$Protected = Protect-PGP -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -SignKey $PSScriptRoot\Keys\PrivatePGP1.asc -SignPassword 'ZielonaMila9!' -String 'Signed and encrypted text'
Unprotect-PGP -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -Password 'ZielonaMila9!' -String $Protected -VerifyWhen -Verify is used with file output, PSPGP writes decrypted content through a temporary file and only moves it to the requested output path after signature verification succeeds.
Get-PGPKey -KeyServer 'https://keys.openpgp.org' -Search 'user@example.com'
$KeyInfo = Get-PGPKeyInfo -FilePath $PSScriptRoot\Keys\PublicPGP1.asc
$KeyInfo | Select-Object KeyId, Fingerprint, Algorithm, BitStrength, CreationTime, Expiration, IsEncryptionKey, IsRevoked
New-PGPKey -FilePathPublic $PSScriptRoot\Keys\PublicPGP1.asc -FilePathPrivate $PSScriptRoot\Keys\PrivatePGP1.asc -UserName 'user@example.com' -Password 'secret' -UploadKeyServer 'https://keys.openpgp.org'See the Examples folder for runnable scripts:
Examples\Example-GeneratePGP.ps1Examples\Example-EncryptString.ps1Examples\Example-EncryptStringMultipleKeys.ps1Examples\Example-EncryptStringNoPassword.ps1Examples\Example-DecryptString.ps1Examples\Example-EncryptFolder.ps1Examples\Example-EncryptFolderMultipleKeys.ps1Examples\Example-DecryptFolder.ps1Examples\Example-DecryptFile.ps1Examples\Example-SignString.ps1Examples\Example-VerifySignature.ps1Examples\Example-DetachedSignature.ps1Examples\Example-ClearSignString.ps1Examples\Example-SymmetricString.ps1Examples\Example-InspectSignedString.ps1Examples\Example-GetPGPKeyInfo.ps1