I'm finding that I am repeating myself in powershell scripts in some cases where execution context matters. Delayed string expansion is one such case:
$MyString = 'The $animal says $sound.'
function MakeNoise{
param($animal, $sound)
$ExecutionContext.InvokeCommand.ExpandString($MyString)
}
PS> MakeNoise pig oink
The pig says oink.
That long ExpandString()
line gets repeated frequently. I'd prefer that line to be terse like this:
xs($MyString)
xs $MyString
$MyString | xs
Any of these would be preferable. My usual strategies of encapsulation in commandlets don't seem to work for this case because the context of the call to ExpandString()
is critical.
So my questions are:
- Is there a way to create an alias for an object method?
- Is there some other way call an object's method in a terse manner while preserving the context of the call?
It seems you need a way to delay evaluating $ExecutionContext until it's time to actually do the string expansion. Here's one way to do that, implemented as a function:
function xs
{
[CmdletBinding()]
param
(
[parameter(ValueFromPipeline=$true,
Position=0,
Mandatory=$true)]
[string]
$string
)
process
{
$code = "`$ExecutionContext.InvokeCommand.ExpandString(`"$string`")"
[scriptblock]::create($code)
}
}
Then:
&($MyString | xs)
&(xs $MyString)
The scriptblock is created at runtime, so $ExecutionContext is evaluated for each invocation.
You could just make your own function for this
function xs{
param(
[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
[string]$expand)
$ExecutionContext.InvokeCommand.ExpandString($expand)
}
function MakeNoise{
param($animal, $sound)
$MyString = 'The $animal says $sound.'
xs $MyString
# $MyString | xs <-- would also work
}
MakeNoise pig oink
Look at the cmdlet New-Alias - https://technet.microsoft.com/en-us/library/hh849959.aspx