Created
June 25, 2023 06:09
-
-
Save nidrissi/256dfa1d1afe980f80825d1a9d2fa10d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Splits a PDF file containing multiple exams along ranges specified in a CSV file, to be used with Moodle. | |
.DESCRIPTION | |
Given a CSV file named "exams.csv" with the following content: | |
Name;ID;Start;End | |
John Doe;1234;1;2 | |
Jane Doe;5678;3;4 | |
And a PDF file named "exams.pdf" with 4 pages, the following command: | |
Select-Exams -InputCSV exams.csv -InputPDF exams.pdf -OutputZip exams.zip | |
Will produce a zip file named "exams.zip" containing two PDF files: | |
- John Doe_1234_assignsubmission_file_Copie John Doe.pdf, containing pages 1 and 2 of the original PDF. | |
- Jane Doe_5678_assignsubmission_file_Copie Jane Doe.pdf, containing pages 3 and 4 of the original PDF. | |
.OUTPUTS | |
None | |
By default, the function will output nothing. | |
System.IO.FileInfo | |
The zip file created, if -PassThru is specified. | |
.NOTES | |
Requires PDFtk to be installed. See https://www.pdflabs.com/tools/pdftk-server/. | |
.LINK | |
https://idrissi.eu/post/select-exams | |
#> | |
function Select-Exams { | |
[CmdletBinding(SupportsShouldProcess)] | |
param ( | |
# The path of the CSV file that explains how to split the PDF file. The headers of that CSV file should be: | |
# - Name: The name of the student. | |
# - ID: The Moodle participant for the student in that specific course (distinct from the global Moodle ID). | |
# - Start: The first page of that student's exam. | |
# - End: The last page of that student's exam. | |
[Parameter(Mandatory)] | |
[ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = "File not found.")] | |
[String] $InputCSV, | |
# The path of the PDF containing all the pages of the students' exams. | |
[Parameter(Mandatory)] | |
[ValidateScript({ Test-Path $_ -PathType Leaf }, ErrorMessage = "File not found")] | |
[String] $InputPDF, | |
# The path of the zip file to be created. | |
[Parameter(Mandatory)] | |
[String] $OutputZip, | |
# The delimiter used in the CSV file. | |
[Parameter()] | |
[String] $Delimiter = ";", | |
# If specified, the function will return the zip file created. | |
[Parameter()] | |
[Switch] $PassThru | |
) | |
begin { | |
if (-not (Get-Command "pdftk.exe" -ErrorAction SilentlyContinue)) { | |
throw "PDFtk must be installed for this script to work." | |
} | |
} | |
process { | |
$ImportedCSV = Import-Csv -Path $InputCSV -Delimiter $Delimiter | |
$TempFolder = New-Item -Type Directory -Path (Join-Path Temp: (New-Guid)) | |
Write-Verbose "Created temporary folder $TempFolder." | |
Push-Location $TempFolder | |
Write-Verbose "Bursting the PDF..." | |
# this produces files named pg_0001.pdf, pg_0002.pdf etc | |
pdftk.exe $InputPDF burst output (Join-Path $TempFolder "pg_%04d.pdf") | |
$FinalFolder = New-Item -Path $TempFolder -Name "final" -Type Directory | |
$Index = 0 | |
foreach ($entry in $ImportedCSV) { | |
Write-Progress -Activity "PDFtk" -Status ($entry | ConvertTo-Json -Compress) -PercentComplete ($Index / $ImportedCSV.Count * 100) | |
if ((!$entry.Start) -or (!$entry.End) -or (!$entry.Name) -or (!$entry.ID)) { | |
Write-Warning ("Skipping $($entry | ConvertTo-Json -Compress)") | |
continue | |
} | |
$OutputPDFName = "{0}_{1}_assignsubmission_file_Copie {0}.pdf" -f $entry.Name, $entry.ID | |
$OutputPDF = Join-Path $FinalFolder $OutputPDFName | |
$Range = ($entry.Start)..($entry.End) | ForEach-Object { | |
Join-Path $TempFolder ("pg_{0:d4}.pdf" -f $_) | |
} | |
pdftk.exe @Range output $OutputPDF | |
$Index++ | |
} | |
Write-Verbose "Compressing to $OutputZip." | |
Compress-Archive -Path @(Get-ChildItem $FinalFolder) -DestinationPath $OutputZip -PassThru:$PassThru | |
} | |
clean { | |
if ($null -ne $TempFolder) { | |
Remove-Item -Recurse $TempFolder | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment