private/WinPEStartup/Set-WinPEStartupUSBDriveLetter.ps1
|
#requires -Version 5.1 function Set-WinPEStartupUSBDriveLetter { <# .SYNOPSIS Reassigns USB drive letters in WinPE starting at H. .DESCRIPTION Detects mounted USB partitions that currently have drive letters and reassigns them in deterministic order (DiskNumber, PartitionNumber) to the next available letters from H through Z. Used drive letters are discovered through .NET ([System.IO.DriveInfo]::GetDrives()) to improve reliability in WinPE. .EXAMPLE Set-WinPEStartupUSBDriveLetter Reassigns USB partition drive letters starting at H. .EXAMPLE Set-WinPEStartupUSBDriveLetter -Verbose Reassigns USB partition drive letters and writes detailed logs. .NOTES Author: David Segura Module: OSDCloud #> [CmdletBinding()] [OutputType([void])] param () $Error.Clear() if ($env:SystemDrive -ne 'X:') { Write-Warning 'Set-WinPEStartupUSBDriveLetter: Not running in WinPE (SystemDrive is not X:). Exiting.' return } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Start" $usbDisks = @(Get-Disk -ErrorAction SilentlyContinue | Where-Object { $_.BusType -eq 'USB' }) if (-not $usbDisks) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No USB disks detected" return } $usbPartitions = foreach ($usbDisk in $usbDisks) { Get-Partition -DiskNumber $usbDisk.Number -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter } } $usbPartitions = @($usbPartitions | Sort-Object -Property DiskNumber, PartitionNumber) if (-not $usbPartitions) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No USB partitions with drive letters detected" return } $usedLetters = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase) foreach ($drive in [System.IO.DriveInfo]::GetDrives()) { $driveLetter = $drive.Name.Substring(0, 1).ToUpperInvariant() [void]$usedLetters.Add($driveLetter) } foreach ($usbPartition in $usbPartitions) { $currentLetter = ([string]$usbPartition.DriveLetter).ToUpperInvariant() if (-not [string]::IsNullOrWhiteSpace($currentLetter)) { [void]$usedLetters.Remove($currentLetter) } } $candidateLetters = [char[]](72..90) $resultCount = 0 $failureCount = 0 foreach ($usbPartition in $usbPartitions) { $newLetter = $null foreach ($candidateLetter in $candidateLetters) { $candidate = ([string]$candidateLetter).ToUpperInvariant() if (-not $usedLetters.Contains($candidate)) { $newLetter = $candidate [void]$usedLetters.Add($candidate) break } } if (-not $newLetter) { Write-Warning "Set-WinPEStartupUSBDriveLetter: No available drive letters remain in the H-Z range for Disk $($usbPartition.DiskNumber) Partition $($usbPartition.PartitionNumber)." $failureCount += 1 continue } $oldLetter = ([string]$usbPartition.DriveLetter).ToUpperInvariant() if ($oldLetter -eq $newLetter) { Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Disk $($usbPartition.DiskNumber) Partition $($usbPartition.PartitionNumber) already using $newLetter" $resultCount += 1 continue } try { Write-Host -ForegroundColor DarkGray "[$(Get-Date -format s)] USB DriveLetter: $oldLetter -> $newLetter" Set-Partition -DiskNumber $usbPartition.DiskNumber -PartitionNumber $usbPartition.PartitionNumber -NewDriveLetter $newLetter -ErrorAction Stop $resultCount += 1 } catch { Write-Warning "Set-WinPEStartupUSBDriveLetter: Failed to reassign Disk $($usbPartition.DiskNumber) Partition $($usbPartition.PartitionNumber) from $oldLetter to $newLetter. $($_.Exception.Message)" $failureCount += 1 } } Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Complete (Success=$resultCount, Failed=$failureCount)" } |