Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- .SYNOPSIS
- Automates USB drive synchronization using CSV-defined mappings with event-driven monitoring.
- To install as a service, use the following commands:
- nssm install "AutomatedFlashDriveSync" "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "C:\Users\J2897\Code\PowerShell\DriveSync\AutomatedFlashDriveSync.ps1"
- nssm set "AutomatedFlashDriveSync" Description "Automates the synchronization of USB drives with specified directories using a CSV-defined mapping."
- .DESCRIPTION
- This script:
- 1. Runs as a service monitoring USB insertion events via WMI
- 2. Performs automatic/manual syncs using device mappings from DeviceMapping.csv
- 3. Uses Robocopy for file synchronization with detailed logging
- 4. Supports multiple partitions per device
- .OPERATION MODES
- - Automatic: Triggers on USB insertion (Win32_DiskDrive creation event)
- - Manual: Press 'S' to force sync, 'Q' to quit
- .SYNC FEATURES
- - Automatic drive letter detection
- - Path validation (source/target)
- - Logging with timestamps
- - Error handling with exit codes
- - Safe retries (R:3/W:5)
- .REQUIREMENTS
- - DeviceMapping.csv from mapping script (USB_Drive_Mapper_CSV.ps1)
- - Robocopy available in PATH
- - Admin privileges for WMI events
- .NOTES
- CSV must contain: DeviceID,SourceDirectory,TargetDirectory
- Safe exit code range: Robocopy codes < 8
- #>
- # Path to CSV file (global variable)
- $global:csvPath = "C:\Users\J2897\Code\PowerShell\DriveSync\DeviceMapping.csv"
- function global:Scan-Devices {
- param (
- [Parameter(Mandatory=$true)]
- [string]$csvFile
- )
- try {
- Write-Host "`n[SCAN STARTED] Loading CSV from: $csvFile"
- $devices = Import-Csv -Path $csvFile
- Write-Host "Loaded $($devices.Count) device mappings"
- # Wait for drive initialization
- Write-Host "Waiting 5 seconds for drive preparation..."
- 1..5 | ForEach-Object {
- Write-Host " - Second $_/5"
- Start-Sleep -Seconds 1
- }
- # Get fresh device lists
- $diskDrives = Get-WmiObject -Class Win32_DiskDrive | Where-Object { $_.PNPDeviceID -like "USBSTOR*" }
- Write-Host "Detected USB disk drives: $($diskDrives.Count)"
- foreach ($device in $devices) {
- $trimmedFriendlyName = $device.FriendlyName.Trim()
- Write-Host "`nProcessing device: $trimmedFriendlyName ($($device.DeviceID))"
- # Find matching disk drive
- $matchingDisk = $diskDrives | Where-Object { $_.PNPDeviceID -eq $device.DeviceID }
- if (-not $matchingDisk) {
- Write-Host " No matching disk found!"
- continue
- }
- Write-Host " Found matching disk: $($matchingDisk.Model)"
- # Get drive letters
- $driveLetters = $matchingDisk.GetRelated("Win32_DiskPartition") |
- ForEach-Object { $_.GetRelated("Win32_LogicalDisk") } |
- Select-Object -ExpandProperty DeviceID
- if (-not $driveLetters) {
- Write-Host " No drive letters found!"
- continue
- }
- Write-Host " Drive letters: $($driveLetters -join ', ')"
- foreach ($letter in $driveLetters) {
- # Ensure correct source path handling
- $sourcePath = if ($device.SourceDirectory -and $device.SourceDirectory.Trim() -ne "") {
- "$letter\$($device.SourceDirectory)"
- } else {
- "$letter\"
- }
- Write-Host "`n Attempting sync from: $sourcePath"
- if (Test-Path $sourcePath) {
- Write-Host " Source path verified - starting sync..."
- # Ensure the target directory exists
- if (-not (Test-Path $device.TargetDirectory)) {
- Write-Host " Target directory does not exist. Creating: $($device.TargetDirectory)"
- New-Item -ItemType Directory -Path $device.TargetDirectory -Force | Out-Null
- }
- $logPath = Join-Path $device.TargetDirectory "SyncLog_$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
- # Ensure correct formatting for source and target paths
- $robocopyParams = @(
- $sourcePath,
- $device.TargetDirectory,
- "/E", "/COPY:DAT", "/R:3", "/W:5", "/LOG:$logPath",
- "/NP", "/V"
- )
- Write-Host " Starting sync with Robocopy..."
- try {
- & robocopy @robocopyParams | ForEach-Object { Write-Host $_ }
- if ($LASTEXITCODE -lt 8) {
- Write-Host " Sync completed successfully (Exit Code: $LASTEXITCODE)"
- } else {
- Write-Host " Sync completed with warnings (Exit Code: $LASTEXITCODE)"
- }
- } catch {
- Write-Host " Sync failed: $_"
- }
- }
- else {
- Write-Host " Source path not found!"
- }
- }
- }
- }
- catch {
- Write-Host "[CRITICAL ERROR] $_"
- }
- Write-Host "`n[SCAN COMPLETED]"
- }
- # Event registration
- $null = Register-WmiEvent -Query @"
- SELECT * FROM __InstanceCreationEvent WITHIN 2
- WHERE TargetInstance ISA 'Win32_DiskDrive'
- AND TargetInstance.InterfaceType = 'USB'
- "@ -SourceIdentifier "USBInserted" -Action {
- Write-Host "`n[EVENT TRIGGERED] Starting scan sequence..."
- Scan-Devices -csvFile $global:csvPath
- }
- # Monitoring loop
- Write-Host "Monitoring USB devices. Press 'S' to scan manually, 'Q' to quit."
- try {
- while ($true) {
- if ([Console]::KeyAvailable) {
- $key = [Console]::ReadKey($true).Key
- if ($key -eq [ConsoleKey]::S) {
- Write-Host "`n[MANUAL SCAN]"
- Scan-Devices -csvFile $global:csvPath
- }
- elseif ($key -eq [ConsoleKey]::Q) {
- break
- }
- }
- Start-Sleep -Milliseconds 100
- }
- }
- finally {
- Write-Host "Exiting..."
- Get-EventSubscriber -SourceIdentifier "USBInserted" | Unregister-Event -ErrorAction SilentlyContinue
- }
Add Comment
Please, Sign In to add comment