tools/Install-LocalPreview.ps1
|
<# .SYNOPSIS Install the staged GitEasy module to your user-scope PowerShell module folder so you can see what an Install-Module from PSGallery would look like - same versioned layout, same payload, including the PDFs. .DESCRIPTION Install-LocalPreview.ps1 runs the publish staging (tools\Publish- GitEasy.ps1, dry-run mode) to assemble exactly what the .nupkg would contain, then copies the staged folder to the user-scope module path under a versioned subfolder (the layout Install-Module uses): PS 7+ on Windows : $HOME\Documents\PowerShell\Modules\GitEasy\<ver>\ PS 5.1 : $HOME\Documents\WindowsPowerShell\Modules\GitEasy\<ver>\ After install you can: Import-Module GitEasy (Get-Module GitEasy).Path # see where it loaded from explorer (Get-Module GitEasy).ModuleBase # browse the installed copy To remove a preview later: Remove-Item -Recurse "$HOME\Documents\PowerShell\Modules\GitEasy\<ver>" This is NOT the same as tools\Install-GitEasy.ps1. That script installs the runtime essentials system-wide (Program Files, requires admin) and omits docs / Assets / PDFs. This script installs the FULL Gallery payload to user-scope so you can preview what consumers will see. .PARAMETER ProjectRoot Absolute path to the GitEasy source repository. Defaults to C:\Sysadmin\Scripts\GitEasy. .PARAMETER ModulesRoot Override the destination modules root. Defaults to the user-scope modules folder for the current PowerShell edition. .PARAMETER SkipTests Pass through to Publish-GitEasy.ps1 - skip the Pester gate. Useful when you just verified the suite and don't want to rerun. .PARAMETER Force Overwrite an existing install at the same version path without backup. By default, an existing same-version folder is renamed to <path>.bak.<timestamp> before the new copy lands. .EXAMPLE .\tools\Install-LocalPreview.ps1 Default - stage with the full Pester gate, copy to your user-scope versioned module path, verify Import-Module GitEasy loads the new install. .EXAMPLE .\tools\Install-LocalPreview.ps1 -SkipTests Skip the Pester gate (faster iteration). Use only if you have just run Pester yourself. .NOTES The versioned subfolder layout (...\GitEasy\1.5.3\GitEasy.psd1) is what Install-Module produces. PowerShell's loader picks the highest available version across all paths on $env:PSModulePath, so a 1.5.3 user-scope install will win over any older copy on the machine - including a stale 1.4.2 in Program Files. #> [CmdletBinding()] param( [string] $ProjectRoot = 'C:\Sysadmin\Scripts\GitEasy', [string] $ModulesRoot, [switch] $SkipTests, [switch] $Force ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' Write-Host '' Write-Host 'STATE CHECK: Install GitEasy local preview' -ForegroundColor Cyan if (-not (Test-Path -LiteralPath $ProjectRoot -PathType Container)) { throw "Missing project folder: $ProjectRoot" } # Resolve the modules root for the current PowerShell edition. Naively # constructing $HOME\Documents\PowerShell\Modules misses the case where # Documents is redirected through OneDrive (Microsoft's default on many # managed Windows installs) - the real user-scope path then lives under # $env:USERPROFILE\OneDrive\... and is the entry PS actually uses. # Discover it from $env:PSModulePath instead of constructing it. if (-not $ModulesRoot) { $userScope = ($env:PSModulePath -split [System.IO.Path]::PathSeparator) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Container -ErrorAction SilentlyContinue) -and ($_ -like "$env:USERPROFILE\*") -and ($_ -notlike "*\Program Files\*") } | Select-Object -First 1 if (-not $userScope) { # Fall back to the convention if PSModulePath has nothing under $USERPROFILE. $editionFolder = if ($PSVersionTable.PSEdition -eq 'Core') { 'PowerShell' } else { 'WindowsPowerShell' } $userScope = Join-Path $HOME "Documents\$editionFolder\Modules" Write-Warning "No user-scope path on `$env:PSModulePath - falling back to $userScope (may not be auto-loaded)." } $ModulesRoot = $userScope } # Read manifest version $manifest = Test-ModuleManifest -Path (Join-Path $ProjectRoot 'GitEasy.psd1') -ErrorAction Stop $version = $manifest.Version.ToString() Write-Host "Project root : $ProjectRoot" Write-Host "Module version: $version" Write-Host "Modules root : $ModulesRoot" Write-Host "Edition : PowerShell $($PSVersionTable.PSEdition) $($PSVersionTable.PSVersion)" Write-Host '' # Step 1 - run the publish staging $publisher = Join-Path $ProjectRoot 'tools\Publish-GitEasy.ps1' if (-not (Test-Path -LiteralPath $publisher)) { throw "Missing publisher script: $publisher" } $pubArgs = @{ SkipNetworkChecks = $true # local preview, no need to probe PSGallery URIs } if ($SkipTests) { $pubArgs.SkipTests = $true } Write-Host '==> Staging via Publish-GitEasy.ps1 (dry run)...' -ForegroundColor Cyan & $publisher @pubArgs | Out-Null if ($LASTEXITCODE -ne 0) { throw "Staging failed (exit $LASTEXITCODE). Run .\tools\Publish-GitEasy.ps1 directly to see the error." } # Stage location is deterministic: $env:TEMP\GitEasy-publish-stage-<version>\GitEasy $stagePath = Join-Path $env:TEMP "GitEasy-publish-stage-$version\GitEasy" if (-not (Test-Path -LiteralPath $stagePath -PathType Container)) { throw "Expected staged folder not found at $stagePath. Did the publisher run cleanly?" } # Step 2 - resolve target versioned path $installBase = Join-Path $ModulesRoot 'GitEasy' $targetPath = Join-Path $installBase $version if (-not (Test-Path -LiteralPath $ModulesRoot -PathType Container)) { New-Item -ItemType Directory -Path $ModulesRoot -Force | Out-Null } # Step 3 - handle existing install at the same version if (Test-Path -LiteralPath $targetPath -PathType Container) { if ($Force) { Remove-Item -Recurse -Force $targetPath Write-Host "Cleared prior install at $targetPath" -ForegroundColor DarkGray } else { $stamp = (Get-Date).ToString('yyyyMMddHHmmss') $backup = "$targetPath.bak.$stamp" Rename-Item -LiteralPath $targetPath -NewName (Split-Path -Leaf $backup) -Force Write-Host "Backed up prior install -> $backup" -ForegroundColor DarkGray } } # Step 4 - copy Write-Host "==> Copying staged folder to $targetPath" -ForegroundColor Cyan New-Item -ItemType Directory -Path $targetPath -Force | Out-Null Copy-Item -Path (Join-Path $stagePath '*') -Destination $targetPath -Recurse -Force # Step 5 - verify via Get-Module -ListAvailable in the CURRENT edition's # session. Shelling out to powershell.exe (PS 5.1) would only see the # WindowsPowerShell\Modules paths and miss a PS 7 user-scope install. Write-Host '==> Verifying install...' -ForegroundColor Cyan $available = @(Get-Module GitEasy -ListAvailable | Sort-Object Version -Descending) $found = $available | Select-Object -First 1 if (-not $found) { Write-Warning " Get-Module -ListAvailable found no GitEasy. The freshly-installed path may not be on `$env:PSModulePath in this session." } elseif ([string]$found.Version -eq $version -and $found.ModuleBase -like "$targetPath*") { Write-Host " OK PowerShell loader picks $($found.Version) from $($found.ModuleBase)" -ForegroundColor Green } else { Write-Warning " Loader picks $($found.Version) from $($found.ModuleBase) - your fresh install may be shadowed by another copy." } # Report ALL available copies so the user can see any conflicts if ($available.Count -gt 1) { Write-Host '' Write-Host ' All GitEasy copies visible to this edition:' -ForegroundColor DarkGray foreach ($m in $available) { $marker = if ($m.ModuleBase -like "$targetPath*") { '<- fresh install' } else { '' } Write-Host (" {0,-8} {1} {2}" -f $m.Version, $m.ModuleBase, $marker) -ForegroundColor DarkGray } } # Step 6 - report what landed $installed = Get-ChildItem -Path $targetPath -Recurse -File Write-Host '' Write-Host "Installed GitEasy $version" -ForegroundColor Green Write-Host (" Path : $targetPath") Write-Host (" Files: {0} ({1:N1} KB)" -f $installed.Count, (($installed | Measure-Object Length -Sum).Sum / 1KB)) Write-Host '' Write-Host 'Try it now:' -ForegroundColor Cyan Write-Host ' Import-Module GitEasy' Write-Host ' Get-Command -Module GitEasy' Write-Host ' (Get-Module GitEasy).Path' Write-Host " explorer '$targetPath'" Write-Host '' Write-Host 'To remove this preview install later:' -ForegroundColor DarkGray Write-Host " Remove-Item -Recurse '$targetPath'" |