lib/Junction.ps1
|
function Get-JunctionTarget { <# .SYNOPSIS Returns the target path of an existing junction or symlink, working on both Windows PowerShell 5.1 (uses .Target) and PowerShell 7+ (uses .LinkTarget). Returns $null when no target can be determined. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Path ) $item = Get-Item -Path $Path -Force -ErrorAction Stop foreach ($prop in 'LinkTarget', 'Target') { if ($item.PSObject.Properties[$prop]) { $value = $item.$prop if ($value) { if ($value -is [array]) { return [string]$value[0] } return [string]$value } } } return $null } function New-DevJunction { <# .SYNOPSIS Migrates a directory's contents to a target path and replaces the original location with an NTFS junction. Verifies that an existing junction points to the expected target before skipping. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(Mandatory)] [string] $LinkPath, [Parameter(Mandatory)] [string] $TargetPath, [Parameter(Mandatory)] [string] $Name ) if (-not (Test-Path -Path $TargetPath -PathType Container)) { if ($PSCmdlet.ShouldProcess($TargetPath, 'Create directory')) { New-Item -ItemType Directory -Path $TargetPath -Force | Out-Null } } if (Test-Path -Path $LinkPath) { $item = Get-Item -Path $LinkPath -Force if ($item.Attributes -match 'ReparsePoint') { $existingTarget = Get-JunctionTarget -Path $LinkPath $expected = $TargetPath.TrimEnd('\', '/') $actual = if ($existingTarget) { $existingTarget.TrimEnd('\', '/') } else { '<unknown>' } if ($actual -ieq $expected) { Write-Status -Level Info -Message " [INFO] $Name is already a junction to $TargetPath" } else { Write-Status -Level Warn -Message " [WARN] $Name is a junction to '$actual' (expected '$expected')." Write-Status -Level Warn -Message " Remove the existing junction manually or update `$Paths to match." } return } $children = @(Get-ChildItem -Path $LinkPath -Force) if ($children.Count -gt 0) { if ($PSCmdlet.ShouldProcess("$LinkPath -> $TargetPath", "Move $Name data")) { Write-Status -Level Info -Message " [INFO] Relocating $Name data to $TargetPath..." $children | Move-Item -Destination $TargetPath -Force } } if ($PSCmdlet.ShouldProcess($LinkPath, 'Remove (will be replaced with junction)')) { Remove-Item -Path $LinkPath -Recurse -Force } } else { Write-Status -Level Info -Message " [INFO] $LinkPath does not exist; creating junction directly." } if ($PSCmdlet.ShouldProcess("$LinkPath -> $TargetPath", 'Create junction')) { New-Item -ItemType Junction -Path $LinkPath -Value $TargetPath | Out-Null Write-Status -Level Info -Message " [INFO] Junction created: $LinkPath -> $TargetPath" } } |