Pages

Thursday, February 18, 2021

Using PowerShell to Batch Password Protect Adobe PDF Files in a Directory

As a follow up to my previous post:

Attempting to use itextsharp.dll throws the error: "Could not load file or assembly 'BouncyCastle.Crypto, Version=1.8.6.0, Culture=neutral, PublicKeyToken=0e99375e54769942'..."

http://terenceluk.blogspot.com/2021/02/attempting-to-use-itextsharpdll-throws.html

… the script provided in the blog post did not match the requirements I needed so I’ve gone ahead to modify it and created two versions:

  1. Uses an Excel spreadsheet with predefined passwords to password protect PDF documents and fills in the name of the file
  2. Uses an Excel spreadsheet to fill in PDF file names and the randomly generated password used to password protect it

The following are the two PowerShell scripts:

Using PowerShell to Password Protect Adobe PDF Files (requires only passwords)

The following describes how to use PowerShell to password protect Adobe PDF files with a reference spreadsheet with only the passwords defined. The PowerShell script’s logic is as follows:

  1. Opens up a spreadsheet with two columns:
    1. Source Name < blank
    2. Password < password specified
  2. Looks into a directory and begins password protecting the documents with the passwords in the spreadsheet AND fills in the source name column with the file name
  3. Saves the PDF into another directory

1. Begin by creating a spreadsheet with two columns leaving the Source Name blank with the Password column filled in:

    a) Source Name

    b) Password

image

2. Proceed by creating a .ps1 file from the following code (also attached as PasswordProtectPDF.ps1):

Add-Type -Path "C:\itextsharp.5.5.13.2\lib\BouncyCastle.Crypto.dll"

[System.Reflection.Assembly]::LoadFrom("itextsharp.dll")

function PSUsing {

param (

[System.IDisposable] $excelSheetNumbernputObject = $(throw "The parameter -inputObject is required."),

[ScriptBlock] $scriptBlock = $(throw "The parameter -scriptBlock is required.")

)

Try {

&$scriptBlock

}

Finally {

if ($excelSheetNumbernputObject.psbase -eq $null) {

$excelSheetNumbernputObject.Dispose()

} else {

$excelSheetNumbernputObject.psbase.Dispose()

}

}

}

$sourcePath = "C:\PDF\"

$destinationPath = "C:\PDF\WithPassword\"

$excelReferenceSheet = "c:\ScriptsNew\PDFList.xlsx"

$xlCellTypeLastCell = 11

$startRow,$col=2,1

$excelSheetNumber=1

# OPEN EXCEL FILE WITH PASSWORDS

$excel=new-object -com excel.application

$excel.DisplayAlerts = $false

$excel.Visible = $false

$workbook=$excel.workbooks.open($excelReferenceSheet)

$worksheet=$workbook.Sheets.Item($excelSheetNumber)

$rowIncrement=0;

# BEGIN TRAVERSING THROUGH SOURCE FOLDER

$files = Get-ChildItem "C:\PDF\\*" -file

foreach ($f in $files){

# WRITE SOURCE FILE NAME INTO SPREADSHEET

#Write-Output $f.name

$worksheet.Cells.Item($startRow + $rowIncrement,$col) = $f.name

#RETRIEVE PASSWORD FROM EXCEL

$password=$worksheet.Cells.Item($startRow + $rowIncrement,$col+1).Value2

#Write-Output $password

$rowIncrement++

$fullSourcePathAndFileName = $sourcePath + $f.name

$destinationPathAndFileName = $destinationPath + $f.name

# PASSWORD PROTECT PDF

New-Object PSObject -Property @{Source=$sourcePath + $sourceFileName;Destination=$destinationFileName;Password=$password}

$file = New-Object System.IO.FileInfo $fullSourcePathAndFileName

$fileWithPassword = New-Object System.IO.FileInfo $destinationPathAndFileName

PSUsing ( $fileStreamIn = $file.OpenRead() ) {

PSUsing ( $fileStreamOut = New-Object System.IO.FileStream($fileWithPassword.FullName,[System.IO.FileMode]::Create,[System.IO.FileAccess]::Write,[System.IO.FileShare]::None) ) {

PSUsing ( $reader = New-Object iTextSharp.text.pdf.PdfReader $fileStreamIn ) {

[iTextSharp.text.pdf.PdfEncryptor]::Encrypt($reader, $fileStreamOut, $true, $password, $password, [iTextSharp.text.pdf.PdfWriter]::ALLOW_PRINTING)

}

}

}

}

