Ading Exif processing
parent
ebcce55e47
commit
a2c5f23852
|
|
@ -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.
|
|
@ -31,11 +31,12 @@
|
|||
|
||||
|
||||
$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 {
|
||||
|
||||
|
||||
$dateTimeStart = Get-Date -f "yyyy-MM-dd HH:mm:ss"
|
||||
Write-Log "***********************************************************************************"
|
||||
Write-Log "* Start of processing: [$dateTimeStart]"
|
||||
|
|
@ -49,7 +50,7 @@ function Write-Log {
|
|||
)
|
||||
|
||||
$date = Get-Date -f "yyyy-MM-dd"
|
||||
|
||||
|
||||
if (($null -eq $global:LogPathName) -or ($global:LogPathName -eq ""))
|
||||
{
|
||||
$global:LogPathName = Join-Path -Path ".\" -ChildPath "Logs"
|
||||
|
|
@ -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 "
|
||||
|
|
@ -292,7 +294,16 @@ 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,13 +352,18 @@ 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+'"'
|
||||
|
||||
Add-Content -Path $ReconcileFile -Value $record
|
||||
|
||||
if ($IncludeExif) {
|
||||
$null = Get-ImageFileContents -ImageFile $($_.FullName)
|
||||
$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
|
||||
}
|
||||
|
||||
Add-Content -Path $ReconcileFile -Value $record
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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"))"
|
||||
|
|
|
|||
|
|
@ -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-ImageFileContents {
|
||||
param(
|
||||
[String] $ImageFile
|
||||
)
|
||||
|
||||
function Get-ByteMultiplier {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[int] $Factor
|
||||
)
|
||||
|
||||
$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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
25
README.md
25
README.md
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue