Module with comments and tested

pull/1/head
Tom Peltonen 2021-07-25 14:51:52 +10:00
parent 78d0cb52b8
commit c22c6893f0
3 changed files with 999 additions and 1336 deletions

View File

@ -3,111 +3,6 @@ $default_reconcileFile = "##protect_transfer_reconcile_files##.csv"
$default_profile = "default" $default_profile = "default"
$default_archiveFile = ".\ptr_file_##date##.7z" $default_archiveFile = ".\ptr_file_##date##.7z"
function Open-Log {
$dateTimeStart = Get-Date -f "yyyy-MM-dd HH:mm:ss"
Write-Log "***********************************************************************************"
Write-Log "* Start of processing: [$dateTimeStart]"
Write-Log "***********************************************************************************"
}
function Write-Log {
param(
[String] $LogEntry
)
$date = Get-Date -f "yyyy-MM-dd"
if ($LogPath -eq "")
{
$logPath = Join-Path -Path ".\" -ChildPath "Logs"
}
$logName = "ptr_files_$date.log"
$sFullPath = Join-Path -Path $logPath -ChildPath $logName
if (!(Test-Path -Path $logPath)) {
$null = New-Item -Path $logPath -ItemType Directory
}
if (!(Test-Path -Path $sFullPath)) {
Write-Host "Log path: $sFullPath"
$null = New-Item -Path $sFullPath -ItemType File
}
$dateTime = Get-Date -f "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $sFullPath -Value "[$dateTime]. $LogEntry"
}
function Close-Log {
$dateTime = Get-Date -f "yyyy-MM-dd HH:mm:ss"
Write-Log "***********************************************************************************"
Write-Log "* End of processing: [$dateTime]"
Write-Log "***********************************************************************************"
}
function Get-SoftwareName {
return [String] "PETERDOCS"
}
function New-RandomPassword {
param(
[int] $length = 20,
[String] $characters = "abcdefghiklmnoprstuvwxyzABCDEFGHKLMNOPRSTUVWXYZ1234567890!()?}][{@#*+-",
[switch] $ConvertToSecureString
)
$password = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
$private:ofs=""
if ($ConvertToSecureString.IsPresent) {
return ConvertTo-SecureString -String [String]$characters[$password] -AsPlainText -Force
} else {
return [String]$characters[$password]
}
}
function Test-FilesExist
{
Param(
[Parameter(Mandatory)][String] $FolderName,
[String] $FileFilter
)
Get-ChildItem $folderName -Recurse | Where-Object {!$_.PSIsContainer} | ForEach-Object {
return $true
}
return $false
}
function Get-ConvenientFileSize
{
Param(
[Parameter(Mandatory)][long] $Size
)
if ($totalFileSize -ge 1000000000000) {
$totalRightLabel = "TB"
$totalFileXbytes = [math]::Round(($size / 1000000000000), 2)
} else {
if ($totalFileSize -ge 1000000000) {
$totalRightLabel = "GB"
$totalFileXbytes = [math]::Round(($size / 1000000000), 2)
} else {
if ($totalFileSize -ge 1000000) {
$totalRightLabel = "MB"
$totalFileXbytes = [math]::Round(($size / 1000000), 2)
} else {
$totalRightLabel = "KB"
$totalFileXbytes = [math]::Round(($size / 1000), 2)
}
}
}
return $totalFileXbytes.ToString() + " " + $totalRightLabel
}
function Get-B2ApiToken { function Get-B2ApiToken {
@ -161,8 +56,10 @@ function Get-B2ApiToken {
catch catch
{ {
$errorDetail = $_.Exception.Message $errorDetail = $_.Exception.Message
Write-Error -Exception "Unable to authenticate with given APIKey.`n`r$errorDetail" ` Write-Error -Exception "Unable to authenticate with given API Key.`n`r$errorDetail" `
-Message "Unable to authenticate with given APIKey.`n`r$errorDetail" -Category AuthenticationError -Message "Unable to authenticate with given API Key.`n`r$errorDetail" -Category AuthenticationError
#throw "Unable to authenticate with given APIKey.`n`r$errorDetail"
throw $_
} }
} }
@ -335,158 +232,6 @@ function Invoke-B2SDownload {
} }
# ==============================================================================
# Reconcile
function Set-Reconcile
{
Param(
[Parameter(Mandatory)][String] $ReconcileFile,
[Parameter(Mandatory)][String] $FolderName,
[String] $RootFolderName,
[String] $FileFilter,
[switch] $Feedback = $false
)
if ($reconcileFile -eq "")
{
$reconcileFile = $default_reconcileFile
}
if ($folderName.StartsWith("@")) {
If (!(Test-Path -Path $folderName.Substring(1) )) {
Write-Log "File '$($folderName.Substring(1))' does not exist"
Write-Host "File '$($folderName.Substring(1))' does not exist" -ForegroundColor Red
Close-Log
Exit
}
} else {
If (!(Test-Path -Path $folderName )) {
Write-Log "Folder '$folderName' does not exist"
Write-Host "Folder '$folderName' does not exist" -ForegroundColor Red
Close-Log
Exit
}
}
Write-Log "Generating reconciliation file '$reconcileFile'"
Write-Host "Generating reconciliation file '$reconcileFile'"
$totalFileCount = 0
$totalFileSize = 0
if ($rootFolderName -eq "") {
$rootFolderName = $folderName
}
if ($ExcludeHash) {
$messageFrequency = 1000
} else {
$messageFrequency = 500
}
Set-Content -Path $reconcileFile -Value '"FullName","LastWriteTime","CreationTime","LastAccessTime","Length","Hash","ParentFolder","Object","Attributes","Extension"'
if ($folderName.StartsWith("@")) {
Write-Log "Using @ file '$($folderName.Substring(1))'"
Write-Host "Using @ file '$($folderName.Substring(1))'"
Get-Content -Path $($folderName.Substring(1)) | ForEach-Object {
if ($_ -ne "") {
If (!(Test-Path -Path $_ )) {
Write-Log "Folder/file '$($_)' does not exist"
Write-Host "Folder/file '$($_)' does not exist" -ForegroundColor Red
}
else {
Get-ChildItem $_ -Filter $fileFilter -Recurse | Where-Object {!$_.PSIsContainer} | ForEach-Object {
$totalFilecount = $totalFileCount + 1
$totalFileSize = $totalFileSize + $_.Length
if (($totalFilecount % $messageFrequency) -eq 0) {
Write-Log "Read $totalFileCount files and size $(Get-ConvenientFileSize -Size $totalFileSize ). Currently at folder '$($_.Directory)' "
Write-Host "Read $totalFileCount files and size $(Get-ConvenientFileSize -Size $totalFileSize ). Currently at folder '$($_.Directory)' "
}
if ($ExcludeHash) {
$sourceHash = ""
} else {
$sourceHash = (Get-FileHash -Path $_.FullName).Hash
}
$record = '"'+$_.FullName.Replace($rootFolderName, "")+'","'+$_.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+'"'
Add-Content -Path $reconcileFile -Value $record
}
}
}
}
} else {
Get-ChildItem $folderName -Filter $fileFilter -Recurse | Where-Object {!$_.PSIsContainer} | ForEach-Object {
$totalFilecount = $totalFileCount + 1
$totalFileSize = $totalFileSize + $_.Length
if (($totalFilecount % $messageFrequency) -eq 0) {
Write-Log "Read $totalFileCount files and size $(Get-ConvenientFileSize -Size $totalFileSize ). Currently at folder '$($_.Directory)' "
Write-Host "Read $totalFileCount files and size $(Get-ConvenientFileSize -Size $totalFileSize ). Currently at folder '$($_.Directory)' "
}
if ($ExcludeHash) {
$sourceHash = ""
} else {
$sourceHash = (Get-FileHash -Path $_.FullName).Hash
}
$record = '"'+$_.FullName.Replace($rootFolderName, "")+'","'+$_.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+'"'
Add-Content -Path $reconcileFile -Value $record
}
}
Write-Log "Total reconcile file count is $totalFileCount and size $(Get-ConvenientFileSize -Size $totalFileSize ) ($totalFileSize)"
if ($feedback) {
Write-Host "Total reconcile file count is $totalFileCount and size $(Get-ConvenientFileSize -Size $totalFileSize )" -ForegroundColor Green
}
}
function Invoke-SinglePack
{
Param(
[Parameter(Mandatory)][String] $ArchiveFolder,
[Parameter(Mandatory)][String] $ArchiveFile,
[String] $FileFilter,
[Boolean] $FirstCompress
)
if (!(Test-Path -Path $ArchiveFolder -PathType Leaf)) {
Write-Log "Archive folder '$ArchiveFolder'"
Write-Host "Archivefolder '$ArchiveFolder'"
}
if (Test-FilesExist -FolderName $ArchiveFolder -FileFilter $FileFilter) {
try {
if ($FirstCompress) {
Compress-7Zip -Path $ArchiveFolder -ArchiveFileName $ArchiveFile -Format SevenZip -PreserveDirectoryRoot -Filter $FileFilter
} else {
Compress-7Zip -Path $ArchiveFolder -ArchiveFileName $ArchiveFile -Format SevenZip -PreserveDirectoryRoot -Filter $FileFilter -Append
}
$FirstCompress = $false
} catch {
Write-Log "Compress error with folder/file '$ArchiveFolder'. See any previous errors. $Error"
Write-Host "Compress error with folder/file '$ArchiveFolder'. See any previous errors. $Error" -ForegroundColor Red
}
} else {
Write-Log "Empty folder/file '$ArchiveFolder'"
Write-Host "Empty folder/file '$ArchiveFolder'"
}
return $FirstCompress
}
# Compress / Package # Compress / Package
@ -619,629 +364,3 @@ function Invoke-SinglePack
#> #>
function Invoke-Pack
{
Param(
[Parameter(Mandatory)][String] $SourceFolder,
[String] $RecipientKey,
[String] $SecretKey,
[String] $ArchiveFile,
[String] $ReconcileFile,
[String] $FileFilter ="*",
[String] $SecretFile,
[switch] $ExcludeHash,
[String] $RootFolder,
[String] $LogPath
)
Open-Log
Write-Log "Function parameters follow"
Write-Log "Parameter: SourceFolder Value: $SourceFolder "
Write-Log "Parameter: RecipientKey Value: $RecipientKey "
if ($null -eq $SecretKey) {
Write-Log "Parameter: SecretKey Value: (null)) "
} else {
Write-Log "Parameter: SecretKey Value: ************** "
}
Write-Log "Parameter: ArchiveFile Value: $ArchiveFile "
Write-Log "Parameter: ReconcileFile Value: $ReconcileFile "
Write-Log "Parameter: FileFilter Value: $FileFilter "
Write-Log "Parameter: SecretFile Value: $SecretFile "
Write-Log "Parameter: ExcludeHash Value: $ExcludeHash "
Write-Log "Parameter: LogPath Value: $LogPath "
Write-Log ""
if ($SourceFolder.StartsWith("@")) {
If (!(Test-Path -Path $SourceFolder.Substring(1) )) {
Write-Log "File '$($SourceFolder.Substring(1))' does not exist"
Write-Host "File '$($SourceFolder.Substring(1))' does not exist" -ForegroundColor Red
Close-Log
Exit
}
} else {
If (!(Test-Path -Path $SourceFolder )) {
Write-Log "Folder '$SourceFolder' does not exist"
Write-Host "Folder '$SourceFolder' does not exist" -ForegroundColor Red
Close-Log
Exit
}
}
if ($RecipientKey -eq "") {
$getEnvName = $(Get-SoftwareName) + "_RECIPIENTKEY"
if ([System.Environment]::GetEnvironmentVariable($getEnvName) -ne "" -and $null -ne [System.Environment]::GetEnvironmentVariable($getEnvName)) {
$RecipientKey = [System.Environment]::GetEnvironmentVariable($getEnvName)
}
}
if (($RecipientKey -eq "") -and ($SecretKey -eq "")) {
Write-Log "Recipient Key or Secret Key required for packing"
Write-Host "Recipient Key or Secret Key required for packing" -ForegroundColor Red
Close-Log
return
}
if ($RootFolder -eq "") {
if ($SourceFolder.EndsWith("*")) {
Write-Log "Root folder required for packing when using wild card for Source Folder"
Write-Host "Root folder required for packing when using wild card for Source Folder" -ForegroundColor Red
Close-Log
return
} else {
$RootFolder = $SourceFolder
}
}
if ($ArchiveFile -eq "") {
$ArchiveFile = $default_archiveFile.Replace("##date##", (Get-Date -Format "yyyyMMdd_HHmm"))
}
if ($SecretKey -eq "") {
if ($SecretFile -eq "")
{
$SecretFile = $ArchiveFile + ".key"
}
$secret = New-RandomPassword -Length 80
Protect-CmsMessage -To $recipientKey -OutFile $SecretFile -Content $secret
} else {
$secret = $SecretKey
}
Write-Log "Saving folders/files to archive file '$ArchiveFile'"
Write-Host "Saving folders/files to archive file '$ArchiveFile'"
if ($ReconcileFile -eq "")
{
$ReconcileFile = $default_reconcileFile
}
if ($FileFilter -eq "")
{
$FileFilter = "*"
}
if ($SourceFolder.EndsWith("*"))
{
Write-Log "Archive primary folder is '$SourceFolder'"
$firstCompress = $true
Get-ChildItem $SourceFolder| ForEach-Object {
$firstCompress = Invoke-SinglePack -ArchiveFolder $_.FullName -ArchiveFile $ArchiveFile -FileFilter $FileFilter -FirstCompress $firstCompress
}
} else {
if ($SourceFolder.StartsWith("@")) {
Write-Log "Using @ file '$($SourceFolder.Substring(1))'"
Write-Host "Using @ file '$($SourceFolder.Substring(1))'"
$firstCompress = $true
Get-Content -Path $($SourceFolder.Substring(1)) | ForEach-Object {
if ($_ -ne "") {
if ($_.EndsWith("*")) {
Get-ChildItem $_ | ForEach-Object {
$firstCompress = Invoke-SinglePack -ArchiveFolder $_.FullName -ArchiveFile $ArchiveFile -FileFilter $FileFilter -FirstCompress $firstCompress
}
} else {
If (!(Test-Path -Path $_ )) {
Write-Log "Folder/file '$($_)' does not exist"
Write-Host "Folder/file '$($_)' does not exist" -ForegroundColor Red
}
else {
$firstCompress = Invoke-SinglePack -ArchiveFolder $_ -ArchiveFile $ArchiveFile -FileFilter $FileFilter -FirstCompress $firstCompress
}
}
}
}
} else {
Write-Log "Archive folder '$SourceFolder'"
Write-Host "Archive folder '$SourceFolder'"
Compress-7Zip -Path $SourceFolder -ArchiveFileName $ArchiveFile -Format SevenZip -Filter $FileFilter
}
}
If (!(Test-Path -Path $ArchiveFile )) {
Write-Log "Archive file '$ArchiveFile' was not created. See any previous errors"
Write-Host "Archive file '$ArchiveFile' was not created. See any previous errors" -ForegroundColor Red
Close-Log
Exit
}
Set-Reconcile -ReconcileFile $ReconcileFile -FolderName $SourceFolder -FileFilter $FileFilter -RootFolderName $rootFolder
If (!(Test-Path -Path $ReconcileFile )) {
Write-Log "Reconcile file '$ReconcileFile' was not created. See any previous errors"
Write-Host "Reconcile file '$ReconcileFile' was not created. See any previous errors" -ForegroundColor Red
Close-Log
return
}
Write-Log "Add reconcile file '$ReconcileFile' to file '$ArchiveFile'"
$fullReconcileName = (Get-Item $ReconcileFile).FullName
$fullZipName = (Get-Item $ArchiveFile).FullName
Compress-7Zip -Path $fullReconcileName -ArchiveFileName $fullZipName -Format SevenZip -Append -Password $secret -EncryptFilenames
Remove-Item $fullReconcileName
Write-Log "Archive file '$ArchiveFile' created from folder '$SourceFolder'"
Write-Host "Archive file '$ArchiveFile' created from folder '$SourceFolder'" -ForegroundColor Green
Close-Log
}
# Send package
function Invoke-PutArchive
{
Param(
[Parameter(Mandatory)][String] $CompressFile,
[Parameter(Mandatory)][String] $TargetPath,
[String] $SecretFile,
[String] $TargetProfile,
[String] $AccountId,
[String] $AccountKey
)
if ($compressFile -eq "") {
Write-Log "Archive file name required"
Write-Host "Archive file name required" -ForegroundColor Red
Close-Log
return
}
if ($targetProfile -eq "") {
$getEnvName = $(Get-SoftwareName) + "_PROFILE"
if ([System.Environment]::GetEnvironmentVariable($getEnvName) -ne "" -and $null -ne [System.Environment]::GetEnvironmentVariable($getEnvName)) {
$targetProfile = [System.Environment]::GetEnvironmentVariable($getEnvName)
}
if ($null -eq $targetProfile -or $targetProfile -eq "") {
$targetProfile = $default_profile
}
}
if (!(Test-Path -Path $compressFile )) {
Write-Log "Archive file '$compressFile' not found"
Write-Host "Archive file '$compressFile' not found" -ForegroundColor Red
Close-Log
return
}
if ($secretFile -eq "") {
$secretFile = $compressFile + ".key"
}
$remoteType = $false
if ($targetPath.StartsWith("s3://")) {
$remoteType = $true
[int] $offset = "s3://".Length
$parts = $targetPath.Substring($offset).Split("/")
$bucketHost = $parts[0]
$offset = $offset + $bucketHost.Length + 1
if ($bucketHost -eq "") {
Write-Log "Bucket name required"
Write-Host "Bucket name required" -ForegroundColor Red
Close-Log
return
}
Set-AWSCredential -ProfileName $targetProfile
$targetObject = $targetPath.Substring($offset)
Write-Log "Transferring '$compressFile' file to host '$bucketHost' folder '$targetObject'"
Write-Host "Transferring '$compressFile' file to host '$bucketHost' folder '$targetObject'"
Write-S3Object -BucketName $bucketHost -File $compressFile -Key $targetObject
if (Test-Path -Path $secretFile) {
$targetObject = $targetPath.Substring($offset) + ".key"
Write-Log "Transferring '$secretFile' file to host '$bucketHost' folder '$targetObject'"
Write-Host "Transferring '$secretFile' file to host '$bucketHost' folder '$targetObject'"
Write-S3Object -BucketName $bucketName -File $secretFile -Key $targetObject
}
$targetObject = $targetPath.Substring($offset)
Write-Log "Archive file '$compressFile' stored on S3 bucket '$bucketHost' at '$targetObject'"
Write-Host "Archive file '$compressFile' stored on S3 bucket '$bucketHost' at '$targetObject'" -ForegroundColor Green
}
if ($targetPath.StartsWith("b2://")) {
$remoteType = $true
[int] $offset = "b2://".Length
$parts = $targetPath.Substring($offset).Split("/")
$bucketHost = $parts[0]
$offset = $offset + $bucketHost.Length + 1
if ($null -eq $accountId -or $accountId -eq "") {
$accountId = $targetProfile
}
if ($accountKey -eq "") {
$getEnvName = $(Get-SoftwareName) + "_ACCOUNTKEY"
if ([System.Environment]::GetEnvironmentVariable($getEnvName) -ne "" -and $null -ne [System.Environment]::GetEnvironmentVariable($getEnvName)) {
$accountKey = [System.Environment]::GetEnvironmentVariable($getEnvName)
}
if ($null -eq $accountKey -or $accountKey -eq "") {
Write-Log "Account key required"
Write-Host "Account key required" -ForegroundColor Red
Close-Log
return
}
}
$b2ApiToken = Get-B2ApiToken -AccountId $accountId -AccountKey $accountKey
$b2Bucket = Get-B2Bucket -ApiToken $b2ApiToken.Token -AccountId $b2ApiToken.accountId -ApiUri $b2ApiToken.ApiUri -BucketHost $bucketHost
if ($null -eq $b2Bucket -or $b2Bucket.BucketID -eq "") {
Write-Log "Bucket '$bucketHost' not found"
Write-Host "Bucket '$bucketHost' not found" -ForegroundColor Red
Close-Log
return
}
$b2UploadUri = Get-B2UploadUri -BucketHost $b2Bucket.bucketId -FileName $compressFile -ApiUri $b2ApiToken.ApiUri -ApiToken $b2ApiToken.Token
$targetObject = $targetPath.Substring($offset)
Write-Log "Transferring '$compressFile' file to host '$bucketHost' folder '$targetObject'"
Write-Host "Transferring '$compressFile' file to host '$bucketHost' folder '$targetObject'"
$b2Upload = Invoke-B2SUpload -BucketHost $b2UploadUri.bucketId -TargetPath $targetObject -FileName $compressFile -ApiUri $b2UploadUri.uploadUri -ApiToken $b2UploadUri.Token
Write-Log "Upload: $b2Upload"
if (Test-Path -Path $secretFile) {
$targetObject = $targetPath.Substring($offset) + ".key"
Write-Log "Transferring '$secretFile' file to host '$bucketHost' folder '$targetObject'"
Write-Host "Transferring '$secretFile' file to host '$bucketHost' folder '$targetObject'"
$b2Upload = Invoke-B2SUpload -BucketHost $b2UploadUri.bucketId -TargetPath $targetObject -FileName $secretFile -ApiUri $b2UploadUri.uploadUri -ApiToken $b2UploadUri.Token
Write-Log "Upload: $b2Upload"
}
$targetObject = $targetPath.Substring($offset)
Write-Log "Archive file '$compressFile' stored on Backblaze bucket '$bucketHost' at '$targetObject'"
Write-Host "Archive file '$compressFile' stored on Backblaze bucket '$bucketHost' at '$targetObject'" -ForegroundColor Green
}
if (!($remoteType)) {
Write-Log "Unknown remote path '$targetFolder.'. No transfer performed"
Write-Host "Unknown remote path '$targetFolder.'. No transfer performed" -ForegroundColor Red
Write-Host "Recognised transfer prefixes: "
Write-Host " s3:// : Send to S3 compatible location"
Write-Host " "
Write-Host "If you are saving to local drives or network shared folders,"
Write-Host "please use your OS tools to move the file"
Write-Host " "
}
}
# Receive package
function Invoke-GetArchive
{
Param(
[Parameter(Mandatory)][String] $CompressFile,
[Parameter(Mandatory)][String] $SourcePath,
[String] $SecretFile,
[String] $SourceProfile,
[String] $AccountId,
[String] $AccountKey
)
if ($compressFile -eq "") {
Write-Log "Archive file name required"
Write-Host "Archive file name required" -ForegroundColor Red
Close-Log
return
}
if ($sourceProfile -eq "") {
$getEnvName = $(Get-SoftwareName) + "_PROFILE"
if ([System.Environment]::GetEnvironmentVariable($getEnvName) -ne "" -and $null -ne [System.Environment]::GetEnvironmentVariable($getEnvName)) {
$sourceProfile = [System.Environment]::GetEnvironmentVariable($getEnvName)
}
if ($null -eq $sourceProfile -or $sourceProfile -eq "") {
$sourceProfile = $default_profile
}
}
$remoteType = $false
if ($sourcePath.StartsWith("s3://")) {
$remoteType = $true
[int] $offset = "s3://".Length
$parts = $sourcePath.Substring($offset).Split("/")
$bucketHost = $parts[0]
$offset = $offset + $bucketHost.Length + 1
Set-AWSCredential -ProfileName $sourceProfile
$sourceObject = $sourcePath.Substring($offset)
Write-Log "Fetching '$compressFile' file from host $bucketHost folder $sourceObject"
Write-Host "Fetching '$compressFile' file from host $bucketHost folder $sourceObject"
$null = Read-S3Object -BucketName $bucketHost -File $compressFile -Key $sourceObject
if (!(Test-Path -Path $compressFile)) {
Write-Log "Archive file '$sourceObject' not found."
Write-Host "Archive file '$sourceObject' not found." -ForegroundColor Red
} else {
$sourceObject = $sourcePath.Substring($offset) + ".key"
$secretFile = $compressFile + ".key"
Write-Log "Fetching '$secretFile' file from host '$bucketHost' folder '$sourceObject'"
Write-Host "Fetching '$secretFile' file from host '$bucketHost' folder '$sourceObject'"
$null = Read-S3Object -BucketName $bucketHost -File $secretFile -Key $sourceObject
if (!(Test-Path -Path $secretFile)) {
Write-Log "Secret file '$sourceObject' not found. Required if you are using recipient keys"
Write-Host "Secret file '$sourceObject' not found. Required if you are using recipient keys"
}
$sourceObject = $sourcePath.Substring($offset)
Write-Log "Archive file '$compressFile' fetched from S3 '$sourcePath'"
Write-Host "Archive file '$compressFile' fetched from S3 '$sourcePath'" -ForegroundColor Green
}
}
if ($sourcePath.StartsWith("b2://")) {
$remoteType = $true
[int] $offset = "b2://".Length
$parts = $sourcePath.Substring($offset).Split("/")
$bucketHost = $parts[0]
$offset = $offset + $bucketHost.Length + 1
if ($null -eq $accountId -or $accountId -eq "") {
$accountId = $sourceProfile
}
if ($accountKey -eq "") {
$getEnvName = $(Get-SoftwareName) + "_ACCOUNTKEY"
if ([System.Environment]::GetEnvironmentVariable($getEnvName) -ne "" -and $null -ne [System.Environment]::GetEnvironmentVariable($getEnvName)) {
$accountKey = [System.Environment]::GetEnvironmentVariable($getEnvName)
}
if ($null -eq $accountKey -or $accountKey -eq "") {
Write-Log "Account key required"
Write-Host "Account key required" -ForegroundColor Red
Close-Log
return
}
}
$b2ApiToken = Get-B2ApiToken -AccountId $accountId -AccountKey $accountKey
$b2Bucket = Get-B2Bucket -ApiToken $b2ApiToken.Token -AccountId $b2ApiToken.accountId -ApiUri $b2ApiToken.ApiUri -BucketHost $bucketHost
if ($null -eq $b2Bucket -or $b2Bucket.BucketID -eq "") {
Write-Log "Bucket '$bucketHost' not found"
Write-Host "Bucket '$bucketHost' not found" -ForegroundColor Red
Close-Log
return
}
$sourceObject = $sourcePath.Substring($offset)
Write-Log "Fetching '$compressFile' file from host '$bucketHost' folder '$sourceObject'"
Write-Host "Fetching '$compressFile' file from host '$bucketHost' folder '$sourceObject'"
Invoke-B2SDownload -BucketHost $bucketHost -SourcePath $sourceObject -FileName $compressFile -ApiDownloadUri $b2ApiToken.DownloadUri -ApiToken $b2ApiToken.Token
if (!(Test-Path -Path $compressFile)) {
Write-Log "Archive file '$sourceObject' not found."
Write-Host "Archive file '$sourceObject' not found." -ForegroundColor Red
} else {
$sourceObject = $sourcePath.Substring($offset) + ".key"
$secretFile = $compressFile + ".key"
Write-Log "Fetching '$secretFile' file from host '$bucketHost' folder '$sourceObject'"
Write-Host "Fetching '$secretFile' file from host '$bucketHost' folder '$sourceObject'"
Invoke-B2SDownload -BucketHost $bucketHost -SourcePath $sourceObject -FileName $secretFile -ApiDownloadUri $b2ApiToken.DownloadUri -ApiToken $b2ApiToken.Token
if (!(Test-Path -Path $secretFile)) {
Write-Log "Secret file '$sourceObject' not found. Required if you are using recipient keys"
Write-Host "Secret file '$sourceObject' not found. Required if you are using recipient keys"
}
$sourceObject = $sourcePath.Substring($offset)
Write-Log "Archive file '$compressFile' fetched from Backblaze '$sourcePath'"
Write-Host "Archive file '$compressFile' fetched from Backblaze '$sourcePath'" -ForegroundColor Green
}
}
if (!($remoteType)) {
Write-Log "Unknown remote path '$sourcePath'. No get performed"
Write-Host "Unknown remote path '$sourcePath'. No get performed" -ForegroundColor Red
Write-Host "Recognised transfer prefixes: "
Write-Host " s3://bucket/path/path : Fetch from S3 compatible location"
Write-Host " b2://bucket/path/path : Fetch from Backblaze location"
Write-Host " "
Write-Host "If you are fetching from local drives or network shared folders,"
Write-Host "please use your OS tools to move the file"
Write-Host " "
}
}
# Unpack package
function Invoke-Unpack
{
Param(
[Parameter(Mandatory)][String] $RestoreFolder,
[Parameter(Mandatory)][String] $Secret,
[Parameter(Mandatory)][String] $CompressFile
)
If (!(Test-Path -Path $CompressFile )) {
Write-Log "Archive file '$CompressFile' does not exist"
Write-Host "Archive file '$CompressFile' does not exist" -ForegroundColor Red
Close-Log
Exit
}
Write-Log "Restoring files transferred to '$restoreFolder'"
Write-Log "Archive file is '$compressFile'"
# Uncompress the data files
Expand-7Zip -ArchiveFileName $compressFile -TargetPath $restoreFolder -Password $secret
Write-Log "Contents unpacked from archive file '$compressFile' to folder '$restoreFolder'"
Write-Host "Contents unpacked from archive file '$compressFile' to folder '$restoreFolder'" -ForegroundColor Green
}
# Reconcile
function Invoke-Reconcile
{
Param(
[Parameter(Mandatory)][String] $ReconcileFile,
[Parameter(Mandatory)][String] $Folder,
[String] $TargetReconcileFile,
[String] $RootFolder,
[Switch] $ExtendedCheck
)
if ($reconcileFile -eq "")
{
$reconcileFile = $default_reconcileFile
}
Write-Log "Reconciling documents transferred"
Write-Host "Reconciling documents transferred"
If (!(Test-Path -Path $reconcileFile )) {
Write-Log "Reconciliation file '$reconcileFile' does not exist"
Write-Host "Reconciliation file '$reconcileFile' does not exist" -ForegroundColor Red
Close-Log
Exit
}
If (!(Test-Path -Path $folder )) {
Write-Log "Folder '$folder' does not exist"
Write-Host "Folder '$folder' does not exist" -ForegroundColor Red
Close-Log
Exit
}
Write-Log "Using reconciliation file '$reconcileFile'"
$totalFileCount = 0
$totalFileSize = 0
$errorCount = 0
$errorCreateCount = 0
$missingFileCount = 0
$missingHash = $false
# For each entry in the reconcile file
# find the file and compare hash
Import-Csv $reconcileFile | ForEach-Object {
$totalFileCount = $totalFileCount +1
if ($rootFolder -ne "") {
$adjustedName = $_.FullName.Replace($rootFolder, "\")
$restoreFileName = $(Join-Path -Path $folder -ChildPath $adjustedName)
} else {
$restoreFileName = $(Join-Path -Path $folder -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"
}
} 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"))"
$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).Length -ne $_.Length) {
$errorCount = $errorCount + 1
Write-Log "Length mismatch for file '$restoreFileName' with target value $(Get-Item -Path $restoreFileName).Length)"
}
# Note that last / write access time is not checked by default as it will comonly be changed after restore
if ($extendedCheck) {
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"))"
}
if ((Get-Item -Path $restoreFileName).LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss") -ne $_.LastWriteTime) {
$errorCount = $errorCount + 1
Write-Log "Last write mismatch for file '$restoreFileName' with target value $((Get-Item -Path $restoreFileName).LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss"))"
}
}
$totalFileSize = $totalFileSize + (Get-Item -Path $restoreFileName).Length
} else {
$missingFileCount = $missingFileCount + 1
$errorCount = $errorCount + 1
Write-Log "Non existant target file '$restoreFileName'"
}
}
Write-Log "Total file storage size is $(Get-ConvenientFileSize -Size $totalFileSize ) ($totalFileSize)"
Write-Host "Total file storage size is $(Get-ConvenientFileSize -Size $totalFileSize )"
if ($missingHash)
{
Write-Log "Reconcile file had one or many or all blank hash entries"
Write-Host "Reconcile file had one or many or all blank hash entries" -ForegroundColor Yellow
}
Write-Log "Total file count is $totalFileCount with $errorCount errors"
Write-Log "There are $missingFileCount missing files"
if ($errorCreateCount -gt 0) {
Write-Log "File create mismatch count is $errorCreateCount"
Write-Host "File create mismatch count is $errorCreateCount" -ForegroundColor Red
}
if ($errorCount -gt 0) {
Write-Host "Total file count is $totalFileCount with $errorCount errors" -ForegroundColor Red
} else {
Write-Host "Total file count is $totalFileCount with $errorCount errors" -ForegroundColor Green
}
if ($missingFileCount -gt 0) {
Write-Host "There are $missingFileCount missing files" -ForegroundColor Red
}
}
<#
Export-ModuleMember -Function 'Get-SoftwareName'
Export-ModuleMember -Function 'Open-Log'
Export-ModuleMember -Function 'Write-Log'
Export-ModuleMember -Function 'Close-Log'
Export-ModuleMember -Function 'New-RandomPassword'
Export-ModuleMember -Function 'Set-Reconcile'
Export-ModuleMember -Function 'Invoke-Pack'
Export-ModuleMember -Function 'Invoke-PutArchive'
Export-ModuleMember -Function 'Invoke-GetArchive'
Export-ModuleMember -Function 'Invoke-Unpack'
Export-ModuleMember -Function 'Invoke-Reconcile'
#>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
Function Get-ExifContents {
param(
$ImageStream,
[int] $ExifCode
)
Try {
if (-not $ImageStream.PropertyIdList.Contains($ExifTagCode))
{
$Value = "<empty>"
} else {
$PropertyItem = $ImageStream.GetPropertyItem($ExifCode)
$valueBytes = $PropertyItem.Value
$Value = [System.Text.Encoding]::ASCII.GetString($valueBytes)
}
}
Catch{
$Value = "<empty>"
}
return $Value
}
Function Get-ImageFileContents {
param(
[String] $ImageFile
)
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
$ExifData = [PSCustomObject][ordered]@{
File = $ImageFile
CameraMaker = $maker
CameraModel = $model
SoftwareVersion = $version
DateTaken = $dateTime
}
$image.dispose()
$fs.Close()
Write-Host " File '$($ExifData.File)' and maker '$($ExifData.CameraMaker)' "
return $ExifData
}
Catch {
Write-Error "Error Opening '$ImageFile'"
if ($image) {
$image.dispose()
}
if ($fs) {
$fs.close()
}
return $null
}
}