$workbook.SaveAs($excelReferenceSheet)

$excel.Close

$excel.Quit()

[System.GC]::Collect()

[System.GC]::WaitForPendingFinalizers()

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet)

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

Remove-Variable -Name excel

3. Open the ps1 script and edit the 3 paths as highlighted in red above:

$sourcePath = "C:\PDF\" <-- Directory containing the source PDFs

$destinationPath = "C:\PDF\WithPassword\" <-- Directory containing the source PDFs

$excelReferenceSheet = "c:\ScriptsNew\PDFList.xlsx" <-- Directory where the spreadsheet that the script will reference for the PDF file name and password

$files = Get-ChildItem "C:\PDF\\*" -file <-- Update the C:\PDF to the directory containing the source PDFs

4. Download the following .nupkg packages:

iTextSharp 5.5.13.2
https://www.nuget.org/packages/iTextSharp/

BouncyCastle 1.8.6.1
https://www.nuget.org/packages/BouncyCastle/1.8.6.1

Rename the .nupkg extension to .zip, extract them to a folder and then copy the itextsharp.dll and BouncyCastle.Crypto.dll files

5. Create the directory where the password protected PDF files will be stored.

6. Proceed to execute the PowerShell script to password protect PDFs.

image

7. New PDFs should be created in the destination directory upon successfully executing the PowerShell script.

image

8. The spreadsheet referenced for configuring the passwords will have the Source Name column filled in with the file names of the password protected PDFs:

image

Using PowerShell to Password Protect Adobe PDF Files (auto generate passwords)

The following describes how to use PowerShell to password protect Adobe PDF files with a reference spreadsheet with only the passwords defined. The PowerShell script’s logic is as follows:

  1. Opens up a spreadsheet with two columns:
    1. Source Name < blank
    2. Password < password specified
  2. Looks into a directory and begins password protecting the documents with the passwords in the spreadsheet AND fills in the source name column with the file name
  3. Saves the PDF into another directory

1. Begin by creating a spreadsheet with two columns leaving the Source Name and Password columns blank:

    a) Source Name

    b) Password

image

2. Proceed by creating a .ps1 file from the following code (also attached as PasswordProtectPDF.ps1):

Add-Type -Path "C:\itextsharp.5.5.13.2\lib\BouncyCastle.Crypto.dll"

Add-Type -AssemblyName System.Web

[System.Reflection.Assembly]::LoadFrom("itextsharp.dll")

function PSUsing {

param (

[System.IDisposable] $excelSheetNumbernputObject = $(throw "The parameter -inputObject is required."),

[ScriptBlock] $scriptBlock = $(throw "The parameter -scriptBlock is required.")

)

Try {

&$scriptBlock

}

Finally {

if ($excelSheetNumbernputObject.psbase -eq $null) {

$excelSheetNumbernputObject.Dispose()

} else {

$excelSheetNumbernputObject.psbase.Dispose()

}

}

}

$sourcePath = "C:\PDF\"

$destinationPath = "C:\PDF\WithPassword\"

$excelReferenceSheet = "C:\Scripts-GeneratePassword\PDFList.xlsx"

$xlCellTypeLastCell = 11

$startRow,$col=2,1

$excelSheetNumber=1

$passwordLength = 15

$numberOfSpecialCharacters = 4

# OPEN EXCEL FILE TO FILL OUT PDF FILENAME AND PASSWORDS

$excel=new-object -com excel.application

$excel.DisplayAlerts = $false

$excel.Visible = $false

$workbook=$excel.workbooks.open($excelReferenceSheet)

$worksheet=$workbook.Sheets.Item($excelSheetNumber)

$rowIncrement=0;

# BEGIN TRAVERSING THROUGH SOURCE FOLDER

$files = Get-ChildItem "C:\PDF\\*" -file

foreach ($f in $files){

# WRITE SOURCE FILE NAME INTO SPREADSHEET

#Write-Output $f.name

$worksheet.Cells.Item($startRow + $rowIncrement,$col) = $f.name

#GENERATE RANDOM PASSWORD AND FILL OUT SPREADSHEET

$password = [System.Web.Security.Membership]::GeneratePassword($passwordLength,$numberOfSpecialCharacters)

$worksheet.Cells.Item($startRow + $rowIncrement,$col+1).Value2 = $password

#Write-Output $password

$rowIncrement++

$fullSourcePathAndFileName = $sourcePath + $f.name

$destinationPathAndFileName = $destinationPath + $f.name

# PASSWORD PROTECT PDF

New-Object PSObject -Property @{Source=$sourcePath + $sourceFileName;Destination=$destinationFileName;Password=$password}

$file = New-Object System.IO.FileInfo $fullSourcePathAndFileName

$fileWithPassword = New-Object System.IO.FileInfo $destinationPathAndFileName

PSUsing ( $fileStreamIn = $file.OpenRead() ) {

PSUsing ( $fileStreamOut = New-Object System.IO.FileStream($fileWithPassword.FullName,[System.IO.FileMode]::Create,[System.IO.FileAccess]::Write,[System.IO.FileShare]::None) ) {

PSUsing ( $reader = New-Object iTextSharp.text.pdf.PdfReader $fileStreamIn ) {

[iTextSharp.text.pdf.PdfEncryptor]::Encrypt($reader, $fileStreamOut, $true, $password, $password, [iTextSharp.text.pdf.PdfWriter]::ALLOW_PRINTING)

}

}

}

}

$workbook.SaveAs($excelReferenceSheet)

$excel.Close

$excel.Quit()

[System.GC]::Collect()

[System.GC]::WaitForPendingFinalizers()

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet)

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

Remove-Variable -Name excel

3. Open the ps1 script and edit the 3 paths as highlighted in red above:

$sourcePath = "C:\PDF\" <-- Directory containing the source PDFs

$destinationPath = "C:\PDF\WithPassword\" <-- Directory containing the source PDFs

$excelReferenceSheet = "c:\ScriptsNew\PDFList.xlsx" <-- Directory where the spreadsheet that the script will reference for the PDF file name and password

$passwordLength = 15 <-- The length of the randomly generated password

$numberOfSpecialCharacters = 4 <-- The amount of non-numerical special characters in the password (e.g. !, -, $, &, @, #, %, etc)

$files = Get-ChildItem "C:\PDF\\*" -file <-- Update the C:\PDF to the directory containing the source PDFs

4. Download the following .nupkg packages:

iTextSharp 5.5.13.2

https://www.nuget.org/packages/iTextSharp/

BouncyCastle 1.8.6.1

https://www.nuget.org/packages/BouncyCastle/1.8.6.1

Rename the .nupkg extension to .zip, extract them to a folder and then copy the itextsharp.dll and BouncyCastle.Crypto.dll files

5. Create the directory where the password protected PDF files will be stored.

6. Proceed to execute the PowerShell script to password protect PDFs.

image

7. New PDFs should be created in the destination directory upon successfully executing the PowerShell script.

image

8. The spreadsheet referenced for configuring the passwords will have the Source Name column filled in with the file names and corresponding passwords of the password protected PDFs:

image

No comments: