Bookmark and Share

Hey, Scripting Guy! Question

Hey, Scripting Guy! I enjoy using Windows PowerShell, but I do not like the two-word cmdlet names you created for everything. As a matter of fact, I hate the two-word cmdlet names because the dash (-) symbol is hard to type. I guess I will eventually get used to it, but you have to realize that Windows PowerShell as a tool for network administrators is really hard to use. I studied computer architecture and networking protocols at university—not typing. I don’t suppose you can do anything about it now, but I just thought I would let off some steam. For a tool that is advertised to make things easier, it sure is hard to use.

-- BW

Hey, Scripting Guy! AnswerHello BW,

Microsoft Scripting Guy Ed Wilson here. It is dark as pitch. Not a star in the sky. Not a street light visible through the thick evening fog. I am trying to catch up on e-mail sent to the scripter@microsoft.com e-mail alias and get ready for the approaching holiday season in the United States. Between now and the new year, Craig and I will only be working a few overlapping days, and we are not going to publish reruns through the holidays as has been done in the past. This means burning the midnight oil so to speak. I enjoy working in the evening. I am listening to Phil Collins on my Zune HD, and sipping a cup of blueberry tea. The sleeping Office Communicator icon in the notification area of my Window 7 Task Bar and dearth of meetings means I can be doubly productive, which is perfect because I need to write twice the number of Hey, Scripting Guy! posts during the next two weeks to meet my goal.

Anyway, BW, you seem to be averse to typing the dash symbol. You are not the first person who has mentioned this to me. If you really want to fix the problem, you can do it with a single-line command as shown here:

gcm -CommandType cmdlet | % { Set-Alias ( $_.name -replace "-","") $_.name }

GCM is the alias for the Windows PowerShell Get-Command cmdlet. An alias allows you to create a shortcut name for a command. Do this for commands that are hard to type, too long to type, or too difficult to remember. By using aliases, you can completely customize the way that you interact with Windows PowerShell. To see a list of the available aliases, use the Get-Alias cmdlet, which will list aliases that are created by Windows PowerShell as well as any aliases you may have created yourself.

Truncated output from the Get-Alias cmdlet is seen just below. You will notice that the first alias that is listed is the percent sign. It is an alias for the ForEach-Object cmdlet and was used in the code we used to remove the dash from all the cmdlet names. The next alias, the question mark, is also a commonly used alias. The problem a number of people coming from a DOS/VBScript background have with the question mark alias is that command-line utilities often used the question mark for help. Some of the new aliases we created can also be seen. AddComputer, AddContent, and others are the standard command names with the dash removed. These are shown here:

PS C:\> Get-Alias

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           %                                                   ForEach-Object
Alias           ?                                                   Where-Object
Alias           ac                                                  Add-Content
Alias           AddComputer                                         Add-Computer
Alias           AddContent                                          Add-Content
Alias           AddHistory                                          Add-History
Alias           AddMember                                           Add-Member
Alias           AddPSSnapin                                         Add-PSSnapin
Alias           AddType                                             Add-Type
Alias           asnp                                                Add-PSSnapIn
Alias           cat                                                 Get-Content

The problem with simply executing a command inside the Windows PowerShell console is that once you close and re-open Windows PowerShell console, the aliases are gone. They will need to be recreated each time that you open Windows PowerShell. This is shown by the output seen here:

Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS C:\> Get-Alias

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           %                                                   ForEach-Object
Alias           ?                                                   Where-Object
Alias           ac                                                  Add-Content
Alias           asnp                                                Add-PSSnapIn
Alias           cat                                                 Get-Content
Alias           cd                                                  Set-Location
Alias           chdir                                               Set-Location

One thing you can do to make sure you always have the aliases you wish is to save your command history after you have run the command to create the aliases. You can save your command history to an XML file by using the following command:

Get-History |
Export-Clixml -Path c:\fso\history.xml

The saved XML file can be viewed in XML Notepad as seen in the following image. The thing to keep in mind about this technique is you want to make sure that you have a clean command history by closing the Windows PowerShell console and re-opening it:

Image of XML file being viewed with XML Notepad


After you have your newly created history.xml file, you need only to import the file and execute each of the commands in your command history. You can do this by using the following command:

Import-Clixml C:\fso\history.xml |
add-history -passthru |
foreach-object {invoke-history}

The use of this command is seen here. Notice that when the history is invoked, the command is displayed on the command line. The Get-Alias cmdlet is then used to list the last four alises, which are our newly created aliases.

