Private/IWAPG-Hlp-Setup.ps1
|
function Get-RelativePath { <# .SYNOPSIS Returns a relative Windows path from BasePath to TargetPath when possible; otherwise returns the absolute, normalized TargetPath. .DESCRIPTION - Normalizes base and target paths via [System.IO.Path]::GetFullPath. - If paths are on different roots (drive letters or UNC shares), falls back to absolute. - Uses Uri.MakeRelativeUri to compute the relative portion. - Decodes URL-encoded characters and converts forward slashes to backslashes. .PARAMETER BasePath The base directory you want to compute the relative path from. .PARAMETER TargetPath The file or directory path you want to compute the relative path to. .OUTPUTS [string] Relative path if computable, otherwise absolute normalized TargetPath. #> [CmdletBinding()] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$BasePath, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$TargetPath ) try { # Normalize and ensure BasePath ends with a directory separator so Uri treats it as a folder $baseFull = [System.IO.Path]::GetFullPath(($BasePath.TrimEnd('\') + '\')) $targetFull = [System.IO.Path]::GetFullPath($TargetPath) # If roots differ (e.g., C:\ vs D:\ or different UNC shares), relative path is not possible $baseRoot = [System.IO.Path]::GetPathRoot($baseFull) $targetRoot = [System.IO.Path]::GetPathRoot($targetFull) if (-not [string]::Equals($baseRoot, $targetRoot, [System.StringComparison]::OrdinalIgnoreCase)) { return $targetFull } # Compute the relative URI and convert it to a Windows path $uriBase = [Uri]$baseFull $uriTarget = [Uri]$targetFull $rel = $uriBase.MakeRelativeUri($uriTarget).ToString() # Decode URL-encoded chars (e.g., spaces) and switch to backslashes $relWin = [Uri]::UnescapeDataString($rel).Replace('/', '\') return $relWin } catch { # On any unexpected error, just return the original target (best-effort behavior) return $TargetPath } } function Set-SetupFromSource { <# .SYNOPSIS Suggests the setup file and (optionally) proposes the final package name from a given source folder. .DESCRIPTION - Recursively searches for 'Invoke-AppDeployToolkit.exe' under SourcePath. - If found, populates SetupFileControl with a relative path (via Get-RelativePath) when the exe resides under SourcePath. - Does not overwrite SetupFileControl if it already points to an existing file (absolute or relative to SourcePath). - If 'Invoke-AppDeployToolkit.ps1' exists in the same folder, extracts AppName/AppVersion and sets FinalFilenameControl.Text: * 'AppName_Version' when both are present; * 'AppName' when AppVersion is missing/empty. Filename is sanitized (spaces removed, invalid filename chars replaced with '-'). - Parsing/IO errors are swallowed. .PARAMETER SourcePath The source directory to inspect. Must exist. .PARAMETER SetupFileControl The TextBox to populate with the suggested setup path (relative when possible). .PARAMETER FinalFilenameControl The TextBox to populate with the proposed final filename (e.g., 'AppName_Version' or 'AppName'). .OUTPUTS None. Mutates the provided TextBox controls. .EXAMPLE Set-SetupFromSource -SourcePath $SourceFolder.Text -SetupFileControl $SetupFile -FinalFilenameControl $FinalFilename #> [CmdletBinding()] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$SourcePath, [Parameter(Mandatory)][ValidateNotNull()][System.Windows.Controls.TextBox]$SetupFileControl, [Parameter(Mandatory)][ValidateNotNull()][System.Windows.Controls.TextBox]$FinalFilenameControl ) if (-not (Test-Path $SourcePath)) { return } # If current SetupFile value already points to an existing file (absolute or relative to source), do not override. $current = $SetupFileControl.Text.Trim() if ($current) { if (Test-Path $current) { return } $maybeRelative = Join-Path $SourcePath $current if (Test-Path $maybeRelative) { return } } # Search for Invoke-AppDeployToolkit.exe $exeHit = Get-ChildItem -Path $SourcePath -Filter 'Invoke-AppDeployToolkit.exe' -File -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 if ($exeHit) { # Prefer a relative path when the file is inside the source folder $SetupFileControl.Text = Get-RelativePath -BasePath $SourcePath -TargetPath $exeHit.FullName # If FinalFilenameControl already has a value, don't override user's input. $finalCurrent = $FinalFilenameControl.Text.Trim() if (-not $finalCurrent) { # Look for Invoke-AppDeployToolkit.ps1 in the same folder $ps1Path = Join-Path $exeHit.Directory.FullName 'Invoke-AppDeployToolkit.ps1' if (Test-Path $ps1Path) { try { $content = Get-Content $ps1Path -Raw # Support both single and double quotes: AppName = 'X' or AppName = "X" $appName = $null $appVersion = $null if ($content -match '(?m)AppName\s*=\s*[''"]([^''"]+)[''"]') { $appName = $matches[1] } if ($content -match '(?m)AppVersion\s*=\s*[''"]([^''"]*)[''"]') { $appVersion = $matches[1] } # Sanitize function: remove spaces, replace invalid filename chars with '-' function _Sanitize([string]$s) { if ([string]::IsNullOrWhiteSpace($s)) { return $null } $noSpaces = ($s -replace '\s+', '') return ($noSpaces -replace '[\\/:*?"<>|]', '-') } $cleanName = _Sanitize $appName $cleanVer = _Sanitize $appVersion # Build proposed filename: # - If both present: "Name_Version" # - If version missing/empty but name present: "Name" if ($cleanName) { $parts = @($cleanName) if ($cleanVer) { $parts += $cleanVer } $FinalFilenameControl.Text = ($parts -join '_') } # else: do nothing when AppName is missing } catch { # fail silently } } } } } |