4
votes

In bash, I have a bunch of aliases that add parameters to existing programs/functions, for example:

alias grep='grep --color'

I know that's not the best analogy, but is there a simple way to do that in Powershell? It seems like Set-Alias doesn't let you specify parameters.

You can create an alias for a cmdlet, but you cannot create an alias for a command that consists of a cmdlet and its parameters.

They suggest creating a new cmdlet to do so, but I'd prefer to be able to pass additional parameters without having to hardcode all the allowed params in the new cmdlet (like New-ProxyCommand seems to require you to do). That way, I don't have to know when the proxied/aliased cmdlet params change and change that in my proxy cmdlet.

So what's the best solution for

  • Not statically duplicating the parameter definition for the aliased/proxied cmdlet. Let the original cmdlet do the validation or dynamically refer to it.
  • Use an alias/differently named cmdlet so you have to do something explicit to get the different behavior
  • Have the alias/new cmdlet pass values to existing parameters in the aliased/proxied cmdlet

Closest I can think of is something like the below, though syntax is probably wrong. Also seems like it wouldn't play the nicest with piping, but that can probably be worked around somehow.

& $proxiedcommand $additionaldefaultparams $rawparamsfromread-host

Or is there a way to use the things for proxy cmdlets to dynamically instantiate parameters like below?

function aliased-cmdlet
{
[CmdletBinding((Get-Command Original-Cmdlet)._cmdletBindingsettings_)]
Param(
(Get-Command Original-Cmdlet)._paramsettings_)
)

Original-Cmdlet -CustomDefault Value -Whatever Else
}
1
This example by Jeff Hicks or this walkthrough by Don Jones of proxied functions might help - BenH
You might want to consider writing a scriptlet (script function) that uses $myinvocation, specifically $myinvocation.line, and parsing it for any parameters that may have been supplied that you need to modify or override. See, for example, this MSDN page on "Getting ALL Your Parameters" - Jeff Zeitlin
@BenH, I updated my question a little. I think the proxy command comes close, but doesn't deal the with params becoming stale. It seems like the solution would be to get more meta and do the proxy cmdlet generation dynamically. Seems a little over-engineered and fragile for what I feel like should be a simple solution. - undefinedvariable

1 Answers

5
votes

If the only change you want to override is a default parameter value, there's already a built-in facility for that. Use the $PSDefaultParameterValues automatic variable:

PS C:\> ('a a a' |Select-String 'a').Matches.Count
1
PS C:\> $PSDefaultParameterValues['Select-String:AllMatches']=$true
PS C:\> ('a a a' |Select-String 'a').Matches.Count
3

If you want to override default parameter values in some instances, but not change the default behavior of the cmdlet, create a proxy command and set default values for the proxy command:

# Gather required info
$OriginalCommand = Get-Command Select-String
$NewCommandName = 'Select-AllMatches'
$Metadata = [System.Management.Automation.CommandMetadata]::new($OriginalCommand)

# Create proxy command
$ProxyString = [System.Management.Automation.ProxyCommand]::Create($Metadata)
New-Item -Path function:\ -Name $NewCommandName -Value $ProxyString

# Set default parameter values for proxy command
$PSDefaultParameterValues["$NewCommandName`:AllMatches"] = $true

Now the parameter default value is only overridden for Select-AllMatches:

PS C:\> ('a a a' |Select-String 'a').Matches.Count
1
PS C:\> ('a a a' |Select-AllMatches 'a').Matches.Count
3