kreuzberger
Goto Top

PDF Eigenschaften mit PowerShell bearbeiten

Moin ihr Digitalfreunde,

kennt jemand zufällig eine Lösung, ob bzw. wie man per Powershell (Nachladbares Modul?) die Tags einer PDF auslesen und bearbeiten könnte?

In einer PDF stehen ja „Tags“ wie zb. >Titel<, >Verfasser<, >Thema< und >Stichworte<.

Ich würde gerne nach diesen Tags suchen können per PowerShell und ggf. Änderungen vornehmen wollen.

Hat da jemand eine Idee?


Danke im Voraus


Kreuzberger

Content-ID: 4081194118

Url: https://administrator.de/contentid/4081194118

Ausgedruckt am: 21.11.2024 um 17:11 Uhr

StefanKittel
StefanKittel 27.09.2022 um 22:13:12 Uhr
Goto Top
Hallo,
schau mal nach dem PDF Toolkit
https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/
Stefan
colinardo
Lösung colinardo 28.09.2022, aktualisiert am 17.09.2024 um 23:09:33 Uhr
Goto Top
Servus.
Ich mache das immer mit der .NET Bibliothek iTextSharp die sich nativ via Add-Type in die Powershell einbinden lässt. Findest du in meinen Beiträgen/Kommentaren übrigens diverse Beispiele dazu.

#edit# hier mal zwei Funktionen mit Beispielen am Ende die ich dafür nutze:

back-to-topGet-PDFMetaData / Set-PDFMetaData

<#
.Synopsis
    Get PDF Metadata
.DESCRIPTION
    Get PDF Metadata Properties
.EXAMPLE
    Get-PDFMetaData -FilePath "D:\test.pdf"  
.EXAMPLE
    Get-ChildItem -Path "D:\FolderA" -File -Filter *.pdf | Get-PDFMetaData  

    You can use the pipeline to get the metadata from your pdf files
.OUTPUTS
   [System.Collections.Generic.Dictionary[string,string]]
#>
function Get-PDFMetaData {
    [cmdletbinding(SupportsShouldProcess=$true)]
    param(
        # FilePath of PDF
        [Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][Alias('Fullname')][string[]]$FilePath  
    )
    begin{
        # Funktion zum Laden des iTextSharp Assemblies
        function Load-iTextLibrary {
            if($psscriptroot -ne ''){  
                $localpath = join-path $psscriptroot 'itextsharp.dll'  
            }else{
                $localpath = join-path $env:TEMP 'itextsharp.dll'  
            }
            $zip = $null;$tmp = ''  
            try{
                if(!(Test-Path $localpath)){
                    Add-Type -A System.IO.Compression.FileSystem
                    $tmp = "$env:TEMP\$([IO.Path]::GetRandomFileName())"  
                    write-host "Downloading and extracting required 'iTextSharp.dll' ... " -F Green -NoNewline  

                    (New-Object System.Net.WebClient).DownloadFile('https://www.nuget.org/api/v2/package/iTextSharp/5.5.13.1', $tmp)  
                    $zip = [System.IO.Compression.ZipFile]::OpenRead($tmp)
                    $zip.Entries | ?{$_.Fullname -eq 'lib/itextsharp.dll'} | %{  
                        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_,$localpath)
                    }
                    write-host "OK" -F Green   
                }
                if (Get-Item $localpath -Stream zone.identifier -ea SilentlyContinue){
                    Unblock-File -Path $localpath
                }
                Add-Type -Path $localpath
            }catch{
                throw "Error: $($_.Exception.Message)"  
            }finally{
                if ($zip){$zip.Dispose()}
                if ($tmp -ne ''){del $tmp -Force -EA SilentlyContinue}  
            }
        }
        # iText Library laden
        Load-iTextLibrary
    }
    process{
        foreach($file in $filepath){
            if ($PSCmdlet.ShouldProcess($file,"GetMetadata")){  
                # create reader object
                $reader = New-Object iTextSharp.text.pdf.PdfReader $file
                # output metadata
                $reader.Info
                # cleanup
                $reader.Dispose()
            }
        }
    }
}

