Tag Archives: aliases

Put the Alias Description Property to Work II

In part I of Put the Alias Description Property to Work, I showed and explained how to add a description property to each of my personal, profile script-created aliases. This allowed me to use a basic function, that filtered the Get-Alias results to return only my aliases. In this post, we will take this one step further and we will add descriptions to the built-in aliases in PowerShell. If you remember, we determined that most of the built-in aliases do not include a source property. Therefore, sorting or filtering on that property is of little value.

The source property is not a settable property, meaning that no matter how hard I try, I cannot edit it. The Description property, as we learned, is open for me to make changes. This is also true with built-in aliases and not just the aliases I create. Here is what we are going to do. All the aliases resolve to a command, and all but four of those commands have a source property. We are going to acquire a command’s source and set it as the description of its alias. This might make more sense with some examples, so let’s start there.

But before we do, let’s look at the default properties returned by Get-Alias.

Get-Alias | Get-Random
CommandType     Name                Version    Source
-----------     ----                -------    ------
Alias           pwd -> Get-Location 

Get-Alias returns CommandType, Name, Version, and Source. Kind of. Name is really a property called DisplayName. It may be better to know that now. In the first, real example, we are also going to use Get-Random to randomly select an alias for us. Then, we will return its ResolvedCommandName, DisplayName, Description, and Options properties.

$Alias = Get-Alias | Get-Random
Get-Alias -Name $Alias |
    Select-Object ResolvedCommandName,DisplayName,Description,Options
ResolvedCommandName DisplayName               Description  Options
------------------- -----------               -----------  -------
Connect-PSSession   cnsn -> Connect-PSSession             ReadOnly

Notice that currently, its Description property is blank. In the next example, we will use the value stored in $Alias and run it through a ForEach-Object loop. Take a look at the PowerShell now, and I will do that recently experimented with, line-by-line explanation further below.

Get-Alias -Name $Alias | ForEach-Object {
    if ($_.Description -eq '') {
        $Params = @{
            Name = $_.Name
            Value = $_.ResolvedCommandName
            Description = if ((Get-Command -Name $_.ResolvedCommandName).Source) {
                ((Get-Command -Name $_.ResolvedCommandName).Source)
            } else {'None'}
            Option = $_.Options
            Force = $true
        }
        Set-Alias @Params -Verbose
    }
}

VERBOSE: Performing the operation "Set Alias" on target "Name: cnsn Value: Connect-PSSession".

Line 1: Pipe our single alias into a ForEach-Object loop.
Line 2: Continue into an if construct if the alias’ description is empty. If it is not, we would move on to the next alias if there were more than just one.
Line 3: Create a hash table and store it in the $Params variable.
Line 4, 5: Add the name and the resolved command name into the Name and Value keys, respectively.
Line 6 – 8: Add a description to the Description key based on whether or not there is a source. If there is a source, add it, if there is not a source add the string None.
Line 9, 10: Add the options and $true value into the Option and Force keys, respectively.
Line 12: Invoke the Set-Alias command, splatting the $Params hash table as parameters and associated parameter values.

Let’s rerun the command we did just a minute ago.

Get-Alias -Name $Alias |
    Select-Object ResolvedCommandName,DisplayName,Description,Options
ResolvedCommandName DisplayName               Description                Options
------------------- -----------               -----------                -------
Connect-PSSession   cnsn -> Connect-PSSession Microsoft.PowerShell.Core ReadOnly

We have taken the source of the command Connect-PSSession and placed its value into the description of an alias that resolves to Connect-PSSession. It is not genius, but it is something!

Moving on, the next command pipes out all the known aliases and the values in each of the included properties. I will only include the first ten, as there are almost 150.

Get-Alias |
    Select-Object ResolvedCommandName,DisplayName,Description,Options
ResolvedCommandName DisplayName           Description              Options
------------------- -----------           -----------              -------
Where-Object        ? -> Where-Object                   ReadOnly, AllScope
ForEach-Object      % -> ForEach-Object                 ReadOnly, AllScope
Add-Content         ac -> Add-Content                             ReadOnly
Clear-Host          c -> Clear-Host        tommymaynard               None
Get-Content         cat -> Get-Content                                None
Set-Location        cd -> Set-Location                            AllScope
Set-Location        chdir -> Set-Location                             None
Clear-Content       clc -> Clear-Content                          ReadOnly
Clear-Host          clear -> Clear-Host                               None
Clear-History       clhy -> Clear-History                         ReadOnly

This should look familiar. There are a couple of differences in this code block compared to the one above. One, we are piping in all of the aliases (not just one), and two, there is no Verbose parameter included when the Set-Alias command is invoked. We do not need to output the change made to each alias. Yeah, no thanks.

Get-Alias | ForEach-Object {
    if ($_.Description -eq '') {
        $Params = @{
            Name = $_.Name
            Value = $_.ResolvedCommandName
            Description = if ((Get-Command -Name $_.ResolvedCommandName).Source) {
                ((Get-Command -Name $_.ResolvedCommandName).Source)
            } else {'None'}
            Option = $_.Options
            Force = $true
        }
        Set-Alias @Params
    }
}

This is the same command we saw earlier. I have only included the first ten here, as well. Notice the changes made to the Description property for each alias. Now I can easily see which alias goes with which source.

Get-Alias |
    Select-Object ResolvedCommandName,DisplayName,Description,Options
ResolvedCommandName DisplayName           Description                                Options
------------------- -----------           -----------                                -------
Where-Object        ? -> Where-Object     Microsoft.PowerShell.Core       ReadOnly, AllScope
ForEach-Object      % -> ForEach-Object   Microsoft.PowerShell.Core       ReadOnly, AllScope
Add-Content         ac -> Add-Content     Microsoft.PowerShell.Management           ReadOnly
Clear-Host          c -> Clear-Host       tommymaynard                                  None
Get-Content         cat -> Get-Content    Microsoft.PowerShell.Management               None
Set-Location        cd -> Set-Location    Microsoft.PowerShell.Management           AllScope
Set-Location        chdir -> Set-Location Microsoft.PowerShell.Management               None
Clear-Content       clc -> Clear-Content  Microsoft.PowerShell.Management           ReadOnly
Clear-Host          clear -> Clear-Host   None                                          None
Clear-History       clhy -> Clear-History Microsoft.PowerShell.Core                 ReadOnly

Like all worthy PowerShell code, I am going to wrap this in a function, and for the foreseeable future, copy this into my profile script. There is one change in this version that should be mentioned. The Scope parameter is now being included inside the $Params hash table with the Global value. Like the other parameters and parameters values in this hash table, it will be splatted onto the Set-Alias cmdlet when it is invoked. While the Scope parameter is not required with Get-Alias, it absolutely is with Set-Alias. We want the aliases that exist outside the function to be the ones we modify.

function Set-AliasDescription
Get-Alias | ForEach-Object {
    if ($_.Description -eq '') {
        $Params = @{
            Name = $_.Name
            Value = $_.ResolvedCommandName
            Description = if ((Get-Command -Name $_.ResolvedCommandName).Source) {
                ((Get-Command -Name $_.ResolvedCommandName).Source)
            } else {'None'}
            Option = $_.Options
            Force = $true
            Scope = 'Global'
        }
        Set-Alias @Params
    }
}
Set-AliasDescription

With the descriptions set, we can filter such as in the next two examples. Remember, the Get-Alias Description property is not displayed by default.

Get-Alias | Where-Object -Property Description -eq 'None'
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           clear -> Clear-Host
Alias           cls -> Clear-Host
Alias           man -> help
Alias           md -> mkdir
Get-Alias | Where-Object -Property Description -like '*core'
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           ? -> Where-Object
Alias           % -> ForEach-Object
Alias           clhy -> Clear-History
Alias           cnsn -> Connect-PSSession
Alias           dnsn -> Disconnect-PSSession
Alias           etsn -> Enter-PSSession
Alias           exsn -> Exit-PSSession
Alias           foreach -> ForEach-Object
Alias           gcm -> Get-Command
Alias           ghy -> Get-History
Alias           gjb -> Get-Job
Alias           gmo -> Get-Module
Alias           gsn -> Get-PSSession
Alias           h -> Get-History
Alias           history -> Get-History
Alias           icm -> Invoke-Command
Alias           ihy -> Invoke-History
Alias           ipmo -> Import-Module
Alias           nmo -> New-Module
Alias           nsn -> New-PSSession
Alias           oh -> Out-Host
Alias           r -> Invoke-History
Alias           rcjb -> Receive-Job
Alias           rcsn -> Receive-PSSession
Alias           rjb -> Remove-Job
Alias           rmo -> Remove-Module
Alias           rsn -> Remove-PSSession
Alias           sajb -> Start-Job
Alias           spjb -> Stop-Job
Alias           where -> Where-Object
Alias           wjb -> Wait-Job

Put the Alias Description Property to Work

I use a small handful of my own PowerShell aliases and of course some of those included with PowerShell natively. There is a best practice around aliases in PowerShell, and that is to not use them in anything that is going to live longer than a one-time use. Therefore, do not use them in scripts, functions, and modules (except in the case where your module exports aliases). I would recommend not even using them in forum posts or emails or work-only documentation. Keep them away from your own personal documentation, too. You might know what spsv, ndr, rcjb, and shcm mean today, at this moment, but you may not a few months from now. They have a place, however. Use them in your console, or shell, to speed up what would otherwise be a longer, manually entered command. Let’s check my $PROFILE script and see how many of my own PowerShell aliases I have.

Get-Content -Path $PROFILE | Select-String -Pattern '-alias'
Set-Alias -Name c -Value Clear-Host
Set-Alias -Name psrh -Value Open-PSReadLineHistoryFile
Set-Alias -Name sel -Value Select-Object
Set-Alias -Name wa -Value Watch-Apartment
Set-Alias -Name psgal -Value Show-PSGalleryProjectJob
'l','link' | ForEach-Object {Set-Alias -Name $_ -Value Find-Link}
Set-Alias -Name cts -Value Convert-TextToSpeech

Based on the above command and its results, I have seven. Even that is too many to remember when they are not being used often. Well, I forgot one recently and I was annoyed I had to open my profile script file and search for -alias. Sure, I could have used the above Get-Content command I wrote and tried out a minute ago, but why? Why not avoid ever having to search for my aliases from inside a source file again. They exist in the PowerShell session; why not search there? I am already in the session.

My first thought was, why does Microsoft not indicate which aliases are built-in? There is a source property. It is just too bad that not many aliases include that information. It would be much simple to filter aliases that way, removing those that are not a part of a Microsoft.<something>.<something> module. But, if you return this property there is often nothing. To begin with, there are currently 147 aliases on my machine.

(Get-Alias).Count
147

Only seven include a value in their source property.

Get-Alias | Where-Object Source -ne ''
CommandType     Name                    Version    Source
-----------     ----                    -------    ------
Alias           fhx -> Format-Hex       7.0.0.0    Microsoft.PowerShell.Utility
Alias           gcb -> Get-Clipboard    7.0.0.0    Microsoft.PowerShell.Management
Alias           gin -> Get-ComputerInfo 7.0.0.0    Microsoft.PowerShell.Management
Alias           gtz -> Get-TimeZone     7.0.0.0    Microsoft.PowerShell.Management
Alias           scb -> Set-Clipboard    7.0.0.0    Microsoft.PowerShell.Management
Alias           stz -> Set-TimeZone     7.0.0.0    Microsoft.PowerShell.Management

Weird right? One command alias is from the Microsoft.PowerShell.Utility module and six are from the Microsoft.PowerShell.Management module. It is not like there are only one and six aliases, respectively, from each entire module. There are plenty more commands and aliases, as well. Take a look; I have included both modules. We will begin with the Microsoft.PowerShell.Utility module.

((Get-Command -Module Microsoft.PowerShell.Utility).Name |
    ForEach-Object {Get-Alias -Definition $_ -ErrorAction SilentlyContinue}).Count
43
(Get-Command -Module Microsoft.PowerShell.Utility).Name |
    ForEach-Object {Get-Alias -Definition $_ -ErrorAction SilentlyContinue}
CommandType     Name                        Version    Source
-----------     ----                        -------    ------
Alias           clv -> Clear-Variable
Alias           compare -> Compare-Object
Alias           diff -> Compare-Object
Alias           dbp -> Disable-PSBreakpoint
Alias           ebp -> Enable-PSBreakpoint
Alias           epal -> Export-Alias
Alias           epcsv -> Export-Csv
Alias           fc -> Format-Custom
Alias           fhx -> Format-Hex           7.0.0.0    Microsoft.PowerShell.Utility
Alias           fl -> Format-List
Alias           ft -> Format-Table
Alias           fw -> Format-Wide
Alias           gal -> Get-Alias
Alias           gerr -> Get-Error
Alias           gm -> Get-Member
Alias           gbp -> Get-PSBreakpoint
Alias           gcs -> Get-PSCallStack
Alias           gu -> Get-Unique
Alias           gv -> Get-Variable
Alias           group -> Group-Object
Alias           ipal -> Import-Alias
Alias           ipcsv -> Import-Csv
Alias           iex -> Invoke-Expression
Alias           irm -> Invoke-RestMethod
Alias           iwr -> Invoke-WebRequest
Alias           measure -> Measure-Object
Alias           nal -> New-Alias
Alias           nv -> New-Variable
Alias           ogv -> Out-GridView
Alias           rbp -> Remove-PSBreakpoint
Alias           rv -> Remove-Variable
Alias           select -> Select-Object
Alias           sls -> Select-String
Alias           sal -> Set-Alias
Alias           sbp -> Set-PSBreakpoint
Alias           set -> Set-Variable
Alias           sv -> Set-Variable
Alias           shcm -> Show-Command
Alias           sort -> Sort-Object
Alias           sleep -> Start-Sleep
Alias           tee -> Tee-Object
Alias           echo -> Write-Output
Alias           write -> Write-Output

And continue with the Microsoft.PowerShell.Management module.

((Get-Command -Module Microsoft.PowerShell.Management).Name |
    ForEach-Object {Get-Alias -Definition $_ -ErrorAction SilentlyContinue}).Count
62
(Get-Command -Module Microsoft.PowerShell.Management).Name |
    ForEach-Object {Get-Alias -Definition $_ -ErrorAction SilentlyContinue}
CommandType     Name                         Version    Source
-----------     ----                         -------    ------
Alias           ac -> Add-Content
Alias           clc -> Clear-Content
Alias           cli -> Clear-Item
Alias           clp -> Clear-ItemProperty
Alias           cvpa -> Convert-Path
Alias           copy -> Copy-Item
Alias           cp -> Copy-Item
Alias           cpi -> Copy-Item
Alias           cpp -> Copy-ItemProperty
Alias           dir -> Get-ChildItem
Alias           gci -> Get-ChildItem
Alias           ls -> Get-ChildItem
Alias           gcb -> Get-Clipboard         7.0.0.0    Microsoft.PowerShell.Management
Alias           gin -> Get-ComputerInfo      7.0.0.0    Microsoft.PowerShell.Management
Alias           cat -> Get-Content
Alias           gc -> Get-Content
Alias           type -> Get-Content
Alias           gi -> Get-Item
Alias           gp -> Get-ItemProperty
Alias           gpv -> Get-ItemPropertyValue
Alias           gl -> Get-Location
Alias           pwd -> Get-Location
Alias           gps -> Get-Process
Alias           ps -> Get-Process
Alias           gdr -> Get-PSDrive
Alias           gsv -> Get-Service
Alias           gtz -> Get-TimeZone          7.0.0.0    Microsoft.PowerShell.Management
Alias           ii -> Invoke-Item
Alias           mi -> Move-Item
Alias           move -> Move-Item
Alias           mv -> Move-Item
Alias           mp -> Move-ItemProperty
Alias           ni -> New-Item
Alias           mount -> New-PSDrive
Alias           ndr -> New-PSDrive
Alias           popd -> Pop-Location
Alias           pushd -> Push-Location
Alias           del -> Remove-Item
Alias           erase -> Remove-Item
Alias           rd -> Remove-Item
Alias           ri -> Remove-Item
Alias           rm -> Remove-Item
Alias           rmdir -> Remove-Item
Alias           rp -> Remove-ItemProperty
Alias           rdr -> Remove-PSDrive
Alias           ren -> Rename-Item
Alias           rni -> Rename-Item
Alias           rnp -> Rename-ItemProperty
Alias           rvpa -> Resolve-Path
Alias           scb -> Set-Clipboard         7.0.0.0    Microsoft.PowerShell.Management
Alias           si -> Set-Item
Alias           sp -> Set-ItemProperty
Alias           cd -> Set-Location
Alias           chdir -> Set-Location
Alias           sl -> Set-Location
Alias           stz -> Set-TimeZone          7.0.0.0    Microsoft.PowerShell.Management
Alias           saps -> Start-Process
Alias           start -> Start-Process
Alias           sasv -> Start-Service
Alias           kill -> Stop-Process
Alias           spps -> Stop-Process
Alias           spsv -> Stop-Service

In the end, the Microsoft.PowerShell.Utilityhas 43 aliases and the Microsoft.PowerShell.Management module has 63 aliases. Maybe there is a good reason for the source, not being included most of the time. But, we are here to make my aliases easier to find. The source property is not a settable property, therefore, we are going to use the Description property to indicate when an alias is one of mine. Here are my aliases from earlier, each with a new addition to their Description property. It is my name.

Set-Alias -Name c -Value Clear-Host -Description 'tommymaynard'
Set-Alias -Name psrh -Value Open-PSReadLineHistoryFile -Description 'tommymaynard'
Set-Alias -Name sel -Value Select-Object -Description 'tommymaynard'
Set-Alias -Name wa -Value Watch-Apartment -Description 'tommymaynard'
Set-Alias -Name psgal -Value Show-PSGalleryProjectJob -Description 'tommymaynard'
'l','link' | ForEach-Object {Set-Alias -Name $_ -Value Find-Link -Description 'tommymaynard'}
Set-Alias -Name cts -Value Convert-TextToSpeech -Description 'tommymaynard'

Now, after my profile script runs, I can invoke a modified Get-Alias command to return just my aliases from the current PowerShell session.

Get-Alias | Where-Object -Property Description -eq 'tommymaynard'
CommandType     Name                               Version    Source
-----------     ----                               -------    ------
Alias           c -> Clear-Host
Alias           cts -> Convert-TextToSpeech
Alias           l -> Find-Link
Alias           link -> Find-Link
Alias           psgal -> Show-PSGalleryProjectJob
Alias           psrh -> Open-PSReadLineHistoryFile
Alias           sel -> Select-Object
Alias           wa -> Watch-Apartment

This post would not be complete if there was no new function to add to my $PROFILE script. So, with that, here is that new function and alias. Notice I added the description to the new alias, too!

Set-Alias -Name gmal -Value Get-MyAlias -Description 'tommymaynard'
function Get-MyAlias {
    Get-Alias | Where-Object -Property Description -eq 'tommymaynard'
}
gmal
CommandType     Name                              Version    Source
-----------     ----                               -------    ------
Alias           c -> Clear-Host
Alias           cts -> Convert-TextToSpeech
Alias           gmal -> Get-MyAlias
Alias           l -> Find-Link
Alias           link -> Find-Link
Alias           psgal -> Show-PSGalleryProjectJob
Alias           psrh -> Open-PSReadLineHistoryFile
Alias           sel -> Select-Object
Alias           wa -> Watch-Apartment

Part II has been published!

Cmdlet and Function Alias Best Practice

Aliases are a beautiful thing, really. Even though this may be true, we need to make sure we’re following best practice, when we opt to use them. I’m not sure what it is about me, but I get a little antsy whenever I see someone not conforming to a best practice in PowerShell. I really don’t care how you lace and tie your shoes, or make your peanut butter and jelly sandwiches, but when you use your PowerShell aliases is important to me, and it should be to you, too.

The main idea here is that cmdlet and function aliases shouldn’t exist in something that lasts longer than a one time use. That means we shouldn’t see them in help documentation (although, I believe I’ve seen some), in online articles, and in PowerShell-related forum posts. The only time you’ll see me use a cmdlet or function alias, is if you’re looking over my shoulder and watching me type commands into my console, or the ISE’s console pane. Realistically, aliases do two things: One, they help speed up getting results in a one time use scenario, as I’ve mentioned, and two, they confuse PowerShell newcomers that come across a blog where they’ve been used without consideration to best practice. Perhaps it’s my desire to help people learn PowerShell, that’s driving some of this alias indignation. I should mention, that I think it’s acceptable to include them in cases where you also explain that you’re using an alias, and indicate the full cmdlet or function name.

If you showed up here after seeing one of those blogs, or scripts, where someone littered their work with aliases, keep in mind that we have a Get-Alias cmdlet that can help you determine to which cmdlet an alias resolves — we’ll get back to that momentarily. Let’s say you found this command online:

PS> ls c:\windows | ? {$_ -like 'Win*'} | % {echo "$($_.Name)||$($_.LastWriteTime)"}

I understand this command has the potential to be written better. One such way, would be to not pipe to ? in order to filter on the file or directory name, but instead to use the ls -Filter parameter. Weird… in that last sentence, I used a couple aliases instead of their cmdlet names, and even that was confusing. Imagine having read that as a newcomer. This command, since it’s going to live on this webpage “forever,” should have been written like this (for the most part):

PS> Get-ChildItem -Path c:\windows | Where-Object {$_ -like 'Win*'} | ForEach-Object {Write-Output -InputObject "$($_.Name)||$($_.LastWriteTime)"}

It’s longer, there’s no doubt about it, but it’s much more complete and easier to comprehend, especially had you found it in a lengthy script or function.

Back to Get-Alias: If you find yourself confused by a command you found online, where someone “didn’t think of the next person,” then run though the command, or commands, and check the aliases against the Get-Alias cmdlet. Let’s do that below, for the first example command I wrote. Notice that Get-Alias will accept a comma-separated list of (alias) values.

PS> Get-Alias -Name ls,?,%,echo

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           ls -> Get-ChildItem
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           h -> Get-History
Alias           r -> Invoke-History
Alias           % -> ForEach-Object
Alias           echo -> Write-Output

Now, notice the results. We’ve returned aliases that we didn’t request, such as h for Get-History and r for Invoke-History. Why? A little off topic, but this is because the question mark (?), in regular expressions, or regex, stands in for a single character. The results are not only returning the alias for the question mark, but for any aliases that only have a single character. In order to only return what we want, we’ll need to escape the question mark character and put it in quotes, so that the parser is certain we have supplied the string value, of an actual question mark.

PS> Get-Alias -Name ls,'`?',%,echo

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           ls -> Get-ChildItem
Alias           ? -> Where-Object
Alias           % -> ForEach-Object
Alias           echo -> Write-Output

There, we go.

As a community, we should do things so they better help the current, and future members. Use all the aliases you want, but do so where they won’t exist for someone else to stumble upon, unless, you’ve taken the time to explain that you’ve used an alias, and to which cmdlet it refers.

In closing, I want to mention the PSScriptAnalyzer module. I pulled it down and installed it in PowerShell 5.0, using the Find-Module and Install-Module cmdlets: Find-Module -Name PSScriptAnalyzer | Install-Module. I then copied my alias heavily command above, pasted it into notepad, and saved it as C:\file.ps1. Following that, I ran an Invoke-ScriptAnalyzer command. You can see the command and its results below

PS> Invoke-ScriptAnalyzer -Path C:\file.ps1 -IncludeRule PSAvoidUsingCmdletAliases

RuleName                            Severity     FileName   Line  Message
--------                            --------     --------   ----  -------
PSAvoidUsingCmdletAliases           Warning      file.ps1   1     'echo' is an alias of 'Write-Output'. Alias can
                                                                  introduce possible problems and make scripts hard to
                                                                  maintain. Please consider changing alias to its full
                                                                  content.
PSAvoidUsingCmdletAliases           Warning      file.ps1   1     '%' is an alias of 'ForEach-Object'. Alias can
                                                                  introduce possible problems and make scripts hard to
                                                                  maintain. Please consider changing alias to its full
                                                                  content.
PSAvoidUsingCmdletAliases           Warning      file.ps1   1     '?' is an alias of 'Where-Object'. Alias can
                                                                  introduce possible problems and make scripts hard to
                                                                  maintain. Please consider changing alias to its full
                                                                  content.
PSAvoidUsingCmdletAliases           Warning      file.ps1   1     'ls' is an alias of 'Get-ChildItem'. Alias can
                                                                  introduce possible problems and make scripts hard to
                                                                  maintain. Please consider changing alias to its full
                                                                  content.

The cmdlet was instructed to only return the problems it found with aliases (see the parameter used and the included value). It’s a very powerful cmdlet; not only can you find any alias-related best practice failures, but it’ll help you locate any other areas, where you can improve your code.

Thanks for your time, and… your new dedication to not use cmdlet and function aliases, that last longer than a one time use.

Update: I just saw a post from The Scripting! Guy (http://blogs.technet.com/b/heyscriptingguy/archive/2015/10/25/powertip-group-powershell-cmdlet-count-by-version.aspx) where he used a few aliases and told us what they mean. If you’re going to use them, explain them.

about_Aliases

This post is the help rewrite for about_Aliases. While the help files for Windows PowerShell are invaluable, the idea behind a rewrite is so true beginners might even better understand the help file concepts. At times, some things discussed in the Windows PowerShell help file will not be included in a help rewrite. Therefore, it is always best to read the actual help file after reading this post. (PS3.0)

An Alias in Windows PowerShell is a simplified, or quicker, way to type a cmdlet using an alternate name. Get-Alias (or the alias for Get-Alias, gal) will display a list of all of the aliases that the Windows PowerShell session knows about. This includes both built-in aliases and any additional aliases created or imported. The first two examples below, indicate two ways to accomplish the same thing–listing all the aliases. These examples only show the first four results.

PS C:\> Get-Alias

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           asnp -> Add-PSSnapin

This example uses the alias for the Get-Alias cmdlet, gal.

PS C:\> gal

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           asnp -> Add-PSSnapin

To find the cmdlet associated with a single alias, the alias needs to be provided, as the value for the -Name parameter, to the Get-Alias cmdlet.

PS C:\> gal -Name gc

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           gc -> Get-Content

The name parameter (-Name) is not required to use it. This means that if there is something after the Get-Alias cmdlet, such as gc in this example, then it will default to using the -Name parameter.

PS C:\> gal gc

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           gc -> Get-Content

Windows PowerShell will error if the -Name parameter is supplied with a cmdlet name or another value that is not an alias.

PS C:\> gal Get-Content

gal : This command cannot find a matching alias because an alias with the name ‘Get-Content’ does not exist.
At line:1 char:1
+ gal Get-Content
+ ~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (Get-Content:String) [Get-Alias], ItemNotFoundException
+ FullyQualifiedErrorId : ItemNotFoundException,Microsoft.PowerShell.Commands.GetAliasCommand

In order to get an alias (or aliases, if there is more than one) for a cmdlet, the -Definition parameter must be used.

PS C:\> gal -Definition Get-Content

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           cat -> Get-Content
Alias           gc -> Get-Content
Alias           type -> Get-Content

The Get-Service cmdlet returns the computer’s services, the Get-Process cmdlet returns the processes running on the computer, and the Get-ChildItem cmdlet returns the directories and/or files from the root of a drive or from a folder. Here is how a user can get the aliases for multiple cmdlets at the same time.

PS C:\> gal -Definition Get-Service,Get-Process,Get-ChildItem

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Alias           gsv -> Get-Service
Alias           gps -> Get-Process
Alias           ps -> Get-Process
Alias           dir -> Get-ChildItem
Alias           gci -> Get-ChildItem
Alias           ls -> Get-ChildItem

There are a few other cmdlets that allow a user to work with aliases. By using the Get-Command cmdlet (or its alias–if it has one), additional cmdlets can be returned that all end with -Alias.

PS C:\> Get-Command *-Alias

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Export-Alias                                       Microsoft.PowerShell.Utility
Cmdlet          Get-Alias                                          Microsoft.PowerShell.Utility
Cmdlet          Import-Alias                                       Microsoft.PowerShell.Utility
Cmdlet          New-Alias                                          Microsoft.PowerShell.Utility
Cmdlet          Set-Alias                                          Microsoft.PowerShell.Utility

Export-Alias: Exports information about currently defined aliases to a file.

PS C:\> Export-Alias -Path 'C:\aliases.txt'

Import-Alias: Imports an alias, or aliases, from a file.

PS C:\> Import-Alias -Path 'C:\ImportedAliases.txt'

Trying to import aliases that already exist will cause an error for every alias Windows PowerShell tries to import (that already exists).

PS C:\> Export-Alias -Path 'C:\aliases.txt'
PS C:\> Import-Alias -Path 'C:\aliases.txt'
Import-Alias : The alias is not allowed, because an alias with the name ‘ac’ already exists.
At line:1 char:1
+ Import-Alias -Path ‘C:\aliases.txt’
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceExists: (ac:String) [Import-Alias], SessionStateException
    + FullyQualifiedErrorId : AliasAlreadyExists,Microsoft.PowerShell.Commands.ImportAliasCommand

New-Alias: Creates a new alias.
Set-Alias: Changes an existing alias, or creates an alias if it does not already exist.

PS C:\> New-Alias -Name MyAlias -Value Get-Process
PS C:\> MyAlias | select -First 4

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    224      19     3440        772   110    16.50   4612 ALMon
    164      14     2476       2108    44     5.36   2744 ALsvc
     77       9     1336       5288    75   137.55   4076 ApMsgFwd
     90       8     1372       5788    76   162.11   4324 ApntEx

PS C:\> Set-Alias -Name MyAlias -Value Get-Service
PS C:\> MyAlias | select -First 4

Status   Name               DisplayName
------   ----               -----------
Running  AdobeARMservice    Adobe Acrobat Update Service
Stopped  AdobeFlashPlaye... Adobe Flash Player Update Service
Stopped  AeLookupSvc        Application Experience
Stopped  ALG                Application Layer Gateway Service

Bonus Information

Use the Measure-Object cmdlet, or the count property, to find out how many aliases Windows PowerShell knows about.

PS C:\> Get-Alias | Measure-Object

Count    : 182
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

PS C:\> gal | measure

Count    : 182
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

PS C:\> (gal | measure).count
182
PS C:\> (gal).count
182

Real World

While aliases are helpful in the console, the belief is that they should not be used in a script file (.ps1 file). Using full cmdlet names in a script is preferred for script readability. There are plenty of people writing Windows PowerShell who adhere to this best practice even while using aliases for the object cmdlets (select for Select-Object, where for Where-Object, etc.).

Learn More

This information, and more, are stored in the help file about_Aliases that comes with Windows PowerShell. This information can be read by typing any of the commands below. The first example will display the help file in the Windows PowerShell console, the second example will open the full help in its own window, and the third example will send the contents of the help file to the clipboard (so it can be pasted into Word, Notepad, etc.), and the fourth example will open the help file in Notepad.

PS C:\> Get-Help about_aliases
PS C:\> Get-Help about_aliases -ShowWindow
PS C:\> Get-Help about_aliases | clip
PS C:\> Notepad C:\Windows\System32\WindowsPowerShell\v1.0\en-US\about_Aliases.help.txt

There is a built-in, automatic variable $PSHOMEthat stores the installation path of Windows PowerShell. This means that the third example above could have been partially written using that variable.

PS C:\> Notepad $PSHOME\en-us\about_Aliases.help.txt