我正在尝试重命名我的一些cmdlet,并希望在不破坏现有脚本的情况下执行此操作。我想在不使用Set-Alias / New-Alias的情况下这样做,因为当我们从powershell提示符执行Get-Command时我不希望显示别名,我认为可以使用导出的函数来实现相同的功能别名cmdlet会这样做。
这是我想要做的一个例子
Old cmdlet - Add-Foo
Renamed cmdlet - Add-FooBar
Expectation - Scripts using Add-Foo should continue to work the same way as it used to
我正在考虑引入以下功能
function Add-Foo()
{
# Delegate parameter inputs to cmdlet Add-FooBar
}
我有一个简单的版本,但我不确定它是否适用于更复杂的情况。
function Add-Foo()
{
$cmd = "Add-FooBar"
if ($arguments.Length -eq 0){
Invoke-Expression $cmd;
}
else{
# Concatentate cmdlet and arguments into an expression
$expr = "$($cmd) $($args)";
Write-Debug $expr;
Invoke-Expression $expr;
}
}
我不确定我的功能是否与现有用法100%兼容。可以使用Add-Foo函数使其在参数属性(管道绑定)和任何其他可能的用法中表现良好吗?基本上我希望函数按原样获取参数并将其传递给底层重命名的cmdlet。
感谢任何帮助。
由于
答案 0 :(得分:3)
PowerShell有一个内置功能:代理命令。
[System.Management.Automation.ProxyCommand]类有几个静态方法来帮助解决这个问题。下面是一个模板,您可以使用该模板生成代理命令并添加一个条件,选择是否调用原始命令。
function New-ProxyCommand($command)
{
$cmd = Get-Command $command
$blocks = @{
CmdletBinding = [System.Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($cmd)
Params = [System.Management.Automation.ProxyCommand]::GetParamBlock($cmd)
Begin = [System.Management.Automation.ProxyCommand]::GetBegin($cmd)
Process = [System.Management.Automation.ProxyCommand]::GetProcess($cmd)
End = [System.Management.Automation.ProxyCommand]::GetEnd($cmd)
}
# Indent
filter Indent($indent=' ') { $_ | foreach { ($_ -split "`r`n" | foreach { "${indent}$_" }) -join "`r`n" } }
[array]$blocks.Keys | foreach { $blocks[$_] = $blocks[$_] | Indent }
@"
function $command
{
$($blocks.CmdletBinding)
param
($($blocks.Params)
)
begin
{
`$Reroute = `$false ### Put your conditions here ###
if (`$Reroute) { return }
$($blocks.Begin)}
process
{
if (`$Reroute) { return }
$($blocks.Process)}
end
{
if (`$Reroute) { return }
$($blocks.End)}
}
"@
}
示例:
PS> New-ProxyCommand Get-Item
function Get-Item
{
[CmdletBinding(DefaultParameterSetName='Path', SupportsTransactions=$true, HelpUri='http://go.microsoft.com/fwlink/?LinkID=113319')]
param
(
[Parameter(ParameterSetName='Path', Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[string[]]
${Path},
[Parameter(ParameterSetName='LiteralPath', Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('PSPath')]
[string[]]
${LiteralPath},
[string]
${Filter},
[string[]]
${Include},
[string[]]
${Exclude},
[switch]
${Force},
[Parameter(ValueFromPipelineByPropertyName=$true)]
[pscredential]
[System.Management.Automation.CredentialAttribute()]
${Credential}
)
begin
{
$Reroute = $false ### Put your conditions here ###
if ($Reroute) { return }
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-Item', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
if ($Reroute) { return }
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
if ($Reroute) { return }
try {
$steppablePipeline.End()
} catch {
throw
}
}
}
答案 1 :(得分:0)
一种选择是使用私人功能:
function Private:Add-Foo
{
Add-Foobar $args
}
Add-Foo只会在当前范围内调用此函数。该函数在任何子作用域(如被调用的脚本)中都不可见,它们将使用Add-Foo cmdlet。