Self Aliased Functions in PowerShell

When we are working with an interactive shell, we use aliases for the frequently used cmdlets, and aliases are really useful and reduce the amount of keystrokes, and very simple and easy to use, and sometimes they can do magics  as well. It is not recommended to use the aliases in the scripts and functions as part of the best practices. We can create aliases to cmdlets and functions, end even to scripts using the New-Alias cmdlet… New-Alias -Name hello -Value Hello-Word And, we can also create aliases to the function at the time of declaration itself using [Alias("")] statement, we need to place it just before the parameters block param. Parameters block is mandatory, at least an empty block param() Function Hello-World { [Alias('hello','hey')] param ( [string] $Name ) Write-Host "Hello, $Name!" }

Magic of $MyInvocation in PowerShell

Do you know that we can convert a predominant parameter value into a true command? Yes, to test the connectivity of a server we usually use Test-Connection -ComputerName ServerName, but how about using the ServerName -Ping? I know what you are thinking, what if there are hundreds or thousands of servers, do we need to create those many functions? No, just only one function with the help of $MyInvocation automatic variable. What is $MyInvocation? $MyInvocation is an automatic variable which contains information about the invocation details of the current execution, such as function or script name, parameters, parameter values, script root, script path, invocation name and etc., and $MyInvocation works with scripts, functions, and script blocks only. In action I will take the same ping example and show you that in action. I will write a small function to check the ping status with the name MyInvCmd and of course the name doesn’t matter and I will never use it or I can’t use it anywhere with that name, and here’s my function… Function MyInvCmd { $ServerName = $MyInvocation.InvocationName Test-Connection -TargetName $ServerName -IPv4 # In PowerShell 7 } Now, if I load this function and call it in the console, then it will throw me an error like this… MyInvCmd error But, as I said earlier I will never use this function with this name, so I will create an alias for this function with my server name. First to test this out in my local machine I will create an alias with localhost name… New-Alias -Name localhost -Value MyInvCmd That’s all, now load the MyInvCmd function and call with the alias name localhost in the console, and see the magic. You will see the ping results of the localhost as below… localhost example So, if you take a look at the function, $MyInvocation returns the output as below and the value of the InvocationName will be localhost, the actual function name is MyInvCmd though since it is being invoked by the alias name localhost, the value of the InvocationName is localhost and assigned it to $ServerName, and the same is used with -TargetName parameter in the Test-Connection cmdlet. MyCommand : MyInvCmd BoundParameters : {} UnboundArguments : {} ScriptLineNumber : 1 OffsetInLine : 1 HistoryId : 4 ScriptName : Line : localhost PositionMessage : At line:1 char:1 + localhost + ~~~~~~~~~ PSScriptRoot : PSCommandPath : InvocationName : localhost PipelineLength : 1 PipelinePosition : 1 ExpectingInput : False CommandOrigin : Runspace DisplayScriptPosition : So, whatever the alias name that you create for MyInvCmd will be used in the function as a server name, so what I will do is I will get the list of servers and create aliases with all of them. $FilePath = "C:\Inventory\Servers.txt" Get-Content -Path $FilePath | Foreach-Object { New-Alias -Name $_ -Value MyInvCmd } Now, all the server names are aliases to MyInvCmd but every alias invocation is unique and the function will work using the aliased server name. This time I will add more functionality and parameters as well, so that we can change the behavior on every execution. Besides ping functionality, I will add the functionality to get the server info, enter into PSSession, RDP session, and still you can continue to add… function MyInvCmd { <# .SYNOPSIS Replace MyInvCmd with the aliased server name #> [CmdLetBinding(DefaultParameterSetName = 'Help')] param ( [Parameter(Mandatory = $false)] [switch] $Ping, [Parameter(Mandatory = $false)] [switch] $ServerInfo, [Parameter(Mandatory = $false, ParameterSetName = 'PSSession')] [switch] $PSSession, [Parameter(Mandatory = $false, ParameterSetName = 'RDP')] [switch] $RDP ) $ServerName = $MyInvocation.InvocationName if ($Ping) { Test-Connection -TargetName $ServerName -IPv4 } # In PS7 if ($ServerInfo) { $OSInfo = Get-CimInstance -ClassName CIM_OperatingSystem -ComputerName $ServerName $CSInfo = Get-CimInstance -ClassName CIM_ComputerSystem -ComputerName $ServerName [PSCustomObject]@{ OperatingSystem = $OSInfo.Caption TotalMemory = $CSInfo.TotalPhysicalMemory FreeMemory = $OSInfo.FreePhysicalMemory NoOfCPUs = $CSInfo.NumberOfProcessors NoOfLogicalCPUs = $CSInfo.NumberOfLogicalProcessors LastRebootTime = $OSInfo.LastBootUpTime } } if ($PSSession) { Enter-PSSession -ComputerName $ServerName } if ($RDP) { Start-Process -FilePath mstsc.exe -ArgumentList /v:$ServerName } if ($MyInvocation.BoundParameters.Count -eq 0) { Get-Help -Name $ServerName } } And now, I will get my list of servers and add them as aliases to this function. Since I am running this demo in my lab which is running in Hyper-V, I will get all the VM Names and add them as aliases… Get-VM | ForEach-Object { New-Alias -Name $_.Name -Value MyInvCmd } And here’s the list of aliases that I have created for MyInvCmd, and if you notice all the server names are pointing to the MyInvCmd itself. aliases list Now, let’s see how to use these aliases, you can use the server name as command and pass the parameters to it. aliases in action What I like the most in this concept is I can use this pretty much for anything, not only the servers but also I can convert my request numbers, incidents and etc., and you can add lot more functionality at your convince.

Get All The aliases By CmdLet

You can get the alias by name using Get-Alias with -Name parameter… Get-Alias -Name gci To get all the aliases of a CmdLet, use Get-Alias with -Definition parameter… Get-Alias -Definition Get-ChildItem