<#
.Synopsis
    Set PDF Metadata
.DESCRIPTION
    Write Metadata of PDF files
.EXAMPLE
    Set-PDFMetaData -FilePath "D:\test.pdf" -metadata @{'Author'='Mickey Mouse'}  

    Set the Author-Field from the pdf to a new value
.EXAMPLE
    Get-ChildItem -Path "D:\FolderA" -File -Filter *.pdf | Set-PDFMetaData -metadata @{'Author'='Mickey Mouse'}  

    You can use the pipeline to set the metadata of your pdf files
.OUTPUTS
   [System.Collections.Generic.Dictionary[string,string]]
#>
function Set-PDFMetaData {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        [Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][ValidateNotNullOrEmpty()][Alias('Fullname')][string[]]$FilePath,  
        [Parameter(mandatory=$true)][ValidateNotNullOrEmpty()][hashtable]$metadata
    )
    begin{
        # Funktion zum Laden des iTextSharp Assemblies
        function Load-iTextLibrary {
            if($psscriptroot -ne ''){  
                $localpath = join-path $psscriptroot 'itextsharp.dll'  
            }else{
                $localpath = join-path $env:TEMP 'itextsharp.dll'  
            }
            $zip = $null;$tmp = ''  
            try{
                if(!(Test-Path $localpath)){
                    Add-Type -A System.IO.Compression.FileSystem
                    $tmp = "$env:TEMP\$([IO.Path]::GetRandomFileName())"  
                    write-host "Downloading and extracting required 'iTextSharp.dll' ... " -F Green -NoNewline  

                    (New-Object System.Net.WebClient).DownloadFile('https://www.nuget.org/api/v2/package/iTextSharp/5.5.13.1', $tmp)  
                    $zip = [System.IO.Compression.ZipFile]::OpenRead($tmp)
                    $zip.Entries | ?{$_.Fullname -eq 'lib/itextsharp.dll'} | %{  
                        [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_,$localpath)
                    }
                    write-host "OK" -F Green   
                }
                if (Get-Item $localpath -Stream zone.identifier -ea SilentlyContinue){
                    Unblock-File -Path $localpath
                }
                Add-Type -Path $localpath
            }catch{
                throw "Error: $($_.Exception.Message)"  
            }finally{
                if ($zip){$zip.Dispose()}
                if ($tmp -ne ''){del $tmp -Force -EA SilentlyContinue}  
            }
        }
        # iText Library laden
        Load-iTextLibrary
    }
    process{
        foreach($file in $filepath){
            if ($PSCmdlet.ShouldProcess($file,"SetMetadata")){  
                $reader = $null; $fs = $null;$stamper = $null
                try{
                    $finfo = Get-Item -LiteralPath $file
                    # get pdf reader
                    $reader = New-Object iTextSharp.text.pdf.PdfReader $file
                    # create temporary file to store changes into
                    $tmp = join-path $finfo.DirectoryName ([IO.Path]::GetRandomFileName())
                    # handle case where file with random file already esists, and generate new name until free
                    while(Test-Path -LiteralPath $tmp -PathType Leaf){
                        $tmp = join-path $finfo.DirectoryName ([IO.Path]::GetRandomFileName())
                    }
                    # create filestream to temp file
                    $fs = [System.IO.FileStream]::new($tmp,[System.IO.FileMode]::Create,[System.IO.FileAccess]::ReadWrite)
                    # create pdf stamper object with file stream as output
                    $stamper = New-Object iTextSharp.text.pdf.PdfStamper $reader,$fs
                    # get metadata
                    $meta = $reader.Info
                    # set metadata from users hashtable
                    $metadata.GetEnumerator() | %{
                        write-verbose "Key '$($_.Key)' set to value '$($_.Value)'."  
                        if ($meta.ContainsKey($_.Key)){
                            $meta[$_.Key] = $_.Value
                        }else{
                            $meta.Add($_.Key,$_.Value)
                        }    
                    }
            
                    # set metadata into stamper
                    $stamper.MoreInfo = $meta
                    # close stamper/reader
                    $stamper.Close()
                    $stamper.Dispose()
                    $reader.Close()
                    $reader.Dispose()
                    # set original time stamps to file
                    Get-Item -LiteralPath $tmp | %{
                        $_.LastWriteTime = $finfo.LastWriteTime
                        $_.CreationTime = $finfo.CreationTime
                    }
                    # remove original file
                    remove-item $file -Force
                    # rename temp file back to original name
                    Rename-Item -LiteralPath $tmp -NewName $finfo.Name -Force
                }catch{
                    write-host $_.Exception.Message -F Red
                }finally{
                    if($reader){$reader.Dispose()}
                    if($fs){$fs.Dispose()}
                    if($stamper){$stamper.Dispose()}
                }
            }
        }
    }
}

back-to-topNutzungsbeispiele der beiden Funktionen

# PDF Metadaten auslesen
Get-ChildItem -LiteralPath 'D:\quelle' -File -Filter *.pdf | Get-PDFMetaData  
# PDF Metadaten beschreiben
Get-ChildItem -LiteralPath 'D:\quelle' -File -Filter *.pdf | Set-PDFMetaData -metadata @{Author="Max Muster";Title="Another Title"}  
# Nur PDFs mit bestimmten Metadata-Werten verändern
Get-ChildItem -LiteralPath 'D:\quelle' -File -Filter *.pdf | ?{(Get-PDFMetadata -FilePath $_.Fullname)['Author'] -eq 'Max Muster'} | Set-PDFMetaData -metadata @{Author="Mickey Mouse";Title="Another Title";Subject="Another Subject";Keywords="Tag1,Tag2"} -Verbose  


Grüße Uwe
rddomain-1
rddomain-1 17.09.2024 um 19:27:07 Uhr
Goto Top
Hallo colinardo ,

ich habe dein Script hier verwendet und es arbeitet wunderbar

#edit# hier mal zwei Funktionen mit Beispielen am Ende die ich dafür nutze:
Get-PDFMetaData / Set-PDFMetaData

ich habe nur eine Frage an Dich, da ich in Powershell nicht so bewandert bin.
Wenn ich mit

Get-ChildItem -LiteralPath 'D:\quelle' -File -Filter *.pdf | Set-PDFMetaData -metadata @{Author="Max Muster";Title="Another Title"}    

die Metadaten einer Datei verändere (z.B. Author/Titel) dann klappt das super.
Jedoch werden aber auch das Erstelldatum und das Änderungsdatum auf das aktuelle Datum gesetzt.
Dieses würde ich aber gerne unverändert lassen, so das wirklich nur die genannten Metadaten geändert werden - Das Erstell- und Änderungsdatum soll aber nicht geändert werden.
Kannst Du mir sagen bzw. helfen wie ich das im oben genannten Powershell ändern muss.

Danke schon mal für Deine Antwort und Hilfe.

Viele Grüße

Andreas
colinardo
colinardo 17.09.2024 aktualisiert um 23:12:15 Uhr
Goto Top
Servus Andreas,
habe das gerade noch in die Funktion integriert, aktualisiere sie, dann werden die Zeitstempel nicht mehr verändert.

Grüße Uwe
rddomain-1
rddomain-1 18.09.2024 um 16:47:48 Uhr
Goto Top
Hallo Uwe,
vielen lieben Dank für die schnelle Hilfe. Ich ziehe wirklich meinen Hut vor Deinem Können. Wirklich ein PowerShell-Profi. Dein Wissen in PS würde ich auch gerne haben face-smile
Habe es gleich ausprobiert und es funktioniert einwandfrei. TipTop
Nochmals tausend Dank.

viele Grüße

Andreas