J2897

AutomatedFlashDriveSync

Mar 28th, 2025 (edited)
425
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. .SYNOPSIS
  3.     Automates USB drive synchronization using CSV-defined mappings with event-driven monitoring.
  4.     To install as a service, use the following commands:
  5.     nssm install "AutomatedFlashDriveSync" "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "C:\Users\J2897\Code\PowerShell\DriveSync\AutomatedFlashDriveSync.ps1"
  6.     nssm set "AutomatedFlashDriveSync" Description "Automates the synchronization of USB drives with specified directories using a CSV-defined mapping."
  7.  
  8. .DESCRIPTION
  9.     This script:
  10.     1. Runs as a service monitoring USB insertion events via WMI
  11.     2. Performs automatic/manual syncs using device mappings from DeviceMapping.csv
  12.     3. Uses Robocopy for file synchronization with detailed logging
  13.     4. Supports multiple partitions per device
  14.  
  15. .OPERATION MODES
  16.     - Automatic: Triggers on USB insertion (Win32_DiskDrive creation event)
  17.     - Manual: Press 'S' to force sync, 'Q' to quit
  18.  
  19. .SYNC FEATURES
  20.     - Automatic drive letter detection
  21.     - Path validation (source/target)
  22.     - Logging with timestamps
  23.     - Error handling with exit codes
  24.     - Safe retries (R:3/W:5)
  25.  
  26. .REQUIREMENTS
  27.     - DeviceMapping.csv from mapping script (USB_Drive_Mapper_CSV.ps1)
  28.     - Robocopy available in PATH
  29.     - Admin privileges for WMI events
  30.  
  31. .NOTES
  32.     CSV must contain: DeviceID,SourceDirectory,TargetDirectory
  33.     Safe exit code range: Robocopy codes < 8
  34. #>
  35.  
  36. # Path to CSV file (global variable)
  37. $global:csvPath = "C:\Users\J2897\Code\PowerShell\DriveSync\DeviceMapping.csv"
  38.  
  39. function global:Scan-Devices {
  40.     param (
  41.         [Parameter(Mandatory=$true)]
  42.         [string]$csvFile
  43.     )
  44.     try {
  45.         Write-Host "`n[SCAN STARTED] Loading CSV from: $csvFile"
  46.         $devices = Import-Csv -Path $csvFile
  47.         Write-Host "Loaded $($devices.Count) device mappings"
  48.  
  49.         # Wait for drive initialization
  50.         Write-Host "Waiting 5 seconds for drive preparation..."
  51.         1..5 | ForEach-Object {
  52.             Write-Host "  - Second $_/5"
  53.             Start-Sleep -Seconds 1
  54.         }
  55.  
  56.         # Get fresh device lists
  57.         $diskDrives = Get-WmiObject -Class Win32_DiskDrive | Where-Object { $_.PNPDeviceID -like "USBSTOR*" }
  58.         Write-Host "Detected USB disk drives: $($diskDrives.Count)"
  59.  
  60.         foreach ($device in $devices) {
  61.             $trimmedFriendlyName = $device.FriendlyName.Trim()
  62.             Write-Host "`nProcessing device: $trimmedFriendlyName ($($device.DeviceID))"
  63.            
  64.             # Find matching disk drive
  65.             $matchingDisk = $diskDrives | Where-Object { $_.PNPDeviceID -eq $device.DeviceID }
  66.             if (-not $matchingDisk) {
  67.                 Write-Host "  No matching disk found!"
  68.                 continue
  69.             }
  70.  
  71.             Write-Host "  Found matching disk: $($matchingDisk.Model)"
  72.            
  73.             # Get drive letters
  74.             $driveLetters = $matchingDisk.GetRelated("Win32_DiskPartition") |
  75.                           ForEach-Object { $_.GetRelated("Win32_LogicalDisk") } |
  76.                           Select-Object -ExpandProperty DeviceID
  77.  
  78.             if (-not $driveLetters) {
  79.                 Write-Host "  No drive letters found!"
  80.                 continue
  81.             }
  82.  
  83.             Write-Host "  Drive letters: $($driveLetters -join ', ')"
  84.                        
  85.             foreach ($letter in $driveLetters) {
  86.                 # Ensure correct source path handling
  87.                 $sourcePath = if ($device.SourceDirectory -and $device.SourceDirectory.Trim() -ne "") {
  88.                     "$letter\$($device.SourceDirectory)"
  89.                 } else {
  90.                     "$letter\"
  91.                 }
  92.  
  93.                 Write-Host "`n  Attempting sync from: $sourcePath"
  94.                
  95.                 if (Test-Path $sourcePath) {
  96.                     Write-Host "  Source path verified - starting sync..."
  97.                    
  98.                     # Ensure the target directory exists
  99.                     if (-not (Test-Path $device.TargetDirectory)) {
  100.                         Write-Host "  Target directory does not exist. Creating: $($device.TargetDirectory)"
  101.                         New-Item -ItemType Directory -Path $device.TargetDirectory -Force | Out-Null
  102.                     }
  103.  
  104.                     $logPath = Join-Path $device.TargetDirectory "SyncLog_$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
  105.  
  106.                     # Ensure correct formatting for source and target paths
  107.                     $robocopyParams = @(
  108.                         $sourcePath,
  109.                         $device.TargetDirectory,
  110.                         "/E", "/COPY:DAT", "/R:3", "/W:5", "/LOG:$logPath",
  111.                         "/NP", "/V"
  112.                     )
  113.  
  114.                     Write-Host "  Starting sync with Robocopy..."
  115.                     try {
  116.                         & robocopy @robocopyParams | ForEach-Object { Write-Host $_ }
  117.                         if ($LASTEXITCODE -lt 8) {
  118.                             Write-Host "  Sync completed successfully (Exit Code: $LASTEXITCODE)"
  119.                         } else {
  120.                             Write-Host "  Sync completed with warnings (Exit Code: $LASTEXITCODE)"
  121.                         }
  122.                     } catch {
  123.                         Write-Host "  Sync failed: $_"
  124.                     }
  125.                 }
  126.                 else {
  127.                     Write-Host "  Source path not found!"
  128.                 }
  129.             }
  130.  
  131.         }
  132.     }
  133.     catch {
  134.         Write-Host "[CRITICAL ERROR] $_"
  135.     }
  136.     Write-Host "`n[SCAN COMPLETED]"
  137. }
  138.  
  139. # Event registration
  140. $null = Register-WmiEvent -Query @"
  141. SELECT * FROM __InstanceCreationEvent WITHIN 2
  142. WHERE TargetInstance ISA 'Win32_DiskDrive'
  143. AND TargetInstance.InterfaceType = 'USB'
  144. "@ -SourceIdentifier "USBInserted" -Action {
  145.     Write-Host "`n[EVENT TRIGGERED] Starting scan sequence..."
  146.     Scan-Devices -csvFile $global:csvPath
  147. }
  148.  
  149. # Monitoring loop
  150. Write-Host "Monitoring USB devices. Press 'S' to scan manually, 'Q' to quit."
  151.  
  152. try {
  153.     while ($true) {
  154.         if ([Console]::KeyAvailable) {
  155.             $key = [Console]::ReadKey($true).Key
  156.             if ($key -eq [ConsoleKey]::S) {
  157.                 Write-Host "`n[MANUAL SCAN]"
  158.                 Scan-Devices -csvFile $global:csvPath
  159.             }
  160.             elseif ($key -eq [ConsoleKey]::Q) {
  161.                 break
  162.             }
  163.         }
  164.         Start-Sleep -Milliseconds 100
  165.     }
  166. }
  167. finally {
  168.     Write-Host "Exiting..."
  169.     Get-EventSubscriber -SourceIdentifier "USBInserted" | Unregister-Event -ErrorAction SilentlyContinue
  170. }
  171.  
Add Comment
Please, Sign In to add comment