PowerShell脚本对docx、PDF、JPG等非文本文件执行CMS加解密后文件损坏问题
Got it, let's break down why your script is breaking binary files like PDFs or DOCXs—and fix it.
The core issue is how you're reading the file. Get-Content without any flags reads files as text, which tries to interpret binary data as characters using your system's default encoding. This mangles the raw byte structure of non-text files (like PDFs, DOCXs, images) before encryption, so even after decryption, the original byte data is lost forever.
We need to handle files as raw byte streams instead of text. Here's the adjusted script that works for all file types:
$newcert="cert-test" # Create self-signed certificate (unchanged from your original) New-SelfSignedCertificate -DnsName $newcert -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsage KeyEncipherment,DataEncipherment,KeyAgreement -Type DocumentEncryptionCert -NotAfter (Get-Date).AddDays(30) -FriendlyName $newcert $cert=Get-ChildItem -Path Cert:\CurrentUser\My\ | Where-Object subject -like "*$newcert*" $thumb=$cert.thumbprint $file = "d:\target\test\Test.pdf" $encryptedFile = "$file.cms" # Use a separate file for encrypted output to avoid overwriting your original # --- Encrypt the File --- # Read the file as raw binary bytes (no text encoding conversion) $fileBytes = [System.IO.File]::ReadAllBytes($file) # Encrypt the byte array and save to the encrypted output file $fileBytes | Protect-CmsMessage -To $thumb -OutFile $encryptedFile # --- Decrypt the File --- # Read the encrypted file's raw bytes $encryptedBytes = [System.IO.File]::ReadAllBytes($encryptedFile) # Decrypt and write the original byte structure back to disk $decryptedBytes = $encryptedBytes | Unprotect-CmsMessage -To $thumb [System.IO.File]::WriteAllBytes($file, $decryptedBytes) # Overwrites original; adjust path if you want a separate decrypted file
- Reading raw bytes: Instead of
Get-Content, we use[System.IO.File]::ReadAllBytes()to grab every byte of the original file without any text encoding logic. This preserves the exact structure of binary files. - Separate encrypted file: I added a
.cmsextension to the encrypted output to avoid accidentally overwriting your original file during testing—you can tweak this if you prefer, but it's a safer approach. - Writing raw bytes: After decryption,
[System.IO.File]::WriteAllBytes()ensures we write the decrypted byte array back exactly as it was, restoring the original file structure.
If you're using PowerShell Core 6 or later, you can use native PowerShell cmdlets with the -AsByteStream flag instead of .NET methods:
# Encrypt with PowerShell 6+ Get-Content $file -AsByteStream | Protect-CmsMessage -To $thumb -OutFile $encryptedFile # Decrypt with PowerShell 6+ Get-Content $encryptedFile -AsByteStream | Unprotect-CmsMessage -To $thumb | Set-Content $file -AsByteStream
The -AsByteStream flag tells PowerShell to handle the file as raw binary data, skipping any text encoding that would break non-text files.
内容的提问来源于stack exchange,提问作者chaz stone

