Public/Protect-VellumPdfDocument.ps1
|
function Protect-VellumPdfDocument { <# .SYNOPSIS Applies password protection and usage permissions to a VellumPdf document. .DESCRIPTION Wraps Document.Encrypt(PdfEncryptionSettings). Encryption is staged in memory and takes effect when the document is written by Save-VellumPdfDocument. The same Document instance is returned so the call can be chained in a pipeline. At least one of -UserPassword or -OwnerPassword must be supplied. Supplying both is the most common configuration: the user password opens the document for reading and the owner password unlocks all operations regardless of the -Permission set. PDF/A CONSTRAINT: PDF/A (ISO 19005) explicitly forbids encryption. If the document's Conformance is anything other than None (e.g. PdfA2b, PdfA2u, PdfA2a) this cmdlet throws a clear terminating error before calling Encrypt(). The VellumPdf library also enforces this constraint at Save() time, so the fail-fast check here gives an earlier, more actionable message. SIGNING CONSTRAINT: encryption and digital signatures cannot be combined (the library rejects the pair at save time). This cmdlet throws if a signature has been staged with Set-VellumPdfSignature, and vice versa. PASSWORDS: Both password parameters accept [securestring] to keep credentials out of command history and verbose output. Use Read-Host -AsSecureString for interactive entry, or ConvertTo-SecureString for scripts. .PARAMETER Document The VellumPdf document to protect. Accepts pipeline input. .PARAMETER UserPassword The password required to open the document. Plain-text intermediates are never stored in variables or written to output streams. .PARAMETER OwnerPassword The password that grants unrestricted access, overriding -Permission restrictions. Recommended when using -Permission to limit operations. .PARAMETER Permission One or more permission flags to allow. Valid values: None - no permissions granted beyond opening Print - low-resolution printing Modify - modify document content Copy - copy or extract text and graphics Annotate - add or modify annotations and fill forms FillForms - fill in existing form fields Extract - extract text and graphics (accessibility) Assemble - insert, rotate, or delete pages and bookmarks PrintHighRes - high-resolution (faithful) printing All - all of the above (default) Multiple values are combined as flags. Example: -Permission Print,Copy .PARAMETER EncryptMetadata When specified, document metadata (XMP) is also encrypted. When omitted the library default applies (metadata is encrypted by default). .EXAMPLE $pw = Read-Host -Prompt 'Password' -AsSecureString New-VellumPdfDocument | Add-VellumPdfParagraph -Text 'Confidential.' | Protect-VellumPdfDocument -UserPassword $pw | Save-VellumPdfDocument -Path ./protected.pdf .EXAMPLE $userPw = ConvertTo-SecureString 'userpass' -AsPlainText -Force $ownerPw = ConvertTo-SecureString 'ownerpass' -AsPlainText -Force New-VellumPdfDocument | Add-VellumPdfParagraph -Text 'Restricted copy.' | Protect-VellumPdfDocument -UserPassword $userPw -OwnerPassword $ownerPw ` -Permission Print,Copy | Save-VellumPdfDocument -Path ./restricted.pdf .EXAMPLE # Owner-only (no user password needed to open; permissions still enforced) $ownerPw = ConvertTo-SecureString 's3cret' -AsPlainText -Force New-VellumPdfDocument | Add-VellumPdfParagraph -Text 'Body.' | Protect-VellumPdfDocument -OwnerPassword $ownerPw -Permission Print | Save-VellumPdfDocument -Path ./owner-only.pdf .OUTPUTS VellumPdf.Layout.Document (the same instance, for chaining) #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Mutates an in-memory document object only; no external/system state change.')] [CmdletBinding()] [OutputType([VellumPdf.Layout.Document])] param( [Parameter(Mandatory, ValueFromPipeline)] [VellumPdf.Layout.Document]$Document, [securestring]$UserPassword, [securestring]$OwnerPassword, [ValidateSet('None', 'Print', 'Modify', 'Copy', 'Annotate', 'FillForms', 'Extract', 'Assemble', 'PrintHighRes', 'All')] [string[]]$Permission = @('All'), [switch]$EncryptMetadata ) process { Assert-VellumPdfDocumentOpen -Document $Document -CommandName 'Protect-VellumPdfDocument' # Applying encryption twice leaves an orphaned /Encrypt object in the # output (the second settings win, the first linger unreferenced). if ($Document.PSObject.Properties['PSVellumProtected']) { throw ('Protect-VellumPdfDocument: this document is already protected. ' + 'Encryption can only be applied once per document.') } # The library rejects Encrypt() + Sign() at save time; fail fast here # with the same constraint so the error points at the right cmdlet. if ($Document.PSObject.Properties['PSVellumSignature']) { throw ('Protect-VellumPdfDocument: encryption and digital signatures cannot be combined. ' + 'Remove the Set-VellumPdfSignature call to encrypt this document.') } # Require at least one password. if (-not $PSBoundParameters.ContainsKey('UserPassword') -and -not $PSBoundParameters.ContainsKey('OwnerPassword')) { throw 'Protect-VellumPdfDocument: at least one of -UserPassword or -OwnerPassword must be supplied.' } # Fail fast: PDF/A forbids encryption (ISO 19005-2 section 6.3.1). if ($Document.Conformance -ne [VellumPdf.Document.PdfConformance]::None) { throw ("Protect-VellumPdfDocument: PDF/A conformance ($($Document.Conformance)) does not allow " + 'encryption. Remove -Conformance or use a non-conformant document.') } # Build combined permissions flags. $flags = [VellumPdf.Encryption.PdfPermissions]::None foreach ($p in $Permission) { $flags = $flags -bor [VellumPdf.Encryption.PdfPermissions]$p } $settings = [VellumPdf.Encryption.PdfEncryptionSettings]::new() $settings.Permissions = $flags # Convert SecureString passwords to plain text only at the point of assignment. if ($PSBoundParameters.ContainsKey('UserPassword')) { $settings.UserPassword = [System.Net.NetworkCredential]::new('', $UserPassword).Password } if ($PSBoundParameters.ContainsKey('OwnerPassword')) { $settings.OwnerPassword = [System.Net.NetworkCredential]::new('', $OwnerPassword).Password } if ($PSBoundParameters.ContainsKey('EncryptMetadata')) { $settings.EncryptMetadata = $EncryptMetadata.IsPresent } [void]$Document.Encrypt($settings) $Document.PSObject.Properties.Add([psnoteproperty]::new('PSVellumProtected', $true)) $Document } } |