Ading Exif processing

pull/1/head
Tom Peltonen 2021-08-08 09:30:15 +10:00
parent ebcce55e47
commit a2c5f23852
14 changed files with 472 additions and 153 deletions

64
Docs/Advanced.md 100644
View File

@ -0,0 +1,64 @@
# Advanced Usage
There are various options for using PeterDocs. The following sections will cover some of these.
## File Filter
The ``-FileFilter`` parameter allows selection of files tha are to be included into the archive file.
The parameter only applies to the compress function or buidling the reconciliation file.
For example:
```powershell
Compress-Peter -SourceFolder "~/Pictures/" -Secret "c0mpleX%S3cret" -FileFiletr "*.jpg"
```
will only include files with the extension ".jpg"
```powershell
Compress-Peter -SourceFolder "~/Pictures/" -Secret "c0mpleX%S3cret" -FileFiletr "IMG9*.jpg"
```
will only include files with the extension ".jpg" and starting with the characters "IMG90"
## ReconcileFile
The ``-ReconcileFile`` parameter allows specification of the reocnciliation file if you
wish to select your own name.
For example:
```powershell
Compress-Peter -SourceFolder "~/Pictures/" -Secret "c0mpleX%S3cret" -ReconcileFile "reconcile_batch2.csv"
```
will generate a reconcile file named "reconcile_batch2.csv" and place it into the 7Zip archive. Remember
to specify the reconcile file on the compare, something like this:
```powershell
Compare-Peter -RestoreFolder "c:\backup\pictures" -ReconcileFile "reconcile_batch2.csv"
```
## SecretFile
The ``-SecretFile`` parameter allows specification of the secret file if you
wish to select your own name. This parameter is only applicable with the
``-RecipientKey`` parameter
For example:
```powershell
Compress-Peter -SourceFolder "~/Pictures/" -RecipientKey "meerkat@merebox.com" -SecretFile "mypictures.key"
```
will generate a secret file named "mypictures.key". Remember to send this file to your recipient
and to specify the secret file on the expand, something like this:
```powershell
Expand-Peter -RestoreFolder "c:\backup\pictures" -RecipientKey "meerkat@merebox.com" -SecretFile "mypictures.key" -ArchiveFile "myarchive.7z"
```
## LogPath
The ``-LogPath`` parameter allows definition of the folder that will contain the
execution log.

Binary file not shown.

View File

