Now that I’ve been using PowerShell extensively for almost a year, I frequently discover opportunities for core cmdlets to provide a richer experience than they do out of the box. Since PowerShell is a scripting language there are many ways to take advantage of these opportunities including writing new cmdlets, adding type data or format data for specific object types, writing specialized functions, etc. Sometimes though, all I want to do is extend an existing cmdlet as is while adhering to the following rules:
- It improves on the functionality of the original version.
- It can be used interchangeably in place of the original cmdlet in any script with no modification required and no loss of functionality.
I just finished the first revision of a helper function that is required if you want to extend existing cmdlets in this way. This helper function allows me to invoke the original cmdlet that I am modifying with the same parameters that my override received. It’s called Invoke-Cmdlet, and its purpose is simple: retrieve all cmdlets from all loaded snapins that have a specific name and from those determine which one should be executed by following Microsoft’s name resolution rules as closely as possible. In this particular function, the logic is simply to invoke the core cmdlet if there is a core cmdlet that has the same name; otherwise, the first non-core cmdlet that has the same name will be invoked. Here is the PowerShell script defining the function:
Function Invoke-Cmdlet {
param([string]$cmdletName = $(throw “Cannot bind argument to parameter ‘CmdletName’ because it is empty.”))
$matchingCmdlets = Microsoft.PowerShell.Core\Get-Command -CommandType cmdlet -Name $cmdletName
if (@($matchingCmdlets).Count -eq 0) {
throw “The term ‘$cmdletName’ is not recognized as a cmdlet. Verify the term and try again.”
} $cmdletName = $null
foreach ($cmdlet in $matchingCmdlets) {
if ($cmdlet.PSSnapin.IsDefault) {
$cmdletName = “$($cmdlet.PSSnapin.Name)\$($cmdlet.Name)”
break
} elseif (-not $cmdletName) {
$cmdletName = “$($cmdlet.PSSnapin.Name)\$($cmdlet.Name)”
}
}
Invoke-Expression “$cmdletName $($passThruArgs = $args; for ($i = 0; $i -lt $passThruArgs.Count; $i++) { if ($passThruArgs[$i] -match ‘^-‘) { $passThruArgs[$i] } else { `”`$passThruArgs[$i]`” } }) | Write-Output”
}
Now that this function is written, what is an example where you could use this to extend a cmdlet while following the rules outlined above? Right here.
Kirk out.
Technorati Tags: PowerShell, PoSh, Poshoholic
Add to: | Technorati | Digg | del.icio.us | Yahoo | BlinkList | Spurl | reddit | Furl |