PS C:\> Import-Clixml C:\fso\history.xml |
>> add-history -passthru |
>> foreach-object {invoke-history}
>>
gcm -CommandType cmdlet | % { Set-Alias ( $_.name -replace "-","") $_.name }
PS C:\> Get-Alias | select -Last 4

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           WriteOutput                                         Write-Output
Alias           WriteProgress                                       Write-Progress
Alias           WriteVerbose                                        Write-Verbose
Alias           WriteWarning                                        Write-Warning


PS C:\>

One use of the export/import command history technique would be in a setting where you were not permitted to run scripts. Because the Windows PowerShell profile is a script, the profile script will not run if the command execution policy is set to Restricted.

The best place to manage aliases, of course, is to use the Windows PowerShell profile. Our Windows PowerShell profile from yesterday has been updated with the “remove the dash” command and a couple of additional aliases. The Profile.ps1 script is seen here.

Profile.ps1

# HSG_Profile_11_24_09.ps1
# HSG-11-24-09
# Ed Wilson, MSFT, 11/18/2009
# Version 1.0

# *** Variables ***
New-Variable -Name ProfileFolder -Value (Split-Path $PROFILE -Parent) `
   -Description MrEd_Variable
New-Variable -Name IseProfile `
   -Value (Join-Path -Path (Split-Path $PROFILE -Parent) `
   -ChildPath Microsoft.PowerShellISE_profile.ps1) `
   -Description MrEd_Variable
New-Variable -Name MyComputers -Value Hyperv,Win7-PC -Description MrEd_Variable
New-Variable -name temp -value $([io.path]::gettemppath()) -Description MrEd_Variable
Set-Variable -Name MaximumHistoryCount -Value 128 -Description MrEd_Variable

# *** Alias ***
Get-Command -CommandType cmdlet |
Foreach-Object {
 Set-Alias -name ( $_.name -replace "-","") -value $_.name -description MrEd_Alias
} #end Get-Command
New-Alias -name gh -value Get-Help -description MrEd_Alias
New-Alias -name i -value Invoke-History -description MrEd_Alias

# *** PS Drive ***

# *** Function ***

Before transferring the “remove the dashes” command to the Windows PowerShell profile, I modified it by removing the aliases from the command (I know, it seems a little strange to remove aliases from a command that creates aliases) because as a best practice, you do not want to use aliases or positional arguments in scripts. Though it is possible to add aliases, it is also possible to remove aliases—even aliases that are included by default. Suppose, for example, that the use of the question mark for the Where-Object cmdlet really bugs you, and you would rather use it for the Get-Help cmdlet. No problem. You just modify the value of the alias. This is seen here:

PS C:\> Set-Alias -Name ? -Value Get-Help -Force -Option allscope
PS C:\>

Maybe you really do not like the % alias at all. You can remove the alias by using the Remove-Item cmdlet. This is seen here.

PS C:\> Remove-Item alias:\% -Force
PS C:\>

All this is to say that when using an alias, you never know if it is going to exist or not, unless you totally control the environment. As a best practice, do not use aliases in a script. 

Two aliases that I like to use are gh for the Get-Help cmdlet and i for the Invoke-History cmdlet. When creating new aliases, I like to populate the description parameter. This is seen here:

New-Alias -name gh -value Get-Help -description MrEd_Alias
New-Alias -name i -value Invoke-History -description MrEd_Alias

The advantage of populating the description parameter for the alias is it makes it easy to retrieve my custom aliases. I can do this by using the Get-Alias cmdlet to retrieve all the defined aliases, and pipe the results to the Where-Object cmdlet. The command and the truncated results are shown here:

PS C:\> Get-Alias | Where-Object { $_.description -eq 'MrEd_Alias'}

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           AddComputer                                         Add-Computer
Alias           AddContent                                          Add-Content
Alias           AddHistory                                          Add-History

You might be wondering: “We just added a bunch of new aliases. Will we run out of space?” The answer is: Yes, it is possible. The $maxAliasCount variable is set to 4096, but you can change that value if you need to. It is unlikely that you will need to modify this value. We still have plenty of room as shown here:

PS C:\> $MaximumAliasCount
4096
PS C:\> Get-Alias | Measure-Object

Count    : 374
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

PS C:\>

Of course, BW, our Windows PowerShell profile is really beginning to take shape at this point. We will add to our profile tomorrow as Windows PowerShell Profile Week continues.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, keep on scripting!
 

Ed Wilson and Craig Liebendorfer, Scripting Guys