@ -31,8 +31,9 @@
$global:default_reconcileFile = "##protect_transfer_reconcile_files##.csv"
$global:default_exifFile = "##peter_exif##.csv"
$global:LogPathName = ""
$global:MetadataPathName = Join-Path -Path ".\" -ChildPath ".peter-metadata"
function Open-Log {
@ -100,7 +101,8 @@ param(
function Test-PasswordQuality
{
Param(
[Parameter(Mandatory)][String] $TestPassword
[Parameter(Mandatory)]
[String] $TestPassword
)
$qualityMatch = $true
@ -142,20 +144,20 @@ function Get-ConvenientFileSize
)
if ($totalFileSize -ge 1000000000000) {
if ($totalFileSize -ge 1TB) {
$totalRightLabel = "TB"
$totalFileXbytes = [math]::Round(($size / 1000000000000), 2)
$totalFileXbytes = [math]::Round(($size / 1TB), 2)
} else {
if ($totalFileSize -ge 1000000000) {
if ($totalFileSize -ge 1GB) {
$totalRightLabel = "GB"
$totalFileXbytes = [math]::Round(($size / 1000000000), 2)
$totalFileXbytes = [math]::Round(($size / 1GB), 2)
} else {
if ($totalFileSize -ge 1000000) {
if ($totalFileSize -ge 1MB) {
$totalRightLabel = "MB"
$totalFileXbytes = [math]::Round(($size / 1000000), 2)
$totalFileXbytes = [math]::Round(($size / 1MB), 2)
} else {
$totalRightLabel = "KB"
$totalFileXbytes = [math]::Round(($size / 1000), 2)
$totalFileXbytes = [math]::Round(($size / 1KB), 2)
}
}
}
@ -230,11 +232,11 @@ function Get-ConvenientFileSize
.Example
# Create a reconcile file for folder "C:\sourcefiles\"
Build-PeterReconcile -SourceFolder "C:\sourcefiles\" -ReconcileFile ".\myreconcile.csv"
New-PeterReconcile -SourceFolder "C:\sourcefiles\" -ReconcileFile ".\myreconcile.csv"
#>
function Build-PeterReconcile
function New-PeterReconcile
{
Param(
[Parameter(Mandatory)][String] $SourceFolder,
@ -256,7 +258,7 @@ Param(
if ($Feedback) {
Open-Log
Write-Log "Function 'Build-PeterReconcile' parameters follow"
Write-Log "Function 'New-PeterReconcile' parameters follow"
Write-Log "Parameter: SourceFolder Value: $SourceFolder "
Write-Log "Parameter: ReconcileFile Value: $ReconcileFile "
Write-Log "Parameter: RootFolder Value: $RootFolder "
@ -293,6 +295,15 @@ Param(
Write-Log "Generating reconciliation file '$ReconcileFile'"
Write-Host "Generating reconciliation file '$ReconcileFile'"
if ($IncludeExif) {
if (!(Test-Path -Path $global:MetadataPathName )) {
$null = New-Item -Path $global:MetadataPathName -ItemType Directory
}
$ExifFile = Join-Path -Path $global:MetadataPathName -ChildPath $global:default_exifFile
Write-Log "Generating Exif file '$ExifFile'"
Set-Content -Path $ExifFile -Value '"FullName","Author","Title","Subject","Comments","DateTaken","ISO","FNumber"'
}
$totalFileCount = 0
$totalFileSize = 0
@ -307,7 +318,7 @@ Param(
Write-Progress -Activity "Creating reconciliation entries in file $ReconcileFile" -Status "Start"
Set-Content -Path $ReconcileFile -Value '"FullName","LastWriteTime","CreationTime","LastAccessTime","Length","Hash","ParentFolder","Object","Attributes","Extension"'
Set-Content -Encoding utf8 -Path $ReconcileFile -Value '"FullName","LastWriteTime","CreationTime","LastAccessTime","Length","Hash","ParentFolder","Object","Attributes","Extension"'
if ($SourceFolder.StartsWith("@")) {
Write-Log "Using @ file '$($SourceFolder.Substring(1))'"
@ -341,14 +352,19 @@ Param(
}
$record = '"'+$_.FullName.Replace($RootFolder, "")+'","'+$_.LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss")+'"'
$record = $record + ',"'+$_.CreationTime.ToString("yyyy-MM-ddTHH:mm:ss")+'","'+$_.LastAccessTime.ToString("yyyy-MM-ddTHH:mm:ss")+'"'
$record = $record + ','+$_.Length+',"'+$sourceHash+'","'+ $_.Directory + '","' + $_.Name + '","' + $_.Attributes+'","'+$_.Extension+'"'
if ($IncludeExif) {
$null = Get-ImageFileContents -ImageFile $($_.FullName)
}
$record = $record + ','+$_.Length+',"'+$sourceHash+'"'
$record = $record + ',"'+ $_.Directory + '","' + $_.Name + '","' + $_.Attributes+'","'+$_.Extension+'"'
Add-Content -Path $ReconcileFile -Value $record
if ($IncludeExif) {
$exifData = Get-ImageFileContents -ImageFile $($_.FullName)
$exifRecord = '"' + $_.FullName + '","' + $exifData.Author + '","' + $exifData.Title + '","' + $exifData.Subject + '","' + $exifData.Comments + '"'
$exifRecord = $exifRecord + ',"' + $exifData.DateTaken + '","' + $exifData.Iso + '","' + $exifData.FNumber + '"'
Add-Content -Path $ExifFile -Value $exifRecord
}
}
}
}
@ -378,12 +394,16 @@ Param(
$record = $record + ',"'+$_.CreationTime.ToString("yyyy-MM-ddTHH:mm:ss")+'","'+$_.LastAccessTime.ToString("yyyy-MM-ddTHH:mm:ss")+'"'
$record = $record + ','+$_.Length+',"'+$sourceHash+'","'+ $_.Directory + '","' + $_.Name + '","' + $_.Attributes+'","'+$_.Extension+'"'
if ($IncludeExif) {
$null = Get-ImageFileContents -ImageFile $($_.FullName)
}
Add-Content -Path $ReconcileFile -Value $record
if ($IncludeExif) {
$exifData = Get-ImageFileContents -ImageFile $($_.FullName)
$exifRecord = '"' + $_.FullName + '","' + $exifData.Author + '","' + $exifData.Title + '","' + $exifData.Subject + '","' + $exifData.Comments + '"'
$exifRecord = $exifRecord + ',"' + $exifData.DateTaken + '","' + $exifData.Iso + '","' + $exifData.FNumber + '"'
Add-Content -Path $ExifFile -Value $exifRecord
}
}
}
@ -571,6 +591,7 @@ Param(
[String] $FileFilter ="*",
[String] $SecretFile,
[switch] $ExcludeHash,
[switch] $IncludeExif,
[String] $RootFolder,
[String] $LogPath
@ -596,6 +617,7 @@ Param(
Write-Log "Parameter: FileFilter Value: $FileFilter "
Write-Log "Parameter: SecretFile Value: $SecretFile "
Write-Log "Parameter: ExcludeHash Value: $ExcludeHash "
Write-Log "Parameter: IncludeExif Value: $IncludeExif "
Write-Log "Parameter: LogPath Value: $LogPath "
Write-Log ""
@ -668,7 +690,10 @@ Param(
if ($ReconcileFile -eq "")
{
$ReconcileFile = $default_reconcileFile
if (!(Test-Path -Path $global:MetadataPathName)) {
$null = New-Item -Path $global:MetadataPathName -ItemType Directory
}
$ReconcileFile = Join-Path -Path $global:MetadataPathName -ChildPath $default_reconcileFile
}
if ($FileFilter -eq "")
@ -727,9 +752,9 @@ Param(
[int] $archiveFileCount = $archiveInfo.FilesCount
if ($ExcludeHash) {
Build-PeterReconcile -ReconcileFile $ReconcileFile -SourceFolder $SourceFolder -FileFilter $FileFilter -RootFolder $rootFolder -ExcludeHash -ProcessFileCount $archiveFileCount
New-PeterReconcile -ReconcileFile $ReconcileFile -SourceFolder $SourceFolder -FileFilter $FileFilter -RootFolder $rootFolder -ExcludeHash -ProcessFileCount $archiveFileCount -IncludeExif
} else {
Build-PeterReconcile -ReconcileFile $ReconcileFile -SourceFolder $SourceFolder -FileFilter $FileFilter -RootFolder $rootFolder -ProcessFileCount $archiveFileCount
New-PeterReconcile -ReconcileFile $ReconcileFile -SourceFolder $SourceFolder -FileFilter $FileFilter -RootFolder $rootFolder -ProcessFileCount $archiveFileCount -IncludeExif
}
If (!(Test-Path -Path $ReconcileFile )) {
Write-Log "Reconcile file '$ReconcileFile' was not created. See any previous errors"
@ -738,11 +763,11 @@ Param(
return
}
Write-Log "Add reconcile file '$ReconcileFile' to file '$ArchiveFile'"
$fullReconcileName = (Get-Item $ReconcileFile).FullName
Write-Log "Add folder '$global:MetadataPathName' to file '$ArchiveFile'"
$fullMetadatName = (Get-Item $global:MetadataPathName).FullName
$fullZipName = (Get-Item $ArchiveFile).FullName
Compress-7Zip -Path $fullReconcileName -ArchiveFileName $fullZipName -Format SevenZip -Append -Password $secret -EncryptFilenames
Remove-Item $fullReconcileName
Compress-7Zip -Path $fullMetadatName -ArchiveFileName $fullZipName -PreserveDirectoryRoot -Format SevenZip -Append -Password $secret -EncryptFilenames
#Remove-Item $fullMetadatName -Recurse
Write-Log "Archive file '$ArchiveFile' created from folder '$SourceFolder'"
Write-Host "Archive file '$ArchiveFile' created from folder '$SourceFolder'" -ForegroundColor Green
@ -1506,6 +1531,7 @@ Param(
[Parameter(Mandatory)][String] $RestoreFolder,
[String] $ReconcileFile,
[String] $RootFolder,
[Switch] $ExcludeHash,
[Switch] $ExtendedCheck,
[String] $LogPath
)
@ -1534,7 +1560,7 @@ Param(
if ($ReconcileFile -eq "")
{
$ReconcileFile = Join-Path -Path $RestoreFolder -ChildPath $default_reconcileFile
$ReconcileFile = Join-Path -Path (Join-Path -Path $RestoreFolder -ChildPath $global:MetadataPathName) -ChildPath $default_reconcileFile
Write-Log "Using default reconciliation file '$ReconcileFile'"
Write-Host "Using default reconciliation file '$ReconcileFile'"
If (!(Test-Path -Path $ReconcileFile )) {
@ -1572,21 +1598,24 @@ Param(
$restoreFileName = $(Join-Path -Path $RestoreFolder -ChildPath $_.FullName)
}
If (Test-Path -Path $restoreFileName ) {
if ($_.Hash -ne "") {
$targetHash= (Get-FileHash -Path $restoreFileName).Hash
if ($_.Hash -ne $targetHash) {
$errorCount = $errorCount + 1
Write-Log "Hash mismatch for file '$restoreFileName' with target value $targetHash"
if (!($ExcludeHash)) {
if ($_.Hash -ne "") {
$targetHash= (Get-FileHash -Path $restoreFileName).Hash
if ($_.Hash -ne $targetHash) {
$errorCount = $errorCount + 1
Write-Log "Hash mismatch for file '$restoreFileName' with target value $targetHash"
}
} else {
$missingHash = $true
}
} else {
$missingHash = $true
}
if ((Get-Item -Path $restoreFileName).CreationTime.ToString("yyyy-MM-ddTHH:mm:ss") -ne $_.CreationTime) {
Write-Log "Creation mismatch for file '$restoreFileName' with target value $((Get-Item -Path $restoreFileName).CreationTime.ToString("yyyy-MM-ddTHH:mm:ss"))"
if ((Get-Item -Path $restoreFileName).LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss") -ne $_.LastWriteTime) {
Write-Log "LastWrite mismatch for file '$restoreFileName' with target value $((Get-Item -Path $restoreFileName).LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss")) expected $($_.LastWriteTime)"
$errorCreateCount = $errorCreateCount + 1
$dateTimeValue = [Datetime]::ParseExact($_.CreationTime, 'yyyy-MM-ddTHH:mm:ss', $null)
$fileValue = (Get-Item -Path $restoreFileName).CreationTime
$dateTimeValue = [Datetime]::ParseExact($_.LastWriteTime, 'yyyy-MM-ddTHH:mm:ss', $null)
$fileValue = (Get-Item -Path $restoreFileName).LastWriteTime
$diff = ($dateTimeValue - $fileValue).Seconds
# Allow +/- 2 second discrepancy
if (($diff.Seconds -lt -2) -or ($diff.Seconds -gt 2)) {
@ -1595,11 +1624,25 @@ Param(
}
if ((Get-Item -Path $restoreFileName).Length -ne $_.Length) {
$errorCount = $errorCount + 1
Write-Log "Length mismatch for file '$restoreFileName' with target value $(Get-Item -Path $restoreFileName).Length)"
Write-Log "Length mismatch for file '$restoreFileName' with target value $(Get-Item -Path $restoreFileName).Length) expected $($_.Length)"
}
# Note that last / write access time is not checked by default as it will commonly be changed after restore
if ($extendedCheck) {
if ((Get-Item -Path $restoreFileName).CreationTime.ToString("yyyy-MM-ddTHH:mm:ss") -ne $_.CreationTime) {
Write-Log "Creation mismatch for file '$restoreFileName' with target value $((Get-Item -Path $restoreFileName).CreationTime.ToString("yyyy-MM-ddTHH:mm:ss")) expected $($_.CreationTime)"
$errorCreateCount = $errorCreateCount + 1
$dateTimeValue = [Datetime]::ParseExact($_.CreationTime, 'yyyy-MM-ddTHH:mm:ss', $null)
$fileValue = (Get-Item -Path $restoreFileName).CreationTime
$diff = ($dateTimeValue - $fileValue).Seconds
# Allow +/- 2 second discrepancy
if (($diff.Seconds -lt -2) -or ($diff.Seconds -gt 2)) {
$errorCount = $errorCount + 1
}
}
if ((Get-Item -Path $restoreFileName).LastAccessTime.ToString("yyyy-MM-ddTHH:mm:ss") -ne $_.LastAccessTime) {
$errorCount = $errorCount + 1
Write-Log "Last access mismatch for file '$restoreFileName' with target value $((Get-Item -Path $restoreFileName).LastAccessTime.ToString("yyyy-MM-ddTHH:mm:ss"))"

View File

@ -1,62 +1,282 @@
Function Get-ExifContents {
param(
$ImageStream,
[int] $ExifCode
)
Add-Type -AssemblyName System.Drawing
function Get-ExifContents {
param(
[Parameter(Mandatory)]
$ImageStream,
[Parameter(Mandatory)]
[int] $ExifCode,
[Switch] $Numeric,
[int] $Size = 0,
[int] $Parts = 1
)
Try {
if (-not $ImageStream.PropertyIdList.Contains($ExifTagCode))
{
$Value = "<empty>"
$list_id = $ImageStream.PropertyIdList
if ($list_id.IndexOf($ExifCode) -eq -1) {
if ($Numeric) {
$Value = 0
} else {
$Value = ""
}
} else {
if ($Numeric -and $Size -eq 0) {
$Size = 8
}
$PropertyItem = $ImageStream.GetPropertyItem($ExifCode)
$valueBytes = $PropertyItem.Value
$Value = [System.Text.Encoding]::ASCII.GetString($valueBytes)
if ($null -eq $PropertyItem) {
if ($Numeric) {
$Value = 0
} else {
$Value = ""
}
} else {
$valueBytes = $PropertyItem.Value
if ($null -eq $valueBytes) {
if ($Numeric) {
$Value = 0
} else {
$Value = ""
}
} else {
if ($Numeric) {
$Value = MakeNumber -Num $valueBytes -Size $Size -Parts $Parts
} else {
$value = ""
0..($valueBytes.Length-1) | ForEach-Object {
if ($valueBytes[$_] -ne 0) {
$value = $value + [System.Text.Encoding]::ASCII.GetString($valueBytes[$_])
}
}
if ($null -ne $value -and $Size -gt 0 -and $Size -lt $Value.Length) {
$Value = $Value.Substring(0,$Size)
}
}
}
}
}
}
Catch{
$Value = "<empty>"
if ($Numeric) {
Write-Host "Type $($valueBytes.GetType())"
Write-Host "Error in exif: $_"
} else {
Write-Host "Error in exif: $_"
}
$Value = ""
}
return $Value
}
function Get-ByteMultiplier {
param(
[Parameter(Mandatory)]
[int] $Factor
)
Function Get-ImageFileContents {
param(
[String] $ImageFile
)
$byteMultiplier = 1
1..$Factor | ForEach-Object {
$byteMultiplier = $byteMultiplier * 256
}
return $byteMultiplier
}
function MakeNumber {
param(
[Parameter(Mandatory)]
[byte[]] $Num,
[int] $Size,
[int] $Parts = 1
)
if ($null -eq $Num) {
return "<null>"
}
if ($Num.Length -eq $Size -and $Parts -eq 1) {
if ($Size -eq 1) {
return ($Num[0])
}
if ($Size -eq 2) {
return ( $Num[0] + 256 * $Num[1] )
}
}
# GPS cords
if ($Num.Length -eq 24 -and $Parts -eq 3) {
$First =$Num[0] + (Get-ByteMultiplier 1) * $Num[1] + (Get-ByteMultiplier 2) * $Num[2] + (Get-ByteMultiplier 3) * $Num[3] ;
$Second=$Num[8] + (Get-ByteMultiplier 1) * $Num[9] + (Get-ByteMultiplier 2) * $Num[10] + (Get-ByteMultiplier 3) * $Num[11] ;
$Third=$Num[16] + 256 * $Num[17] + 65536 * $Num[18] + 16777216 * $Num[19] ;
return @($first, $second, $third)
}
# Shutter
if ($Num.Length -eq 8 -and $Parts -eq 2) {
$First =$Num[0] + (Get-ByteMultiplier 1) * $Num[1] + (Get-ByteMultiplier 2) * $Num[2] + (Get-ByteMultiplier 3) * $Num[3] ;
$Second=$Num[4] + (Get-ByteMultiplier 1) * $Num[5] + (Get-ByteMultiplier 2) * $Num[6] + (Get-ByteMultiplier 3) * $Num[7] ;
if ($first -gt 2147483648) {
$first = $first - (Get-ByteMultiplier 4)
}
if ($Second -gt 2147483648) {
$Second= $Second - (Get-ByteMultiplier 4)
}
if ($Second -eq 0) {
$Second= 1
}
if (($first -eq 1) -and ($Second -ne 1)) {
$first = "1"
}
return @($first, $second)
}
$First =$Num[0] + (Get-ByteMultiplier 1) * $Num[1] + (Get-ByteMultiplier 2) * $Num[2] + (Get-ByteMultiplier 3) * $Num[3] ;
return $first
}
function Get-ImageFileContents {
param(
[Parameter(Mandatory)]
[String] $ImageFile
)
if (!(Test-Path -Path $ImageFile)) {
Write-Host "File not found: $ImageFile"
break
}
Try {
$fullPath = (Resolve-Path $ImageFile).Path
$fs = [System.IO.File]::OpenRead($fullPath)
$image = [System.Drawing.Image]::FromStream($fs, $false, $false)
$maker = Get-ExifContents -ImageStream $image -ExifCode 271
$model = Get-ExifContents -ImageStream $image -ExifCode 272
$version = Get-ExifContents -ImageStream $image -ExifCode 305
$dateTime = Get-ExifContents -ImageStream $image -ExifCode 306
$latRef = Get-ExifContents -ImageStream $image -ExifCode 1
$longRef = Get-ExifContents -ImageStream $image -ExifCode 3
$fullPath = (Resolve-Path $ImageFile).Path
$fileStreamArgs = @($fullPath
[System.IO.FileMode]::Open
[System.IO.FileAccess]::Read
[System.IO.FileShare]::Read
1024,
[System.IO.FileOptions]::SequentialScan
)
$fs = New-Object System.IO.FileStream -ArgumentList $fileStreamArgs
$image = [System.Drawing.Image]::FromStream($fs)
$val = Get-ExifContents -ImageStream $image -ExifCode 37378 -Numeric -Size 8 -Parts 2
if ($null -eq $val -or $val -eq "") {
$Aperture = ""
} else {
if ($val.Length -eq 2) {
$Aperture = "$($val[0]/$val[1])"
} else {
$Aperture = $val[0]
}
}
# Flash
$val = Get-ExifContents -ImageStream $image -ExifCode 37385 -Numeric -Size 2
if (($val % 2) -eq 1){
$Flash = $true
} else {
$Flash = $false
}
# Shutterspeed
$val = Get-ExifContents -ImageStream $image -ExifCode 33434 -Numeric -Size 8 -Parts 2
if ($null -eq $val -or $val -eq "") {
$Shutterspeed = ""
} else {
if ($val.Length -eq 2) {
$Shutterspeed = "$($val[0])/$($val[1])"
} else {
$Shutterspeed = $val[0]
}
}
# Latitude
$val = Get-ExifContents -ImageStream $image -ExifCode 2 -Numeric -Size 24 -Parts 3
if ($null -eq $val -or $val -eq "") {
$Latitude = ""
} else {
if ($val.Length -eq 3) {
$Latitude = "$($val[0]).$($val[1]).$($val[2])"
} else {
$Latitude = $val[0]
}
}
# Longitude
$val = Get-ExifContents -ImageStream $image -ExifCode 4 -Numeric -Size 24 -Parts 3
if ($null -eq $val -or $val -eq "") {
$Longitude = ""
} else {
if ($val.Length -eq 3) {
$Longitude = "$($val[0]).$($val[1]).$($val[2])"
} else {
$Longitude = $val[0]
}
}
$ExifData = [PSCustomObject][ordered]@{
File = $ImageFile
CameraMaker = $maker
CameraModel = $model
SoftwareVersion = $version
DateTaken = $dateTime
DateTaken = Get-ExifContents -ImageStream $image -ExifCode 36867 -Size 19
DateDigitized = Get-ExifContents -ImageStream $image -ExifCode 36868 -Size 19
DateModified = Get-ExifContents -ImageStream $image -ExifCode 306 -Size 19
Author = Get-ExifContents -ImageStream $image -ExifCode 40093
Title = Get-ExifContents -ImageStream $image -ExifCode 40091 #270
Subject = Get-ExifContents -ImageStream $image -ExifCode 40095
Comments = Get-ExifContents -ImageStream $image -ExifCode 40092 #37510
Keywords = Get-ExifContents -ImageStream $image -ExifCode 40094
Artist = Get-ExifContents -ImageStream $image -ExifCode 315
Copyright = Get-ExifContents -ImageStream $image -ExifCode 33432
Height = Get-ExifContents -ImageStream $image -ExifCode 40963 -Numeric
Width = Get-ExifContents -ImageStream $image -ExifCode 40962 -Numeric
PixelX = Get-ExifContents -ImageStream $image -ExifCode 40962 -Numeric -Size 8
PixelY = Get-ExifContents -ImageStream $image -ExifCode 40963 -Numeric -Size 8
ResolutionX = Get-ExifContents -ImageStream $image -ExifCode 282 -Numeric
ResolutionY = Get-ExifContents -ImageStream $image -ExifCode 283 -Numeric
CameraMaker = Get-ExifContents -ImageStream $image -ExifCode 271
CameraModel = Get-ExifContents -ImageStream $image -ExifCode 272
CameraLabel = Get-ExifContents -ImageStream $image -ExifCode 51105
SoftwareVersion = Get-ExifContents -ImageStream $image -ExifCode 305
LatitudeRef = Get-ExifContents -ImageStream $image -ExifCode 1
Latitude = $Latitude
LongitudeRef = Get-ExifContents -ImageStream $image -ExifCode 3
Longitude = $Longitude
ExifVersion = Get-ExifContents -ImageStream $image -ExifCode 36864
Flash = $Flash
Iso = Get-ExifContents -ImageStream $image -ExifCode 34855 -Numeric
FocalLength = Get-ExifContents -ImageStream $image -ExifCode 37386 -Numeric -Size 2
ShutterSpeed = $Shutterspeed
Aperture = $Aperture
FNumber = Get-ExifContents -ImageStream $image -ExifCode 33437 -Numeric -Size 4
}
$image.dispose()
$fs.Close()
Write-Host " File '$($ExifData.File)' and maker '$($ExifData.CameraMaker)' "
return $ExifData
}
Catch {
Write-Host "Error: $_"
Write-Error "Error Opening '$ImageFile'"
if ($image) {
$image.dispose()
@ -64,8 +284,9 @@ param(
if ($fs) {
$fs.close()
}
break
return $null
}
}
#Get-ImageFileContents -ImageFile "E:\tom\Projects\powershell\ptrFiles\assets\03.jpg"

View File

@ -45,8 +45,9 @@
.Parameter Action
Action to perform, which can be:
- Install : Install 7Zip4PowerShell and other modules
- Pack : Archive the contents of a folder(s)
- Put : Send the archive to AWS S3 or Backblaze
- Get : Receive the archive from AWS S3 or Backblaze
- Unpack : Unpack the archive, but no reconfile is performed
- Reconcile : Reconcile the contents in the restored folder
- ReconcileFile : Generate reconfile file. The pack process does this.
@ -194,75 +195,92 @@
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)][String] $Action,
[Parameter(Mandatory)][String] $Path,
[Parameter(Mandatory)]
[Alias("Task")]
[String] $Action,
[Parameter(Mandatory)]
[Alias("Directory","DirectoryPath","Folder","FolderPath")]
[String] $Path,
[String] $RecipientKey,
[Alias("Password")]
[String] $SecretKey,
[Alias("CompressFile")]
[String] $ArchiveFile,
[String] $RootFolder,
[String] $FileFilter,
[String] $ReconcileFile,
[String] $SecretFile,
[Alias("Profile", "Username")]
[String] $CloudProfile,
[switch] $ExcludeHash,
[String] $LogPath
[switch] $IncludeExif,
[String] $LogPath = ""
)
Import-Module .\PeterDocs
$actioned = $false
if ($action -eq "Install") {
$actioned = $true
if ($cloudProfile -eq "") {
Install-Module -Name 7Zip4Powershell -Scope CurrentUser
Install-Module -Name AWS.Tools.Installer -Scope CurrentUser
Install-Module -Name AWS.Tools.S3 -Scope CurrentUser
Install-Module -Name Meerkat.PeterDocs -Scope CurrentUser
} else {
Install-Module -Name 7Zip4Powershell -Scope $cloudProfile
Install-Module -Name AWS.Tools.Installer -Scope $cloudProfile
Install-Module -Name AWS.Tools.S3 -Scope $cloudProfile
Install-Module -Name Meerkat.PeterDocs -Scope $cloudProfile
}
}
if ($action -eq "Pack") {
$actioned = $true
Compress-Peter -TransferFolder $path -Secret $secret -ArchiveFile $archiveFile -ReconcileFile $reconcileFile -RootFolder $rootFolder -FileFilter $fileFilter
if ($ExcludeHash) {
Compress-Peter -ExcludeHash -SourceFolder $path -SecretKey $SecretKey -ArchiveFile $archiveFile -ReconcileFile $reconcileFile -RootFolder $rootFolder -FileFilter $fileFilter -LogPath $LogPath -IncludeExif
} else {
Compress-Peter -SourceFolder $path -SecretKey $SecretKey -ArchiveFile $archiveFile -ReconcileFile $reconcileFile -RootFolder $rootFolder -FileFilter $fileFilter -LogPath $LogPath -IncludeExif
}
}
if ($action -eq "Put") {
$actioned = $true
Send-Peter -ArchiveFile $archiveFile -TargetPath $path -SecretFile $secretFile -TargetProfile $cloudProfile
Send-Peter -ArchiveFile $archiveFile -TargetPath $path -SecretFile $secretFile -TargetProfile $cloudProfile -LogPath $LogPath
}
if ($action -eq "Get") {
$actioned = $true
Receive-Peter -ArchiveFile $archiveFile -SourcePath $path -SecretFile $secretFile -SourceProfile $cloudProfile
Receive-Peter -ArchiveFile $archiveFile -SourcePath $path -SecretFile $secretFile -SourceProfile $cloudProfile -LogPath $LogPath
}
if ($action -eq "Unpack") {
$actioned = $true
Expand-Peter -RestoreFolder $path -Secret $secret -ArchiveFile $ArchiveFile
Expand-Peter -RestoreFolder $path -SecretKey $secretKey -SecretFile $secretFile -ArchiveFile $ArchiveFile -LogPath $LogPath
}
if ($action -eq "ReconcileFile") {
$actioned = $true
Build-PeterReconcile -ReconcileFile $reconcileFile -FolderName $path -Feedback -RootFolder $rootFolder -FileFilter $fileFilter
if ($ExcludeHash) {
New-PeterReconcile -ExcludeHash -ReconcileFile $reconcileFile -SourceFolder $path -Feedback -RootFolder $rootFolder -FileFilter $fileFilter -LogPath LogPath
} else {
New-PeterReconcile -ReconcileFile $reconcileFile -SourceFolder $path -Feedback -RootFolder $rootFolder -FileFilter $fileFilter -LogPath LogPath -IncludeExif
}
}
if ($action -eq "Reconcile") {
$actioned = $true
Compare-Peter -ReconcileFile $reconcileFile -RestoreFolder $path -RootFolder $rootFolder
if ($ExcludeHash) {
Compare-Peter -ExcludeHash -ReconcileFile $reconcileFile -RestoreFolder $path -RootFolder $rootFolder -LogPath $LogPath
} else {
Compare-Peter -ReconcileFile $reconcileFile -RestoreFolder $path -RootFolder $rootFolder -LogPath $LogPath
}
}
if ($action -eq "ArchiveInformation") {
@ -286,50 +304,6 @@ Import-Module .\PeterDocs
}
if ($action -eq "MakeCert") {
$actioned = $true
if (($RecipientKey -eq "") -and ($SecretKey -eq "")) {
Write-Host "Recipient Key Name required to create a standard certificate" -ForegroundColor Red
return
}
if ($Path -ne "Cert:\CurrentUser\My") {
Write-Host "The -Path value needs to be 'Cert:\CurrentUser\My'" -ForegroundColor Red
return
}
Write-Host "Making a file encryption certificate"
New-SelfSignedCertificate -Subject $RecipientKey -KeyFriendlyName $RecipientKey -DnsName $RecipientKey -CertStoreLocation $Path -KeyUsage KeyEncipherment,DataEncipherment, KeyAgreement -Type DocumentEncryptionCert
}
if ($action -eq "ListCert") {
$actioned = $true
if ($Path -ne "Cert:\CurrentUser\My") {
Write-Host "The -Path value needs to be 'Cert:\CurrentUser\My'" -ForegroundColor Red
return
}
Write-Host "Listing encryption certificates"
if ($RecipientKey -eq "")
{
Get-Childitem -Path $Path -DocumentEncryptionCert
} else {
Write-Host ""
Write-Host " PSParentPath: Microsoft.PowerShell.Security\Certificate::$Path"
Write-Host ""
Write-Host "Thumbprint Subject"
Write-Host "---------- -------"
Get-Childitem -Path $Path -DocumentEncryptionCert | ForEach-Object {
if ($_.Subject -eq ("CN=$RecipientKey"))
{
Write-Host "$($_.Thumbprint) $($_.Subject)"
}
}
}
}
if (!($actioned))
{
Write-Host "Unknown action '$action'. No processing performed" -ForegroundColor Red
@ -340,7 +314,6 @@ Import-Module .\PeterDocs
Write-Host " Unpack : Unpack folder contents from secure 7Zip file"
Write-Host " Reconcile : Reconcile files in unpack folder with list of packed files"
Write-Host " ReconcileFile : Generate a reconcile file without packing"
Write-Host " Install : Install required packages"
Write-Host " ArchiveInformation : Fetch archive information from archive file"
Write-Host ""
@ -348,4 +321,3 @@ Import-Module .\PeterDocs
Write-Host " Get-Help .\ptrDocs.ps1"
}

View File

@ -38,6 +38,23 @@ resolution of digital cameras.
## Usage
Some basic commands in sequence are demonstrated below:
```powershell
# Create the archive file
Compress-Peter -SourceFolder "~/Pictures/" -Secret "c0mpleX%S3cret"
# Send the archive to S3
Send-Peter -ArchiveFile "PETERDOCS_20210625_1245.7z" -TargetPath "s3://bucketname/pathpeter/PETERDOCS_20210625_1245.7z"
# Fetch the archive from S3
Receive-Peter -ArchiveFile "myarchive.7z" -SourcePath "s3://bucketname/pathpeter/PETERDOCS_20210625_1245.7z"
# Expand the archive
Expand-Peter -RestoreFolder "c:\backup\pictures" -Secret "c0mpleX%S3cret" -ArchiveFile "myarchive.7z"
# Compare the restored files
Compare-Peter -RestoreFolder "c:\backup\pictures"
```
The above commands are using the default settings for certain options
Packages source folder contents into a 7ZIP file, adding a reconciliation
file to the 7ZIP file and then encrypting the contents. Send
@ -78,10 +95,12 @@ will add text content to the same log file. The default log name takes the form
You will need to install the PeterDocs module from the PowerShell gallery or
via local file NuGet package file if Internet access is limited.
See the [Advanced Usage](Docs/Advanced.md) for more advanced options.
## Further Reading
[Design](Design.md)
[Design](Docs/Design.md)
[Install](Install.md)
[Install](Docs/Install.md)
[Compress](Compress.md)
[Compress](Docs/Compress.md)