public/functions/New-PowerStubDirectAlias.ps1
|
<# .SYNOPSIS Creates a direct alias for a PowerStub stub. .DESCRIPTION Creates a PowerShell function that acts as a shortcut for a specific stub. Instead of typing 'pstb DevOps <command>', you can use a shorter alias like 'dv <command>'. The alias supports full tab completion for both command names and command parameters. .PARAMETER AliasName The name of the alias to create (e.g., 'dv' for DevOps). .PARAMETER Stub The name of the stub to create an alias for. .PARAMETER Force Overwrites the alias if it already exists. .EXAMPLE New-PowerStubDirectAlias -AliasName dv -Stub DevOps Creates an alias 'dv' for the DevOps stub. Now you can run: dv deploy -Environment prod Instead of: pstb DevOps deploy -Environment prod .EXAMPLE New-PowerStubDirectAlias -AliasName dv -Stub DevOps -Force Overwrites an existing 'dv' alias. .OUTPUTS PSCustomObject with alias information and usage instructions. #> function New-PowerStubDirectAlias { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidatePattern('^[a-zA-Z][a-zA-Z0-9_-]*$')] [string]$AliasName, [Parameter(Mandatory = $true)] [string]$Stub, [Parameter(Mandatory = $false)] [switch]$Force ) if (Test-PowerStubReservedName $AliasName) { throw "'$AliasName' is a reserved name and cannot be used as a direct alias." } Sync-PowerStubConfiguration # Verify stub exists $stubs = Get-PowerStubConfigurationKey 'Stubs' if (-not ($stubs.Keys -contains $Stub)) { throw "Stub '$Stub' not found. Register it first with New-PowerStub." } # Check if function already exists $wasOurAlias = $Script:RegisteredDirectAliases -contains $AliasName $existingCmd = Get-Command $AliasName -ErrorAction SilentlyContinue if ($existingCmd -and -not $Force) { throw "A command named '$AliasName' already exists. Use -Force to overwrite." } # Create the function in global scope using ScriptBlock instead of Invoke-Expression # Escape single quotes in stub name to prevent code injection $escapedStub = $Stub -replace "'", "''" # A simple function with no parameters, for the same reason as Invoke-PowerStubCommand: # nothing meant for the target may be bound here. @args forwards every argument untouched. $functionBody = @" if (`$args.Count -eq 0) { # List commands & (Get-Module PowerStub) { param(`$s) Find-PowerStubCommands `$s } '$escapedStub' return } Invoke-PowerStubCommand '$escapedStub' @args "@ # Create the function via ScriptBlock instead of Invoke-Expression $scriptBlock = [scriptblock]::Create($functionBody) Set-Item -Path "function:global:$AliasName" -Value $scriptBlock # Remember which global functions are ours so module removal only cleans up those if ($Script:RegisteredDirectAliases -notcontains $AliasName) { $Script:RegisteredDirectAliases += $AliasName } # Tab completion for the alias comes from the module's TabExpansion2 wrapper, # which recognizes every name in $Script:RegisteredDirectAliases. # Store in config for re-registration on module load. # If -Force was used to take a name that belongs to another command (for example a # 'devops.bat' on the PATH), remember that consent: module load re-creates such an alias, # but never lets a name that merely appears in the config file shadow a command. $shadowsOtherCommand = $Force -and $existingCmd -and -not $wasOurAlias $directAliases = Get-PowerStubConfigurationKey 'DirectAliases' $forcedAliases = @(Get-PowerStubConfigurationKey 'ForcedDirectAliases') $needsSave = -not $directAliases -or $directAliases[$AliasName] -ne $Stub -or ($shadowsOtherCommand -and $forcedAliases -notcontains $AliasName) if ($needsSave) { # Add only this alias so other sessions' aliases are kept Update-PowerStubConfiguration { if (-not $Script:PSTBSettings['DirectAliases']) { $Script:PSTBSettings['DirectAliases'] = @{} } $Script:PSTBSettings['DirectAliases'][$AliasName] = $Stub if ($shadowsOtherCommand) { $forced = @($Script:PSTBSettings['ForcedDirectAliases']) | Where-Object { $_ } if ($forced -notcontains $AliasName) { $Script:PSTBSettings['ForcedDirectAliases'] = @($forced) + $AliasName } } } } # Return info object $stubConfig = $stubs[$Stub] $stubPath = Get-PowerStubPath -StubConfig $stubConfig [PSCustomObject]@{ AliasName = $AliasName Stub = $Stub StubPath = $stubPath Usage = @" Alias '$AliasName' created for stub '$Stub'. Usage: $AliasName # List available commands $AliasName <command> # Run a command $AliasName <command> <Tab> # Tab complete command names $AliasName <command> -<Tab> # Tab complete command parameters To make persistent, add to your `$PROFILE: Import-Module PowerStub The alias is automatically recreated when the PowerStub module loads. "@ } } |