Write-CommandOverload.ps1
function Write-CommandOverload { <# .Synopsis Writes a command overload. .Description This creates a command that runs another command. It can optionally drop some parameters, or create new ones. .Example #> param( [Parameter(Mandatory=$true,ParameterSetName='CommandMetaData')] [Management.Automation.CommandMetaData] $Command, #|Options Get-Command | ForEach-Object { ($_.ModuleName + $_.PSSnapinName + "\" + $_.Name).TrimStart("\") } [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true, ParameterSetName='CommandName')] [string] $CommandName, # The module the loaded command is in [Parameter(Position=1, ValueFromPipelineByPropertyName=$true, ParameterSetName='CommandName')] [Alias('ModuleName', 'PSSnapinName')] [string] $Module, # Any additional parameters to add to the command. [Parameter(ValueFromPipelineByPropertyName=$true)] [Management.Automation.ParameterMetaData[]] $AdditionalParameter, # Any parameters to remove from the command. [Parameter(ValueFromPipelineByPropertyName=$true)] [string[]] $RemoveParameter, # The new type name [string] $NewTypeName, # The script to be run when each item is processed [ScriptBlock] $ProcessEachItem, # The name of the item [string] $Name, # The default value [Hashtable] $DefaultValue ) process { if ($psCmdlet.ParameterSetName -eq 'CommandName') { $nestedParams = @{} + $psBoundParameters $psBoundParameters.Name = $psBoundParameters.CommandName $null = $nestedParams.Remove('Module'), $nestedParams.Remove('CommandName'), $psBoundParameters.Remove('CommandName'), $psBoundParameters.Remove('DefaultValue'), $psBoundParameters.Remove('ProcessEachItem') $resolvedCommand = Get-Command @psboundParameters if (-not $resolvedCommand) { return } & $myInvocation.MyCommand -Command $resolvedCommand @nestedParams } elseif ($psCmdlet.ParameterSetName -eq 'CommandMetaData') { $MetaData = New-Object Management.Automation.CommandMetaData $Command foreach ($rp in $removeParameter) { if (-not $rp) { continue } $null = $MetaData.Parameters.Remove($rp) } foreach ($ap in $additionalParameter) { if (-not $ap) { continue } $null = $MetaData.Parameters.Add($ap.Name, $ap) } $beginBlock = if ($NewTypeName -or $ProcessEachItem){ [Management.Automation.ProxyCommand]::GetBegin($metaData) -replace '\.Begin\(\$PSCmdlet\)', '.Begin($false)' } else { [Management.Automation.ProxyCommand]::GetBegin($metaData) } if (-not $Name) { $Name = $command.Name } if ($DefaultValue) { $defaultValueText = Write-Hashtable $DefaultValue $beginBlock = $beginBlock -replace '\$outBuffer = \$null', ('$outBuffer = $null ' + $defaultValueText) } # Indent the block of code. Yes, this is neurotic. $beginBlock = $beginBlock -split ([Environment]::NewLine) -ne "" | ForEach-Object { " " * 4 + $_ + [Environment]::NewLine} $endBlock = [Management.Automation.ProxyCommand]::GetEnd($metaData) -split ([Environment]::NewLine) -ne "" | ForEach-Object { " " * 4 + $_ + [Environment]::NewLine} $paramBlock = "$([Management.Automation.ProxyCommand]::GetParamBlock($metaData))" -replace '(\$)\{(\w.+)\}', '$1$2' $ProcessBlock = if ($ProcessEachItem){ " try { `$steppablePipeline.Process(`$_) | ForEach-Object { $ProcessEachItem } } catch { throw } " } elseif ($NewTypeName) { " try { `$steppablePipeline.Process(`$_) | ForEach-Object { `$_.pstypenames.clear() `$_.pstypenames.add('$NewTypeName') `$_ } } catch { throw } " } else { [Management.Automation.ProxyCommand]::GetProcess($metaData) } $ProcessBlock = $ProcessBlock -split ([Environment]::NewLine) -ne "" | ForEach-Object { " " * 4 + $_ + [Environment]::NewLine} "function ${Name} { $([Management.Automation.ProxyCommand]::GetCmdletBindingAttribute($MetaData)) param( $paramBlock ) begin { $BeginBlock } process { $ProcessBlock } end { $EndBlock } } " } } } |