PeterDocs/ptrFiles.ps1

349 lines
12 KiB
PowerShell

param (
[Parameter(Mandatory)][String] $Action,
[Parameter(Mandatory)][String] $Path,
[String] $RecipientKeyName,
[String] $TransferFileName,
[String] $ReconcileFileName = "##protect_transfer_reconcile##.csv",
[String] $SecretFileName = ".\transfer.key",
[switch] $ExcludeHash,
[switch] $Install7zip
)
$default_dateLocal = Get-Date -Format "yyyyMMdd_HHmm"
$default_reconcileFile = "##protect_transfer_reconcile##.csv"
$default_secretEncrypted = ".\transfer.key"
function Write-Log {
param(
[String] $LogEntry
)
$date = Get-Date -f "yyyy-MM-dd"
$logPath = Join-Path -Path ".\" -ChildPath "Logs"
$logName = "protect_transfer_reconcile_$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 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]
}
}
# Reconcile
function Set-Reconcile
{
Param(
[Parameter(Mandatory)][String] $ReconcileFile,
[Parameter(Mandatory)][String] $FolderName,
[switch]$Feedback = $false
)
if ($reconcileFile -eq "")
{
$reconcileFile = $default_reconcileFile
}
If (!(Test-Path -Path $folderName )) {
Write-Log "Folder '$folderName' does not exist"
Write-Host "Folder '$folderName' does not exist" -ForegroundColor Red
Close-Log
return
}
Write-Log "Generating reconciliation file '$reconcileFile'"
Write-Host "Generating reconciliation file '$reconcileFile'"
$totalFileCount = 0
$totalFileSize = 0
Set-Content -Path $reconcileFile -Value '"FullName","LastWriteTime","Length","Hash","ParentFolder","Object"'
Get-Childitem $folderName -Recurse | Where-Object {!$_.PSIsContainer} | ForEach-Object {
$totalFilecount = $totalFileCount + 1
$totalFileSize = $totalFileSize + $_.Length
if ($ExcludeHash) {
$sourceHash = ""
} else {
$sourceHash = (Get-FileHash -Path $_.FullName).Hash
}
$record = '"'+$_.FullName.Replace($folderName, "")+'","'+$_.LastWriteTime.ToString("yyyy-MM-ddTHH:mm:ss")+'",'+$_.Length+',"'+$sourceHash+'","'+ $_.Directory + '","' + $_.Name + '"'
Add-Content -Path $reconcileFile -Value $record
}
if ($totalFileSize -ge 1000000000000) {
$totalRightLabel = "TB"
$totalFileXbytes = [math]::Round(($totalFileSize / 1000000000000), 2)
} else {
if ($totalFileSize -ge 1000000000) {
$totalRightLabel = "GB"
$totalFileXbytes = [math]::Round(($totalFileSize / 1000000000), 2)
} else {
if ($totalFileSize -ge 1000000) {
$totalRightLabel = "MB"
$totalFileXbytes = [math]::Round(($totalFileSize / 1000000), 2)
} else {
$totalRightLabel = "KB"
$totalFileXbytes = [math]::Round(($totalFileSize / 1000), 2)
}
}
}
Write-Log "Total reconcile file count is $totalFileCount and size $totalFileXbytes $totalRightLabel"
if ($feedback) {
Write-Host "Total reconcile file count is $totalFileCount and size $totalFileXbytes $totalRightLabel" -ForegroundColor Green
}
}
function Invoke-Pack
{
Param(
[String] $TransferFolder,
[String] $ToName,
[String] $CompressFile,
[String] $ReconcileFile,
[String] $SecretEncrypted
)
# Send
If (!(Test-Path -Path $transferFolder )) {
Write-Log "Folder '$transferFolder' does not exist"
Write-Host "Folder '$transferFolder' does not exist" -ForegroundColor Red
Close-Log
return
}
Write-Log "Packing files to compress file '$compressFile'"
Write-Log "Source folder is '$transferFolder'"
Write-Host "Packing files to compress file '$compressFile'"
if ($reconcileFile -eq "")
{
$reconcileFile = $default_reconcileFile
}
if ($secretEncrypted -eq "")
{
$secretEncrypted = $default_secretEncrypted
}
# First step - create protected secret
$secret = New-RandomPassword -Length 80
Protect-CmsMessage -To $toName -OutFile $secretEncrypted -Content $secret
# Second step - compress the data files
Compress-7Zip -Path $transferFolder -ArchiveFileName $compressFile -Format SevenZip
# Third step - create the reconcile file
Set-Reconcile -ReconcileFile $reconcileFile -FolderName $transferFolder
# Fourth step - add reconcile file to ZIP and encrypt
Write-Log "Add reconcile file '$reconcileFile' to file '$compressFile'"
$fullReconcileName = (Get-Item $reconcileFile).FullName
$fullZipName = (Get-Item $compressFile).FullName
Compress-7Zip -Path $fullReconcileName -ArchiveFileName $fullZipName -Format SevenZip -Append -Password $secret -EncryptFilenames
Remove-Item $fullReconcileName
Write-Log "Package ready in file '$compressFile' from folder '$transferFolder'"
Write-Host "Package ready in file '$compressFile' from folder '$transferFolder'" -ForegroundColor Green
}
function Invoke-Unpack
{
Param(
[String] $RestoreFolder,
[String] $ToName,
[String] $CompressFile,
[String] $SecretEncrypted
)
# Receive
If (!(Test-Path -Path $CompressFile )) {
Write-Log "Transfer/compress file '$CompressFile' does not exist"
Write-Host "Transfer/compress file '$CompressFile' does not exist" -ForegroundColor Red
Close-Log
return
}
if ($secretEncrypted -eq "")
{
$secretEncrypted = $default_secretEncrypted
}
# First step - decrypt password for uncompressing
Write-Log "Restoring files transferred to '$restoreFolder'"
Write-Log "Package/Compress file is '$compressFile'"
$secret = Unprotect-CmsMessage -To $toName -Path $secretEncrypted
# Second step - uncompress the data files
Expand-7Zip -ArchiveFileName $compressFile -TargetPath $restoreFolder -Password $secret
Write-Log "Package unpacked from file '$compressFile' to folder '$restoreFolder'"
Write-Host "Package unpacked from file '$compressFile' to folder '$restoreFolder'" -ForegroundColor Green
}
# Reconcile
function Invoke-Reconcile
{
Param(
[Parameter(Mandatory)][String] $reconcileFileName,
[Parameter(Mandatory)][String] $folderName
)
Write-Log "Reconciling documents transferred"
Write-Host "Reconciling documents transferred"
If (!(Test-Path -Path $reconcileFileName )) {
Write-Log "Reconciliation file '$reconcileFileName' does not exist"
Write-Host "Reconciliation file '$reconcileFileName' does not exist" -ForegroundColor Red
Close-Log
return
}
If (!(Test-Path -Path $folderName )) {
Write-Log "Folder '$folderName' does not exist"
Write-Host "Folder '$folderName' does not exist" -ForegroundColor Red
Close-Log
return
}
Write-Log "Using reconciliation file '$reconcileFileName'"
$totalFilecount = 0
$errorCount = 0
# For each entry in the reconcile file
# find the file and compare hash
Import-Csv $reconcileFileName | ForEach-Object {
$totalFileCount = $totalFileCount +1
$restoreFileName = $(Join-Path -Path $folderName -ChildPath $_.FullName)
If (Test-Path -Path $restoreFileName ) {
$targetHash= (Get-FileHash -Path $restoreFileName).Hash
if ($_.Hash -ne $targetHash) {
$errorCount = $errorCount + 1
Write-Log "Hash mismatch for file '$restoreFileName'"
}
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'"
}
} else {
$errorCount = $errorCount + 1
Write-Log "Non existant target file '$restoreFileName'"
}
}
Write-Log "Total file count is $totalFileCount with $errorCount errors"
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
}
}
$dateTimeStart = Get-Date -f "yyyy-MM-dd HH:mm:ss"
Write-Log "***********************************************************************************"
Write-Log "* Start of processing: [$dateTimeStart]"
Write-Log "***********************************************************************************"
if ($install7zip) {
Install-Module -Name 7Zip4Powershell -Scope CurrentUser
}
$actioned = $false
if ($action -eq "Pack") {
$actioned = $true
if ($RecipientKeyName -eq "") {
Write-Log "Recipient Key Name required for packing"
Write-Host "Recipient Key Name required for packing" -ForegroundColor Red
Close-Log
return
}
if ($TransferFileName -eq "") {
$TransferFileName = ".\transfer_protect_$default_dateLocal.7z"
}
Invoke-Pack -TransferFolder $path -ToName $recipientKeyName -CompressFile $transferFileName -ReconcileFile $reconcileFileName -SecretEncrypted $secretFileName
}
if ($action -eq "Unpack") {
$actioned = $true
if ($RecipientKeyName -eq "") {
Write-Log "Recipient Key Name required for unpacking"
Write-Host "Recipient Key Name required for unpacking" -ForegroundColor Red
Close-Log
return
}
if ($TransferFileName -eq "") {
Write-Log "Transfer/Compress File Name required for unpacking"
Write-Host "Transfer/Compress File Name required for unpacking" -ForegroundColor Red
Close-Log
return
}
Invoke-Unpack -RestoreFolder $path -ToName $recipientKeyName -CompressFile $transferFileName
}
if ($action -eq "ReconcileFile") {
$actioned = $true
Set-Reconcile -ReconcileFile $reconcileFileName -FolderName $path -Feedback
}
if ($action -eq "Reconcile") {
$actioned = $true
$localReconcileFile = Join-Path -Path $path -ChildPath $reconcileFileName
Invoke-Reconcile -ReconcileFile $localReconcileFile -FolderName $path
}
if (!($actioned))
{
Write-Log "Unknown action '$action'. No processing performed"
Write-Host "Unknown action '$action'. No processing performed" -ForegroundColor Red
Write-Host "Recognised actions: "
Write-Host " Pack : Pack folder contents into secure 7Zip file"
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"
}
Close-Log