lib/Preflight.ps1
|
function Test-PathDriveAvailability { <# .SYNOPSIS Throws if any drive referenced in $Paths is not currently mounted. #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Collections.IDictionary] $Paths ) $drives = $Paths.Values | ForEach-Object { [System.IO.Path]::GetPathRoot($_) } | Sort-Object -Unique foreach ($drive in $drives) { if (-not (Test-Path -Path $drive -PathType Container)) { throw "Drive '$drive' (referenced in `$Paths) is not available. Mount it or update the `$Paths configuration." } } } function Test-AppRunning { <# .SYNOPSIS Returns $true when a process matching the given name is running. When PathHint is supplied, the process's MainModule.FileName must also contain that substring (case-insensitive) - used to disambiguate generic names like "Code" from unrelated apps such as CodeMeter. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $ProcessName, [string] $PathHint ) $procs = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue if (-not $procs) { return $false } if (-not $PathHint) { return $true } foreach ($proc in $procs) { try { if ($proc.MainModule.FileName -like "*$PathHint*") { return $true } } catch { # Get-Process can fail to read MainModule for cross-arch processes # (e.g. 64-bit process from 32-bit PowerShell) without elevation. # Fall back to assuming it counts so we err on the side of warning. return $true } } return $false } function Test-BlockingProcess { <# .SYNOPSIS Detects running applications that hold locks on cache or home directories and prompts the user to abort. Returns $true when it is safe (or the user chose) to proceed. #> [CmdletBinding()] param( [switch] $Force ) $checks = @( @{ Name = 'Docker Desktop'; Process = 'Docker Desktop' } @{ Name = 'Claude'; Process = 'claude' } @{ Name = 'Visual Studio'; Process = 'devenv' } @{ Name = 'Rider'; Process = 'rider64' } @{ Name = 'VS Code'; Process = 'Code'; PathHint = 'Microsoft VS Code' } ) $running = $checks | Where-Object { Test-AppRunning -ProcessName $_['Process'] -PathHint $_['PathHint'] } if (-not $running) { return $true } Write-Status -Level Warn -Message 'WARNING: The following applications are running and may lock files:' foreach ($r in $running) { Write-Status -Level Warn -Message " - $($r.Name)" } if ($Force) { Write-Status -Level Warn -Message ' -Force specified; continuing anyway.' return $true } # Skip the interactive prompt under -WhatIf; just surface the warning. if ($WhatIfPreference) { return $true } return $PSCmdlet.ShouldContinue( 'These applications may interfere with the migration. Continue anyway?', 'Running processes detected' ) } |