4

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
}
3
  • 1
    This example by Jeff Hicks or this walkthrough by Don Jones of proxied functions might help Commented May 25, 2017 at 13:45
  • 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" Commented May 25, 2017 at 13:48
  • @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. Commented May 25, 2017 at 15:14

1 Answer 1

6

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
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for bringing that up. I think I might be able to use that for this specific use case I have in mind. The requirement to tie the parameter to a cmdlet name and have it set globally for a session seems a bit limiting though. That doesn't seem the most compatible if I wanted to have two alias that set different parameters or different values for the same parameter.
Also, it means I would require users to do something explicit to call the original cmdlet without the custom defaults. Which is why an alias is preferred, so that the default behavior for the original cmdlet is not changed.
@undefinedvariable sorry, the grep -> grep example made me think you just wanted to change the defaults. Updated answer
That's bit closer, but I still have to do that dynamically since otherwise the params generated by the commands would be a snapshot of that cmdlet. See my comment above.
@undefinedvariable What exactly do you mean by "dynamically"? Nothing stops you from wrapping the above in a simple function that takes as arguments the original command, the alias name and a hashtable representing the parameter values you want to override, that would basically give you the exact same functionality as bash's alias
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.