Initial commit
This commit is contained in:
commit
e46472393a
|
|
@ -0,0 +1 @@
|
||||||
|
config.json
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
@{
|
||||||
|
ModuleVersion = '1.0.0'
|
||||||
|
GUID = 'affc6c50-b639-478a-a2f2-b7356f1ace16'
|
||||||
|
Author = 'Alex Kohut'
|
||||||
|
Description = 'Handles logging operations.'
|
||||||
|
FunctionsToExport = @('Initialize-Logging', 'Write-Log')
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Modules/Logging/Logging.psm1
|
||||||
|
|
||||||
|
# Function to initialize the log file path
|
||||||
|
function Initialize-Logging {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Path
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store the log file path in a module-scoped variable
|
||||||
|
$Script:LogFile = $Path
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to log messages with timestamps
|
||||||
|
function Write-Log {
|
||||||
|
param (
|
||||||
|
[string]$Message,
|
||||||
|
[ValidateSet("INFO", "WARNING", "ERROR")]
|
||||||
|
[string]$Type = "INFO"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $Script:LogFile) {
|
||||||
|
Throw "Log file path is not initialized. Please run Initialize-Logging first."
|
||||||
|
}
|
||||||
|
|
||||||
|
$logTimestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||||
|
$logMessage = "$logTimestamp [$Type] - $Message"
|
||||||
|
|
||||||
|
Add-Content -Path $Script:LogFile -Value $logMessage
|
||||||
|
|
||||||
|
switch ($Type) {
|
||||||
|
"INFO" { Write-Verbose $logMessage }
|
||||||
|
"WARNING" { Write-Warning $logMessage }
|
||||||
|
"ERROR" { Write-Error $logMessage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export the functions
|
||||||
|
Export-ModuleMember -Function Initialize-Logging, Write-Log
|
||||||
|
|
@ -0,0 +1,423 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Compares the last two versions of a specified file for a given company based on the manifest.json.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
This script takes a company name and a file name as input, reads the manifest.json to find the last two backup versions of the file,
|
||||||
|
extracts them, locates the specific files within the backups, and performs a comparison. The results are logged for audit control.
|
||||||
|
|
||||||
|
.PARAMETER CompanyName
|
||||||
|
The name of the company whose file you want to compare.
|
||||||
|
|
||||||
|
.PARAMETER FileName
|
||||||
|
The specific file within the company's directory to compare.
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\Compare-NWABackup.ps1 -CompanyName "CompanyA" -FileName "DataFile.DAT"
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
Ensure that the manifest.json is correctly formatted and accessible.
|
||||||
|
#>
|
||||||
|
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$CompanyName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$FileName
|
||||||
|
)
|
||||||
|
|
||||||
|
# ----------- Step 1: Define Variables -----------
|
||||||
|
# Assuming manifest.json is located in the backup root directory
|
||||||
|
$backupRoot = "C:\Users\$env:USERNAME\Desktop\NWABackup" # Adjust as necessary
|
||||||
|
$manifestFilePath = Join-Path -Path $backupRoot -ChildPath "manifest.json"
|
||||||
|
|
||||||
|
# Define log file path
|
||||||
|
$logDirectory = Join-Path -Path $backupRoot -ChildPath "Logs"
|
||||||
|
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
||||||
|
$logFile = Join-Path -Path $logDirectory -ChildPath "$timestamp.log"
|
||||||
|
|
||||||
|
# Define temporary extraction directories
|
||||||
|
$tempExtractionRoot = Join-Path -Path $backupRoot -ChildPath "TempComparisons"
|
||||||
|
$tempDirLatest = Join-Path -Path $tempExtractionRoot -ChildPath "$FileName\Latest_$timestamp"
|
||||||
|
$tempDirPrevious = Join-Path -Path $tempExtractionRoot -ChildPath "$FileName\Previous_$timestamp"
|
||||||
|
|
||||||
|
# ----------- Step 0: Import Logging Module -----------
|
||||||
|
$modulesPath = Join-Path -Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ""
|
||||||
|
Import-Module (Join-Path -Path $modulesPath -ChildPath "Logging\Logging.psm1") -Force
|
||||||
|
|
||||||
|
# Create log directory if it doesn't exist
|
||||||
|
if (!(Test-Path -Path $logDirectory)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null
|
||||||
|
# Initialize Logging after creating the log directory
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
Write-Log -Message "Log directory created at ${logDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Failed to create log directory at ${logDirectory}: $_"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Initialize Logging if log directory already exists
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 2: Initialize Logging -----------
|
||||||
|
# Create log directory if it doesn't exist
|
||||||
|
if (!(Test-Path -Path $logDirectory)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null
|
||||||
|
# Initialize Logging after creating the log directory
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
Write-Log -Message "Log directory created at ${logDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Failed to create log directory at ${logDirectory}: $_"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Initialize Logging if log directory already exists
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log the start of the comparison process
|
||||||
|
Write-Log -Message "=== NWABackup Comparison Process Started at $timestamp ===" -Type "INFO"
|
||||||
|
|
||||||
|
# ----------- Step 3: Load the Manifest and Find the File -----------
|
||||||
|
if (!(Test-Path -Path $manifestFilePath)) {
|
||||||
|
Write-Log -Message "Manifest file not found at $manifestFilePath." -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$manifestContent = Get-Content -Path $manifestFilePath -Raw | ConvertFrom-Json
|
||||||
|
Write-Log -Message "Manifest file loaded successfully." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to load manifest file: $_" -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if the company exists in the manifest
|
||||||
|
if (-not ($manifestContent.PSObject.Properties.Name -contains $CompanyName)) {
|
||||||
|
Write-Log -Message "Company '$CompanyName' not found in the manifest." -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Navigate to the specific part for the given company
|
||||||
|
$companyData = $manifestContent.$CompanyName
|
||||||
|
$targetPart = $null
|
||||||
|
$targetZipPaths = @()
|
||||||
|
|
||||||
|
foreach ($partName in $companyData.PSObject.Properties.Name) {
|
||||||
|
# Check if the part contains a 'DAT' entry
|
||||||
|
if ($companyData.$partName.PSObject.Properties.Name -contains 'DAT') {
|
||||||
|
# Retrieve the list of zip files for 'DAT'
|
||||||
|
$datFiles = $companyData.$partName.DAT
|
||||||
|
|
||||||
|
# Check if the part name matches the provided file name (excluding extension)
|
||||||
|
$fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($FileName)
|
||||||
|
if ($fileBaseName -eq $partName) {
|
||||||
|
$targetPart = $partName
|
||||||
|
$targetZipPaths = $datFiles
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $targetPart) {
|
||||||
|
Write-Log -Message "File '$FileName' not found under any part for company '$CompanyName'." -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log -Message "Found '$FileName' under part '$targetPart' for company '$CompanyName'." -Type "INFO"
|
||||||
|
|
||||||
|
# Use the matching zip paths for comparison
|
||||||
|
$backupZips = $targetZipPaths
|
||||||
|
|
||||||
|
# ----------- Step 4: Check Number of Versions -----------
|
||||||
|
if ($backupZips.Count -lt 2) {
|
||||||
|
Write-Log -Message "Only $($backupZips.Count) version(s) found for $CompanyName\$FileName. At least two versions are required for comparison." -Type "WARNING"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 5: Get Locations of the Two Prior Backups -----------
|
||||||
|
# Function to extract DateTime from zip file name
|
||||||
|
function Get-ZipTimestamp {
|
||||||
|
param (
|
||||||
|
[string]$ZipPath
|
||||||
|
)
|
||||||
|
|
||||||
|
# Extract the zip file name without extension
|
||||||
|
$zipName = [System.IO.Path]::GetFileNameWithoutExtension($ZipPath)
|
||||||
|
|
||||||
|
# Assuming zip file name contains the timestamp in 'yyyyMMdd_HHmmss' format
|
||||||
|
$timestampString = $zipName -replace '^.*?(\d{8}_\d{6}).*$', '$1'
|
||||||
|
|
||||||
|
try {
|
||||||
|
return [datetime]::ParseExact($timestampString, 'yyyyMMdd_HHmmss', $null)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to parse timestamp from zip file name '$zipName'. Ensure the zip file name contains a timestamp in 'yyyyMMdd_HHmmss' format." -Type "ERROR"
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a list of objects containing zip paths and their timestamps
|
||||||
|
$backupList = @()
|
||||||
|
|
||||||
|
foreach ($zip in $backupZips) {
|
||||||
|
if (!(Test-Path -Path $zip)) {
|
||||||
|
Write-Log -Message "Backup zip file not found: $zip" -Type "ERROR"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$timestamp = Get-ZipTimestamp -ZipPath $zip
|
||||||
|
if ($timestamp -ne $null) {
|
||||||
|
$backupList += [PSCustomObject]@{
|
||||||
|
ZipPath = $zip
|
||||||
|
Timestamp = $timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if we have at least two valid backups
|
||||||
|
if ($backupList.Count -lt 2) {
|
||||||
|
Write-Log -Message "Not enough valid backup versions found for $CompanyName\$FileName." -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sort the backups by timestamp in descending order (latest first)
|
||||||
|
$sortedBackups = $backupList | Sort-Object -Property Timestamp -Descending
|
||||||
|
|
||||||
|
# Select the top two backups
|
||||||
|
$latestBackup = $sortedBackups[0]
|
||||||
|
$previousBackup = $sortedBackups[1]
|
||||||
|
|
||||||
|
Write-Log -Message "Latest backup: $($latestBackup.ZipPath) (Timestamp: $($latestBackup.Timestamp))" -Type "INFO"
|
||||||
|
Write-Log -Message "Previous backup: $($previousBackup.ZipPath) (Timestamp: $($previousBackup.Timestamp))" -Type "INFO"
|
||||||
|
|
||||||
|
# ----------- Step 6: Unzip the Two Folders for Inspection -----------
|
||||||
|
# Ensure temporary extraction directories exist
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $tempDirLatest -Force | Out-Null
|
||||||
|
New-Item -ItemType Directory -Path $tempDirPrevious -Force | Out-Null
|
||||||
|
Write-Log -Message "Created temporary directories for extraction." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to create temporary extraction directories: $_" -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to extract a specific file from a zip archive
|
||||||
|
function Extract-SpecificFile {
|
||||||
|
param (
|
||||||
|
[string]$ZipPath,
|
||||||
|
[string]$CompanyName,
|
||||||
|
[string]$FileName,
|
||||||
|
[string]$DestinationDir
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Expand-Archive extracts all files; to optimize, you could extract only the specific file if needed
|
||||||
|
Expand-Archive -Path $ZipPath -DestinationPath $DestinationDir -Force
|
||||||
|
Write-Log -Message "Extracted '$FileName' from '$ZipPath' to '$DestinationDir'." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to extract '$FileName' from '$ZipPath': $_" -Type "ERROR"
|
||||||
|
throw $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract the specified file from the latest backup
|
||||||
|
try {
|
||||||
|
Extract-SpecificFile -ZipPath $latestBackup.ZipPath -CompanyName $CompanyName -FileName $FileName -DestinationDir $tempDirLatest
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Extraction failed for the latest backup. Aborting comparison." -Type "ERROR"
|
||||||
|
# Cleanup before exiting
|
||||||
|
Remove-Item -Path $tempDirLatest -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path $tempDirPrevious -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract the specified file from the previous backup
|
||||||
|
try {
|
||||||
|
Extract-SpecificFile -ZipPath $previousBackup.ZipPath -CompanyName $CompanyName -FileName $FileName -DestinationDir $tempDirPrevious
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Extraction failed for the previous backup. Aborting comparison." -Type "ERROR"
|
||||||
|
# Cleanup before exiting
|
||||||
|
Remove-Item -Path $tempDirLatest -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path $tempDirPrevious -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 7: Locate the Files in Each Folder -----------
|
||||||
|
# Construct the expected file paths after extraction
|
||||||
|
$extractedFileLatest = Join-Path -Path (Join-Path -Path $tempDirLatest -ChildPath $CompanyName) -ChildPath $FileName
|
||||||
|
$extractedFilePrevious = Join-Path -Path (Join-Path -Path $tempDirPrevious -ChildPath $CompanyName) -ChildPath $FileName
|
||||||
|
|
||||||
|
# Verify that the extracted files exist
|
||||||
|
if (!(Test-Path -Path $extractedFileLatest)) {
|
||||||
|
Write-Log -Message "Latest extracted file not found at '$extractedFileLatest'." -Type "ERROR"
|
||||||
|
# Cleanup before exiting
|
||||||
|
Remove-Item -Path $tempDirLatest -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path $tempDirPrevious -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Test-Path -Path $extractedFilePrevious)) {
|
||||||
|
Write-Log -Message "Previous extracted file not found at '$extractedFilePrevious'." -Type "ERROR"
|
||||||
|
# Cleanup before exiting
|
||||||
|
Remove-Item -Path $tempDirLatest -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path $tempDirPrevious -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 8: Run a Diff Against the Two Files -----------
|
||||||
|
# Determine if the files are text or binary based on extension
|
||||||
|
$extension = [System.IO.Path]::GetExtension($FileName).ToLower()
|
||||||
|
|
||||||
|
# Function to compare text files
|
||||||
|
function Compare-TextFiles {
|
||||||
|
param (
|
||||||
|
[string]$ReferenceFile,
|
||||||
|
[string]$DifferenceFile
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Read all lines from both files
|
||||||
|
$refLines = Get-Content -Path $ReferenceFile
|
||||||
|
$diffLines = Get-Content -Path $DifferenceFile
|
||||||
|
|
||||||
|
# Determine the maximum number of lines between both files
|
||||||
|
$maxLines = [Math]::Max($refLines.Count, $diffLines.Count)
|
||||||
|
|
||||||
|
# Initialize an array to store detailed differences
|
||||||
|
$differences = @()
|
||||||
|
|
||||||
|
# Loop through each line number
|
||||||
|
for ($i = 0; $i -lt $maxLines; $i++) {
|
||||||
|
$lineNumber = $i + 1
|
||||||
|
$refLine = if ($i -lt $refLines.Count) { $refLines[$i] } else { $null }
|
||||||
|
$diffLine = if ($i -lt $diffLines.Count) { $diffLines[$i] } else { $null }
|
||||||
|
|
||||||
|
if ($refLine -ne $diffLine) {
|
||||||
|
if ($refLine -ne $null -and $diffLine -ne $null) {
|
||||||
|
# Line exists in both files but is different (Modified)
|
||||||
|
$differences += "Line ${lineNumber}: Modified"
|
||||||
|
$differences += " Reference: $refLine"
|
||||||
|
$differences += " Difference: $diffLine"
|
||||||
|
}
|
||||||
|
elseif ($refLine -ne $null) {
|
||||||
|
# Line exists only in the reference file (Removed)
|
||||||
|
$differences += "Line ${lineNumber}: Removed"
|
||||||
|
$differences += " Reference: $refLine"
|
||||||
|
}
|
||||||
|
elseif ($diffLine -ne $null) {
|
||||||
|
# Line exists only in the difference file (Added)
|
||||||
|
$differences += "Line ${lineNumber}: Added"
|
||||||
|
$differences += " Difference: $diffLine"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($differences.Count -gt 0) {
|
||||||
|
Write-Log -Message "Differences found between '$ReferenceFile' and '$DifferenceFile':" -Type "INFO"
|
||||||
|
|
||||||
|
# Log each difference
|
||||||
|
foreach ($diff in $differences) {
|
||||||
|
Write-Log -Message $diff -Type "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define the differences output file path
|
||||||
|
# Ensure that $logFile and $timestamp are accessible within this function
|
||||||
|
if ($global:LogFile -and $global:timestamp) {
|
||||||
|
$logDir = Split-Path -Path $global:LogFile -Parent
|
||||||
|
$differenceFileName = "$(Split-Path -Path $DifferenceFile -Leaf)-Differences-$($global:timestamp).txt"
|
||||||
|
|
||||||
|
# Sanitize the difference file name to remove any invalid characters
|
||||||
|
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars()
|
||||||
|
foreach ($char in $invalidChars) {
|
||||||
|
$differenceFileName = $differenceFileName -replace [regex]::Escape($char), '_'
|
||||||
|
}
|
||||||
|
|
||||||
|
$diffFilePath = Join-Path -Path $logDir -ChildPath $differenceFileName
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Fallback if $global:LogFile or $global:timestamp is not defined
|
||||||
|
$logDir = Split-Path -Path $DifferenceFile -Parent
|
||||||
|
$differenceFileName = "Differences-$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
|
||||||
|
$diffFilePath = Join-Path -Path $logDir -ChildPath $differenceFileName
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export differences to the separate file
|
||||||
|
$differences | Out-File -FilePath $diffFilePath -Encoding UTF8
|
||||||
|
|
||||||
|
Write-Output $differences
|
||||||
|
|
||||||
|
Write-Log -Message "Differences exported to '$diffFilePath'." -Type "INFO"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Output "No differences found between '$ReferenceFile' and '$DifferenceFile'."
|
||||||
|
Write-Log -Message "No differences found between '$ReferenceFile' and '$DifferenceFile'." -Type "INFO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to compare text files: $_" -Type "ERROR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to compare binary files using hash comparison
|
||||||
|
function Compare-BinaryFiles {
|
||||||
|
param (
|
||||||
|
[string]$ReferenceFile,
|
||||||
|
[string]$DifferenceFile
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hashReference = Get-FileHash -Path $ReferenceFile -Algorithm SHA256
|
||||||
|
$hashDifference = Get-FileHash -Path $DifferenceFile -Algorithm SHA256
|
||||||
|
|
||||||
|
if ($hashReference.Hash -ne $hashDifference.Hash) {
|
||||||
|
Write-Log -Message "Hash mismatch detected between '$ReferenceFile' and '$DifferenceFile'." -Type "INFO"
|
||||||
|
Write-Log -Message "Reference Hash: $($hashReference.Hash)" -Type "INFO"
|
||||||
|
Write-Log -Message "Difference Hash: $($hashDifference.Hash)" -Type "INFO"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Log -Message "No hash differences found between '$ReferenceFile' and '$DifferenceFile'." -Type "INFO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to compare binary files: $_" -Type "ERROR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute the appropriate comparison based on file type
|
||||||
|
if ($extension -eq '.dat' -or $extension -eq '.nwh') {
|
||||||
|
# Assuming .DAT and .NWH are text files; adjust if they are binary
|
||||||
|
Compare-TextFiles -ReferenceFile $extractedFilePrevious -DifferenceFile $extractedFileLatest
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# For other file types, perform binary comparison
|
||||||
|
Compare-BinaryFiles -ReferenceFile $extractedFilePrevious -DifferenceFile $extractedFileLatest
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 9: Cleanup Temporary Directories -----------
|
||||||
|
try {
|
||||||
|
Remove-Item -Path $tempDirLatest -Recurse -Force
|
||||||
|
Remove-Item -Path $tempDirPrevious -Recurse -Force
|
||||||
|
Remove-Item -Path $tempExtractionRoot -Recurse -Force
|
||||||
|
Write-Log -Message "Cleaned up temporary extraction directories." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to remove temporary directories: $_" -Type "WARNING"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 10: Completion Message -----------
|
||||||
|
Write-Log -Message "Comparison process completed for $CompanyName\$FileName." -Type "INFO"
|
||||||
|
Write-Host "Comparison completed. Check the log file at '$logFile' for details."
|
||||||
|
|
@ -0,0 +1,279 @@
|
||||||
|
# --------------------------------------------
|
||||||
|
# Northwest Analytics (NWA) Backup Script
|
||||||
|
# --------------------------------------------
|
||||||
|
# This script backs up .DAT and .NWH files from the shared
|
||||||
|
# directory to a user-specific backup folder, preserving
|
||||||
|
# the company directory structure and compressing the
|
||||||
|
# backup into a zip file. It also maintains a global
|
||||||
|
# manifest in JSON format.
|
||||||
|
# --------------------------------------------
|
||||||
|
|
||||||
|
function ConvertTo-Hashtable {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[object]$InputObject
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($InputObject -is [System.Management.Automation.PSCustomObject]) {
|
||||||
|
$hash = @{}
|
||||||
|
foreach ($prop in $InputObject.PSObject.Properties) {
|
||||||
|
$hash[$prop.Name] = ConvertTo-Hashtable -InputObject $prop.Value
|
||||||
|
}
|
||||||
|
return $hash
|
||||||
|
}
|
||||||
|
elseif ($InputObject -is [System.Array]) {
|
||||||
|
return $InputObject | ForEach-Object { ConvertTo-Hashtable -InputObject $_ }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $InputObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 0: Import Logging Module -----------
|
||||||
|
$modulesPath = Join-Path -Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ""
|
||||||
|
Import-Module (Join-Path -Path $modulesPath -ChildPath "Logging\Logging.psm1") -Force
|
||||||
|
|
||||||
|
# ----------- Step 1: Define Variables -----------
|
||||||
|
|
||||||
|
$sharedDirectory = "X:\dev\BOYD\%NWA\Data Collection" # Using environment variable
|
||||||
|
$username = $env:USERNAME
|
||||||
|
$backupRoot = "C:\Users\$username\Desktop\NWABackup"
|
||||||
|
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
||||||
|
$daysBack = 4
|
||||||
|
$thresholdDate = (Get-Date).AddDays(-$daysBack)
|
||||||
|
|
||||||
|
$backupDirectory = Join-Path -Path $backupRoot -ChildPath $timestamp
|
||||||
|
$zipFilePath = Join-Path -Path $backupRoot -ChildPath "$timestamp.zip"
|
||||||
|
$manifestFilePath = Join-Path -Path $backupRoot -ChildPath "manifest.json"
|
||||||
|
|
||||||
|
|
||||||
|
# Define log file path
|
||||||
|
$logDirectory = Join-Path -Path $backupRoot -ChildPath "Logs"
|
||||||
|
$logFile = Join-Path -Path $logDirectory -ChildPath "$timestamp.log"
|
||||||
|
|
||||||
|
# ----------- Step 2: Initialize Logging -----------
|
||||||
|
|
||||||
|
# Create log directory if it doesn't exist
|
||||||
|
if (!(Test-Path -Path $logDirectory)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null
|
||||||
|
# Initialize Logging after creating the log directory
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
Write-Log -Message "Log directory created at ${logDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Failed to create log directory at ${logDirectory}: $_"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Initialize Logging if log directory already exists
|
||||||
|
Initialize-Logging -Path $logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log the start of the backup process
|
||||||
|
Write-Log -Message "=== NWABackup Process Started at $timestamp ===" -Type "INFO"
|
||||||
|
|
||||||
|
# ----------- Step 3: Create Backup Directory -----------
|
||||||
|
|
||||||
|
if (!(Test-Path -Path $backupDirectory)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $backupDirectory -Force | Out-Null
|
||||||
|
Write-Log -Message "Backup directory created at ${backupDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to create backup directory at ${backupDirectory}. Error: $_" -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Log -Message "Backup directory already exists at ${backupDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 4: Copy .DAT and .NWH Files -----------
|
||||||
|
|
||||||
|
# Define the file extensions to include (case-insensitive)
|
||||||
|
$fileExtensions = @('.DAT', '.NWH')
|
||||||
|
|
||||||
|
Write-Log -Message "Starting file retrieval and copy process." -Type "INFO"
|
||||||
|
|
||||||
|
# Get all files recursively and filter by extension and modification date in a single pass
|
||||||
|
try {
|
||||||
|
$files = Get-ChildItem -Path $sharedDirectory -Recurse -File | Where-Object {
|
||||||
|
($fileExtensions -contains $_.Extension.ToUpper()) -and ($_.LastWriteTime -ge $thresholdDate)
|
||||||
|
}
|
||||||
|
Write-Log -Message "Found $($files.Count) files with specified extensions modified in the last $daysBack days." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Error retrieving files: $_" -Type "ERROR"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize a hashtable to build the manifest
|
||||||
|
$manifest = @{}
|
||||||
|
|
||||||
|
foreach ($file in $files) {
|
||||||
|
# Extract company name from the folder structure
|
||||||
|
$relativePath = $file.FullName.Substring($sharedDirectory.Length).TrimStart("\")
|
||||||
|
$pathParts = $relativePath.Split("\")
|
||||||
|
if ($pathParts.Length -lt 2) {
|
||||||
|
Write-Log -Message "Invalid file path structure: $relativePath" -Type "WARNING"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$companyName = $pathParts[0]
|
||||||
|
$fileName = $pathParts[-1]
|
||||||
|
|
||||||
|
# Extract part name and file type from the file name
|
||||||
|
$partName, $fileType = $fileName -split '\.', 2
|
||||||
|
|
||||||
|
if (-not $fileType) {
|
||||||
|
Write-Log -Message "Invalid file format: $fileName" -Type "WARNING"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize company entry if not exists
|
||||||
|
if (-not $manifest.ContainsKey($companyName)) {
|
||||||
|
$manifest[$companyName] = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize part entry if not exists
|
||||||
|
if (-not $manifest[$companyName].ContainsKey($partName)) {
|
||||||
|
$manifest[$companyName][$partName] = @{} # This must be a hash table, not an array
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize file type entry if not exists
|
||||||
|
if (-not $manifest[$companyName][$partName].ContainsKey($fileType)) {
|
||||||
|
$manifest[$companyName][$partName][$fileType] = @()
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add the current backup zip file to the file type's backup array
|
||||||
|
if (-not $manifest[$companyName][$partName][$fileType].Contains($zipFilePath)) {
|
||||||
|
$manifest[$companyName][$partName][$fileType] += $zipFilePath
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define the destination path
|
||||||
|
$destinationPath = Join-Path -Path $backupDirectory -ChildPath $relativePath
|
||||||
|
|
||||||
|
# Get the destination directory
|
||||||
|
$destinationDir = Split-Path -Path $destinationPath -Parent
|
||||||
|
|
||||||
|
# Create the destination directory if it doesn't exist
|
||||||
|
if (!(Test-Path -Path $destinationDir)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $destinationDir -Force | Out-Null
|
||||||
|
Write-Log -Message "Created directory: ${destinationDir}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to create directory ${destinationDir}: $_" -Type "ERROR"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy the file to the backup directory
|
||||||
|
try {
|
||||||
|
Copy-Item -Path $file.FullName -Destination $destinationPath -Force -ErrorAction Stop
|
||||||
|
Write-Log -Message "Copied: $($file.FullName) to ${destinationPath}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to copy $($file.FullName) to ${destinationPath}: $_" -Type "ERROR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ----------- Step 5: Update and Save the Manifest JSON -----------
|
||||||
|
if (Test-Path -Path $manifestFilePath) {
|
||||||
|
try {
|
||||||
|
$existingManifest = Get-Content -Path $manifestFilePath | ConvertFrom-Json
|
||||||
|
Write-Log -Message "Loaded existing manifest file." -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to load existing manifest file. Creating a new one. Error: $_" -Type "ERROR"
|
||||||
|
$existingManifest = @{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$existingManifest = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert PSCustomObject to Hashtable
|
||||||
|
$existingManifest = ConvertTo-Hashtable -InputObject $existingManifest
|
||||||
|
|
||||||
|
# Merge the current manifest into the existing manifest
|
||||||
|
foreach ($company in $manifest.Keys) {
|
||||||
|
if (-not $existingManifest.ContainsKey($company)) {
|
||||||
|
$existingManifest[$company] = @{}
|
||||||
|
Write-Log -Message "Added new company '$company' to manifest." -Type "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($partName in $manifest[$company].Keys) {
|
||||||
|
if (-not $existingManifest[$company].ContainsKey($partName)) {
|
||||||
|
$existingManifest[$company][$partName] = @{}
|
||||||
|
Write-Log -Message "Added new part '$partName' under company '$company' to manifest." -Type "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($fileType in $manifest[$company][$partName].Keys) {
|
||||||
|
if (-not $existingManifest[$company][$partName].ContainsKey($fileType)) {
|
||||||
|
$existingManifest[$company][$partName][$fileType] = @()
|
||||||
|
Write-Log -Message "Added new file type '$fileType' under part '$partName' for company '$company' to manifest." -Type "INFO"
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($zip in $manifest[$company][$partName][$fileType]) {
|
||||||
|
# Ensure the value is treated as an array
|
||||||
|
if ($existingManifest[$company][$partName][$fileType] -isnot [System.Collections.ArrayList]) {
|
||||||
|
$existingManifest[$company][$partName][$fileType] = @($existingManifest[$company][$partName][$fileType])
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add the zip path to the array if it doesn't already exist
|
||||||
|
if (-not $existingManifest[$company][$partName][$fileType].Contains($zip)) {
|
||||||
|
$existingManifest[$company][$partName][$fileType] += $zip
|
||||||
|
Write-Log -Message "Added zip '$zip' to '$company\\$partName\\$fileType' in manifest." -Type "INFO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert the hashtable to JSON with formatting
|
||||||
|
$jsonContent = $existingManifest | ConvertTo-Json -Depth 10 -Compress:$false
|
||||||
|
|
||||||
|
# Save the updated manifest
|
||||||
|
try {
|
||||||
|
Set-Content -Path $manifestFilePath -Value $jsonContent -Encoding UTF8
|
||||||
|
Write-Log -Message "Manifest file updated at $manifestFilePath" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to update manifest file at $manifestFilePath. Error: $_" -Type "ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ----------- Step 6: Compress the Backup Directory -----------
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Compress the *contents* of the backup directory, not the directory itself
|
||||||
|
Compress-Archive -Path "$backupDirectory\*" -DestinationPath $zipFilePath -Force
|
||||||
|
Write-Log -Message "Successfully compressed backup to $zipFilePath" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to compress backup directory: $_" -Type "ERROR"
|
||||||
|
# Optionally, decide whether to exit or continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 7: Cleanup (Optional) -----------
|
||||||
|
|
||||||
|
# Optionally, remove the uncompressed backup directory after compression
|
||||||
|
try {
|
||||||
|
Remove-Item -Path $backupDirectory -Recurse -Force
|
||||||
|
Write-Log -Message "Removed uncompressed backup directory: ${backupDirectory}" -Type "INFO"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Log -Message "Failed to remove uncompressed backup directory ${backupDirectory}: $_" -Type "ERROR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- Step 8: Completion Message -----------
|
||||||
|
|
||||||
|
Write-Log -Message "Backup process completed." -Type "INFO"
|
||||||
|
|
||||||
|
# Optionally, display a message to the user
|
||||||
|
Write-Host "Backup completed successfully. Log file located at $logFile"
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
$configFilePath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
|
||||||
|
|
||||||
|
# Check if the configuration file exists
|
||||||
|
if (-Not (Test-Path $configFilePath)) {
|
||||||
|
Write-Error "Configuration file not found at $configFilePath"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load the configuration file
|
||||||
|
$config = Get-Content $configFilePath | ConvertFrom-Json
|
||||||
|
|
||||||
|
# Variables for script paths
|
||||||
|
$backupScriptPath = $config.BackupScriptPath
|
||||||
|
$compareScriptPath = $config.CompareScriptPath
|
||||||
|
$outputPath = $config.OutputPath
|
||||||
|
|
||||||
|
# Import necessary assemblies for GUI
|
||||||
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
|
Add-Type -AssemblyName System.Drawing
|
||||||
|
|
||||||
|
$processing = $false
|
||||||
|
|
||||||
|
# Create Form
|
||||||
|
$form = New-Object System.Windows.Forms.Form
|
||||||
|
$form.Text = "NWA Sentinel"
|
||||||
|
$form.Size = New-Object System.Drawing.Size(800, 700)
|
||||||
|
$form.StartPosition = "CenterScreen"
|
||||||
|
|
||||||
|
# Create Backup Button
|
||||||
|
$backupButton = New-Object System.Windows.Forms.Button
|
||||||
|
$backupButton.Text = "Backup"
|
||||||
|
$backupButton.Size = New-Object System.Drawing.Size(100, 30)
|
||||||
|
$backupButton.Location = New-Object System.Drawing.Point(10, 10)
|
||||||
|
$form.Controls.Add($backupButton)
|
||||||
|
|
||||||
|
# Create Company List Box
|
||||||
|
$companyList = New-Object System.Windows.Forms.ListBox
|
||||||
|
$companyList.Size = New-Object System.Drawing.Size(200, 300)
|
||||||
|
$companyList.Location = New-Object System.Drawing.Point(10, 50)
|
||||||
|
$form.Controls.Add($companyList)
|
||||||
|
|
||||||
|
# Create File Details List Box
|
||||||
|
$fileDetailsListBox = New-Object System.Windows.Forms.ListBox
|
||||||
|
$fileDetailsListBox.Size = New-Object System.Drawing.Size(550, 300)
|
||||||
|
$fileDetailsListBox.Location = New-Object System.Drawing.Point(220, 50)
|
||||||
|
$form.Controls.Add($fileDetailsListBox)
|
||||||
|
|
||||||
|
# Create Compare Button
|
||||||
|
$compareButton = New-Object System.Windows.Forms.Button
|
||||||
|
$compareButton.Text = "Compare"
|
||||||
|
$compareButton.Size = New-Object System.Drawing.Size(100, 30)
|
||||||
|
$compareButton.Location = New-Object System.Drawing.Point(10, 360)
|
||||||
|
$compareButton.Enabled = $false
|
||||||
|
$form.Controls.Add($compareButton)
|
||||||
|
|
||||||
|
# Create QXP Button
|
||||||
|
$qxpButton = New-Object System.Windows.Forms.Button
|
||||||
|
$qxpButton.Text = "QXP"
|
||||||
|
$qxpButton.Size = New-Object System.Drawing.Size(100, 30)
|
||||||
|
$qxpButton.Location = New-Object System.Drawing.Point(120, 360)
|
||||||
|
$qxpButton.Enabled = $false
|
||||||
|
$form.Controls.Add($qxpButton)
|
||||||
|
|
||||||
|
# Create Compare Output Text Box
|
||||||
|
$compareOutputBox = New-Object System.Windows.Forms.TextBox
|
||||||
|
$compareOutputBox.Multiline = $true
|
||||||
|
$compareOutputBox.ReadOnly = $true
|
||||||
|
$compareOutputBox.ScrollBars = "Vertical"
|
||||||
|
$compareOutputBox.Size = New-Object System.Drawing.Size(760, 200)
|
||||||
|
$compareOutputBox.Location = New-Object System.Drawing.Point(10, 400)
|
||||||
|
$form.Controls.Add($compareOutputBox)
|
||||||
|
|
||||||
|
# Load Company Names into ListBox from manifest.json
|
||||||
|
$manifestPath = "C:\Users\$env:USERNAME\Desktop\NWABackup\manifest.json"
|
||||||
|
$manifestData = $null
|
||||||
|
if (Test-Path $manifestPath) {
|
||||||
|
try {
|
||||||
|
$manifestData = Get-Content -Path $manifestPath | ConvertFrom-Json
|
||||||
|
$companyNames = $manifestData.PSObject.Properties.Name
|
||||||
|
$companyList.Items.AddRange($companyNames)
|
||||||
|
} catch {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Failed to parse manifest.json: $_", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Manifest file not found at $manifestPath", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Event: When a company is selected, populate file details
|
||||||
|
$companyList.Add_SelectedIndexChanged({
|
||||||
|
$selectedCompany = $companyList.SelectedItem
|
||||||
|
$compareOutputBox.Text = ""
|
||||||
|
$qxpButton.Enabled = $false # Disable the QXP button when the company changes
|
||||||
|
|
||||||
|
if ($selectedCompany -and $manifestData) {
|
||||||
|
$fileDetailsListBox.Items.Clear()
|
||||||
|
try {
|
||||||
|
# Retrieve the file groups for the selected company
|
||||||
|
$fileGroups = $manifestData.$selectedCompany.PSObject.Properties
|
||||||
|
|
||||||
|
foreach ($group in $fileGroups) {
|
||||||
|
$fileData = $group.Value
|
||||||
|
$datFiles = $fileData.DAT
|
||||||
|
$qxpFiles = $fileData.QXP
|
||||||
|
|
||||||
|
# Extract dates from zip file paths
|
||||||
|
$dates = $datFiles | ForEach-Object {
|
||||||
|
if ($_ -match "\\(\d{8})_(\d{6})\.zip$") {
|
||||||
|
# Combine date and time into a single string
|
||||||
|
$dateTimeString = "$($matches[1])$($matches[2])"
|
||||||
|
[datetime]::ParseExact($dateTimeString, "yyyyMMddHHmmss", $null)
|
||||||
|
} else {
|
||||||
|
$null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the latest date
|
||||||
|
$latestDate = $dates | Where-Object { $_ } | Sort-Object -Descending | Select-Object -First 1
|
||||||
|
|
||||||
|
# Display the file group and its latest date
|
||||||
|
$latestDateText = if ($latestDate) {
|
||||||
|
$latestDate.ToString("yyyy-MM-dd HH:mm:ss")
|
||||||
|
} else {
|
||||||
|
"No valid date found"
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupName = [string]$group.Name
|
||||||
|
$fileDetailsListBox.Items.Add("$latestDateText :: $groupName")
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Error processing files for company '$selectedCompany': $_", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$fileDetailsListBox.Add_SelectedIndexChanged({
|
||||||
|
$compareOutputBox.Text = "" # Clear the output box
|
||||||
|
$compareButton.Enabled = $true # Enable the Compare button
|
||||||
|
|
||||||
|
$selectedFileGroup = $fileDetailsListBox.SelectedItem
|
||||||
|
$selectedCompany = $companyList.SelectedItem
|
||||||
|
$qxpButton.Enabled = $false # Disable the QXP button by default
|
||||||
|
|
||||||
|
if ($selectedFileGroup -and $selectedCompany -and $manifestData) {
|
||||||
|
try {
|
||||||
|
# Extract the part name from the selected file group
|
||||||
|
$partName = $selectedFileGroup -replace ".* :: ", ""
|
||||||
|
|
||||||
|
# Check if the selected part has QXP files
|
||||||
|
$qxpFiles = $manifestData.$selectedCompany.$partName.QXP
|
||||||
|
|
||||||
|
if ($qxpFiles -and $qxpFiles.Count -gt 0) {
|
||||||
|
$qxpButton.Enabled = $true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Error checking QXP availability for '$selectedFileGroup': $_", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# Backup Button Click Event
|
||||||
|
$backupButton.Add_Click({
|
||||||
|
if (Test-Path $backupScriptPath) {
|
||||||
|
Start-Process -FilePath "powershell.exe" -ArgumentList "-File `"$backupScriptPath`"" -NoNewWindow -Wait
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Backup completed.", "Information", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
|
||||||
|
} else {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Backup script not found at $backupScriptPath", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# Compare Button Click Event
|
||||||
|
$compareButton.Add_Click({
|
||||||
|
if ($processing) {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Please wait for the current operation to complete.", "Info", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectedCompany = $companyList.SelectedItem
|
||||||
|
$selectedFileGroup = $fileDetailsListBox.SelectedItem
|
||||||
|
|
||||||
|
if (-not $selectedCompany) {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Please select a company from the list.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $selectedFileGroup) {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Please select a file group from the list.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$processing = $true
|
||||||
|
$backupButton.Enabled = $false
|
||||||
|
$compareButton.Enabled = $false
|
||||||
|
|
||||||
|
$compareOutputBox.text = ""
|
||||||
|
# Extract the file name (ignore the date and time)
|
||||||
|
$fileName = $selectedFileGroup -replace ".* :: ", ""
|
||||||
|
|
||||||
|
# Construct the PowerShell command
|
||||||
|
$command = "$compareScriptPath -CompanyName '$selectedCompany' -FileName '$fileName.DAT'"
|
||||||
|
|
||||||
|
# Run the compare script and redirect output
|
||||||
|
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$processInfo.FileName = "powershell.exe"
|
||||||
|
$processInfo.Arguments = "-NoProfile -Command `"$command`""
|
||||||
|
$processInfo.RedirectStandardOutput = $true
|
||||||
|
$processInfo.RedirectStandardError = $true
|
||||||
|
$processInfo.UseShellExecute = $false
|
||||||
|
$processInfo.CreateNoWindow = $true
|
||||||
|
|
||||||
|
$process = New-Object System.Diagnostics.Process
|
||||||
|
$process.StartInfo = $processInfo
|
||||||
|
$process.Start() | Out-Null
|
||||||
|
|
||||||
|
# Read both standard output and error output
|
||||||
|
$output = $process.StandardOutput.ReadToEnd()
|
||||||
|
$errorOutput = $process.StandardError.ReadToEnd()
|
||||||
|
$process.WaitForExit()
|
||||||
|
|
||||||
|
# Display the output or errors in the Compare Output TextBox
|
||||||
|
if ($output) {
|
||||||
|
$compareOutputBox.Text = $output -join "`r`n"
|
||||||
|
} elseif ($errorOutput) {
|
||||||
|
$compareOutputBox.Text = "Error: $errorOutput"
|
||||||
|
} else {
|
||||||
|
$compareOutputBox.Text = "No output received from the compare script."
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Error running compare script: $($_.Exception.Message)", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
} finally {
|
||||||
|
$processing = $false
|
||||||
|
$backupButton.Enabled = $true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# Event: QXP Button Click
|
||||||
|
$qxpButton.Add_Click({
|
||||||
|
$selectedCompany = $companyList.SelectedItem
|
||||||
|
if (-not $selectedCompany) {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Please select a company from the list.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectedFileGroup = $fileDetailsListBox.SelectedItem
|
||||||
|
if (-not $selectedFileGroup) {
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Please select a file group from the list.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileName = $selectedFileGroup -replace ".* - ", ""
|
||||||
|
[System.Windows.Forms.MessageBox]::Show("Opening QXP file for ${selectedCompany}: $fileName", "QXP File", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
|
||||||
|
|
||||||
|
# Implement the actual logic for opening the QXP file if needed
|
||||||
|
})
|
||||||
|
|
||||||
|
# Show Form
|
||||||
|
$form.ShowDialog()
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"BackupScriptPath": "X:\\dev\\BOYD\\sentinel\\Modules\\NWABackup.ps1",
|
||||||
|
"CompareScriptPath": "X:\\dev\\BOYD\\sentinel\\Modules\\NWA-Compare.ps1",
|
||||||
|
"OutputPath": "C:\\Users\\$env:USERNAME\\Desktop\\NWABackup\\logs\\compare-output.txt"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue