Last Update: Sep 04, 2024 | Published: May 22, 2015
Efficiency is paramount when working with the PowerShell console to get work done. Because there’s a lot of typing involved when working with PowerShell, there’s several features that intend to limit typing, such as tab completion for command and parameter names. Another ease-of-use feature is the PowerShell alias. Instead of typing Get-WmiObject, you can type a shortcut, gwmi. There’s nothing wrong with that. When it comes time to writing a script, however, the best practice is to use full cmdlet and parameter names. Another use of aliases is as transition-aids, which is demonstrated by using dir instead of having to use Get-ChildItem.
PowerShell automatically defines many aliases whenever you start a new session. You can also create your own aliases. You might do this for your own functions or even command-line tools. In my PowerShell profile, I have a command like this:
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>Set-alias –name np –value notepad.exe
At any time, I can type np and Notepad will launch. My PowerShell profile has grown over the years, and it has been moved around as I have changed computers. Recently I realized I had some aliases that were pointing to items that no longer existed. It doesn’t really matter if you have orphaned aliases, but I like things neat, so I decided that I needed a tool to test if an alias was still valid. I can use the Get-Alias cmdlet to get details.
As I expected np leads to notepad.exe. Let’s peak behind the curtain and see if there is anything else I can use.
Excellent. The definition property gives me the complete command. This is important because I can use Get-Command to verify it.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>$a = Get-alias np
get-command -Name $a.Definition
That looks good and should mean that notepad.exe exists. But let’s test with something that I now will fail. I’ll create an alias that points to a non-existent command.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>set-alias -name foo -value c:windowssystem32foobar.exe
PowerShell will happily create the alias.
But let’s test for the backing command.
I get an exception. That is useful, because now I know I can use a try-catch statement.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>Try { $c = Get-Command $b.Definition -erroraction Stop;$True} Catch { $false}
This is a quick and dirty proof of concept.
Now I have something that I can wrap into a function to test an alias. Here’s my finished Test-Alias command.
#requires -version 4.0 Function Test-Alias { <# .Synopsis Test if an alias is valid. .Description Use this command to verify that an alias is pointing to a command that still exists. Use -Quiet to get only a True/False result. NOTE: Using this command will have a side-effect of importing associated modules. If the alias points to a command in a PSSnapin, you will get an incorrect result unless you add the PSSnapin first. .Parameter Name The alias name. You can pipe Get-Alias to this command. .Parameter Quiet Only display True or False. .Example PS C:> test-alias gsv,ps,foo,np | format-table -AutoSize Name Definition Test ---- ---------- ---- gsv Get-Service True ps Get-Process True foo x False np C:windowsnotepad.exe True .Example PS C:> get-alias | test-alias | where {! $_.Test} | format-table -AutoSize Name Definition Test ---- ---------- ---- chr C:UsersJeffAppDataLocalGoogleChromeApplicationchrome.exe False foo x False pe G:sysinternalsprocexp.exe False TryMe Get-Foo False Find aliases that won't work. .Example PS C:> test-alias gci -quiet True A simple boolean test .Notes Last Updated: 4/2/2015 Version : 1.0 Learn more about PowerShell:Essential PowerShell Learning Resources**************************************************************** * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * **************************************************************** .Link Get-Alias Get-Command .Inputs [string] .Outputs [Boolean] [PSCustomObject] #> [cmdletbinding()] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the name of an alias", ValueFromPipeline,ValueFromPipelineByPropertyName)] [ValidateNotNullorEmpty()] [string[]]$Name, [switch]$Quiet ) Begin { Write-Verbose "Starting $($MyInvocation.Mycommand)" } #begin Process { foreach ($alias in $Name) { Write-Verbose "Testing alias : $alias" Try { $def = (Get-Alias -Name $alias -ErrorAction Stop).Definition } Catch { Write-Warning "No alias found called $alias" } if ($def) { Try { Write-Verbose "Verifying command: $def" if (Get-Command -Name $def -erroraction Stop) { $tested = $True } } Catch { $tested = $False } if ($Quiet) { Write $tested } else { #write a custom object to the pipeline [pscustomobject]@{ Name = $alias Definition = $def Test = $Tested } } #clear $def so it doesn't get accidentally re-used Remove-Variable -Name Def } #if $def } #foreach } #process End { Write-Verbose "Ending $($MyInvocation.Mycommand)" } #end } #end Test-Alias #create an alias Set-Alias -Name ta -Value Test-Alias
You can test an alias by name.
Or you can pipe names to it.
The default behavior is to write a custom object to the pipeline, but I also thought there might be a time when you want to test and need a simple Boolean result. Test-Connection works the same way.
If you were scripting with my function, then this means you could write a simple if statement like this:
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>If (test-alias ls) {
#found
}
But I don’t need a script to validate all of my aliases. I can do it from the console.
pre class=”EnlighterJSRAW” data-enlighter-language=”generic”>get-alias | test-alias | where {-Not $_.Test} | format-table –AutoSize
Now I know what to clean up. Although I can’t tell where these aliases were defined, if you want to test aliases defined in your profile, start a new PowerShell session and run Test-Alias.
There are a few caveats with Test-Alias. Because it uses Get-Command, if you have an alias that points to a command in a module that isn’t currently loaded in your session, that module will be loaded during the process of using Test-Alias.
As an example, let’s say I have an alias called gau that points to Get-ADUser from the ActiveDirectory module. PowerShell will load the ActiveDirectory module during the process of testing the alias. This is because of PowerShell’s autoloading feature introduced in PowerShell 3.0. This also means that any alias that point to commands in a PSSnapin, will fail to properly resolve, unless you first manually add the PSSnapin.
Even if you don’t need to test aliases, I hope you learned a few thing about creating PowerShell tools. As always I’d love to hear what you think.