Category Archives: Quick Learn

Practical examples of PowerShell concepts gathered from specific projects, forum replies, or general PowerShell use.

Implicit Remoting and the Exchange Cmdlets

I work in an environment where we administer Microsoft Exchange 2010 and I’m proud to say that I don’t have the Exchange Management Tools installed on my laptop. Now, that doesn’t mean I don’t sometimes RDP into an Exchange box, but it does force me to forgo that and use Windows PowerShell when I want to do something quicker than to RDP, log on, and open the EMC. One of the first things I added to my $PROFILE, after writing it for use in a script, was a function that would establish a PSSession to one of the Exchange servers. This allows me to run Exchange-specific cmdlets without leaving my laptop and without having the Exchange Management Tools installed.

The first thing I started with was an empty function that I called New-ExchangeSession.

Function New-ExchangeSession {

}

I had a few requirements for this project. One, I didn’t want to rely on connecting to the same Exchange server each time I created a PSSession. If for some reason it wasn’t available, I would have a problem connecting… in addition to a non-responsive Exchange server. Two, I didn’t want to hard code my Exchange server list in either my script (bad!) or in an external file (not as bad, but not great). What I did was make use of the Get-ADGroupMember and the Get-Random cmdlets to return the names of the Exchange Servers from an Active Directory group in which they were all members, and then randomly select one.

I did this as part of Do-Until loop. In line 3, the first thing it does is acquire the members of the group, ExchangeServers, using the Get-ADGroupMember cmdlet included in the Active Directory module. If you’re running PowerShell 3.0 or greater it will load this module automatically. If you’re not, then you’ll have to add it yourself using the Import-Module cmdlet before beginning the Do-Until loop.

Using dotted notation (.Name) we return only the Name property of the group members. Once collected, the Get-Random cmdlet is used to randomly select one of the names and then assign it to the $ExchServ variable.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-Random (Get-ADGroupMember -Identity 'ExchangeServers').Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)
}

If you’re using something older than 3.0, and you really shouldn’t be, you’ll find the dotted notation version just doesn’t work as expected. In that case, you will have to handle this in a more procedural way as seen in the example below. Regardless of which way you get a server name and assign it to the $ExchServ variable, it must reply to a ping, by use of the Test-Connection cmdlet in line 5 above, and line 7 below. This is the conditional check of Do-Until loop. If Test-Connection returns True, it will break out of the Do-Until. If it returns False, it will randomly select another server and try again.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-ADGroupMember -Identity 'ExchangeServers'
        $ExchServ = Get-Random $ExchServ
        $ExchServ = $ExchServ.Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)
}

We start to create the PSSession once we have an Exchange server name chosen and verified it is reachable across the network. This is done by creating a variable, $Session on line 7 below, that will store the session information. We then use that session information as part of our Import-PSSession cmdlet that brings the Exchange cmdlets down to our local computer. The final, informational message on line 9 simply indicates the Exchange server in which we’ve connected.

Function New-ExchangeSession {
    Do {
        $ExchServ = Get-Random (Get-ADGroupMember -Identity 'ExchangeServers').Name
    }
    Until (Test-Connection -ComputerName $ExchServ -Count 1 -Quiet)

    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$ExchServ.mydomain.com/powershell" -Authentication Kerberos
    Import-PSSession -Session $Session -CommandName * -FormatTypeName * | Out-Null
    Write-Output "Connected to $ExchServ"
}

You will often, if not always, receive a warning about some of the imported commands may have unapproved verbs. To view your active session, use the Get-PSSession cmdlet, and to close the session, use the Remove-PSSession -Id  #, where # equals the Id number returned from the Get-PSSession cmdlet.

Find Time between Two Dates

This post will show two ways to determine the time span between two datetimes.

Earlier this year we performed a data migration to our data center. One of the Assistant Directors sent me an instant message first thing on a Monday morning to ask if the migration was complete. I had read that it completed earlier that morning and so I replied with the time at which it ended. The second question was how long the entire data migration took. I knew it started at 11 a.m. on Friday and that it completed at 7:21 a.m. on Monday. I could have done this in my head (11 a.m. Friday to 11 a.m. Monday equals 3 days, minus 4 hours, etc.) but I trust Windows PowerShell with dates, times, and time spans more than I do myself.

The first thing I did was assign a variable, $StateDate, with the date and time when the data migration started. After testing to see it held the proper date and time, I created a second variable, $EndDate, and assigned it the date and time when the data migration ended. I also checked that it stored the correct date and time before moving on.

PS C:\> $StartDate = Get-Date '5/9/2014 11:00:00 AM'
PS C:\> $StartDate

Friday, May 09, 2014 11:00:00 AM

PS C:\> $EndDate = Get-Date '5/12/2014 07:21:00 AM'
PS C:\> $EndDate

Monday, May 12, 2014 7:21:00 AM

I was aware of the New-TimeSpan cmdlet, which we’ll use below, but I wondered if I could simply subtract the start date (the smaller date and time) from the end date (the larger date and time). I tried and it worked! Two days, 20 hours, 21 minutes.

PS C:\> $EndDate - $StartDate

Days              : 2
Hours             : 20
Minutes           : 21
Seconds           : 0
Milliseconds      : 0
Ticks             : 2460600000000
TotalDays         : 2.84791666666667
TotalHours        : 68.35
TotalMinutes      : 4101
TotalSeconds      : 246060
TotalMilliseconds : 246060000

Here’s an example of using the New-TimeSpan cmdlet. Using this cmdlet may be easier, as to not confuse which date to subtract from which.

PS C:\> New-TimeSpan -Start $StartDate -End $EndDate

Days              : 2
Hours             : 20
Minutes           : 21
Seconds           : 0
Milliseconds      : 0
Ticks             : 2460600000000
TotalDays         : 2.84791666666667
TotalHours        : 68.35
TotalMinutes      : 4101
TotalSeconds      : 246060
TotalMilliseconds : 246060000

I didn’t want anything more returned to me other than the days, hours, and minutes. I piped my results from the New-TimeSpan cmdlet to the Select-Object cmdlet and specified the properties I wanted returned. The output wasn’t great (see the final example on this page) and so I took those results and piped them to the Format-List cmdlet.

PS C:\> New-TimeSpan -Start $StartDate -End $EndDate | Select-Object Days,Hours,Minutes | Format-List

Days    : 2
Hours   : 20
Minutes : 21

Here’s how I finished up. I created a new variable, $TimeSpan, and assigned it the results of the New-TimeSpan cmdlet piped the Select-Object cmdlet. Before going any further, I tested that the variable’s value was storing what I wanted. Once I was sure the  variable contained what I wanted, I modified it a bit and sent it to the clipboard so it could be easily pasted into my instant messenger program.

PS C:\> $TimeSpan = New-TimeSpan -Start $StartDate -End $EndDate | Select-Object Days,Hours,Minutes
PS C:\> $TimeSpan

                                   Days                                   Hours                                 Minutes
                                   ----                                   -----                                 -------
                                      2                                      20                                      21

PS C:\>"$($TimeSpan.Days) Days, $($TimeSpan.Hours) Hours, $($TimeSpan.Minutes) Minutes" | clip

Formatting Decimal and Whole Numbers

This post will show how to use some simple logic and formatting to display only two decimal places with decimal numbers, and no decimal places with whole numbers.

I recently updated a game I wrote in Windows PowerShell called, “The 1 to 100 Game.” In this game, a person tries to guess a number between 1 and 100 that has been chosen by the computer (or rather, the advanced function). The computer will offer hints, as to whether the number it has chosen, is higher or lower than what was last guessed by the person playing the game. This person continues to guess until they correctly match the number. You can find the advanced function on the Microsoft TechNet Gallery here: http://gallery.technet.microsoft.com/The-1-to-100-Game-5288e279. While it’s not my most popular advanced function, I enjoyed the project, and especially when I shared it with my son as the 1 to 100 Game is one of the many games we play during our longer car rides. Oh, and if you’re looking for an example of nested do-while language constructs, then look no further – it’s up to three now.

During the rewrite to version 2.0, I decided to add something new. The game records the number of attempts it takes to guess the correct number, and how many games you’ve played. With that type of information, it can easily calculate the average number of attempts per game. This won’t always be a whole number and so I needed a way to only use two decimal places when decimal numbers were returned, and to use no decimal places when whole numbers were returned.

We can format our decimal numbers to only use two decimal places by using the -f Format operator. In the example below, we take a number that has four decimal places and specify that it is formatted to only use two decimal places.

PS C:\> $x = 100.9851
PS C:\> $x
100.9851
PS C:\> '{0:N2}' -f $x
100.99 #We want this, and notice the rounding!

In the next example, we have a whole number. If we use the -f Format operator on this number it will also show two decimal places. This isn’t what we want – we want to leave whole numbers the way they are and not add any decimal places.

PS C:\> $x = 150
PS C:\> $x
150
PS C:\> '{0:N2}' -f $x
150.00 #We don't want this!

Formatting decimal numbers, and leaving whole numbers alone, is going to require some conditional logic (If-Else statement) along with modulus division. Modulus division returns the remainder of a division operation. Here are some examples using the division operator (/) and the modulus operator (%).

PS C:\> 10 / 2
5
PS C:\> 10 % 2
0
PS C:\> 10 / 3
3.33333333333333
PS C:\> 10 % 3
1
PS C:\> 10 / 7
1.42857142857143
PS C:\> 10 % 7
3

When zero is returned from a modulus division operation, it means that the division operation did not result in a remainder. This is a great way to handle whether or not a number should or should not be formatted. In the example below, the modulus division operation on line 3 returns zero. Since zero is equal (-eq) to zero, then $a is divided by $b on line 4.

$a = 10
$b = 2
If ($a % $b -eq 0) {
    $a / $b
} Else {
    '{0:N2}' -f ($a / $b)
}
5

In this example, the modulus division operation does not return zero. Therefore, the else statement is called on line 5. On line 6, $a is divided by $b and then formatted to two decimal places. The parenthesis around ($a / $b)  indicates to PowerShell to divide first, and then do the formatting.

$a = 10
$b = 3
If ($a % $b -eq 0) {
    $a / $b
} Else {
    '{0:N2}' -f ($a / $b)
}
3.33

about_Variables

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)

A variable in Windows PowerShell is a storage container in memory that can hold a value or values. Variables can store numbers, letters, strings (a sequence of numbers, letters, and/or other characters), and the results of a command that has been run in Windows PowerShell. Variables are defined by a dollar sign ($) and a string of text that follows.

PS C:\> $myVariable
PS C:\> $Process
PS C:\> $UserName
PS C:\> $a
PS C:\> $Var

Windows PowerShell has three types of variables. There are user-created variables, automatic variables, and preference variables. User-created variables are created by a user such as the variables in this example.

PS C:\> $Name = 'Macy Jones'
PS C:\> $Number = 10

Automatic variables store the state of Windows PowerShell, such as the $PSHOME variable, which stores the install location of Windows PowerShell. This type of variable cannot be changed by a user. This example shows what happens when a user tries to change the value of the $PSHOME automatic variable.

PS C:\> $PSHOME
C:\Windows\System32\WindowsPowerShell\v1.0
PS C:\> $PSHOME = 'C:\Windows'
Cannot overwrite variable PSHOME because it is read-only or constant.
At line:1 char:1
+ $PSHOME = ‘C:\Windows’
+ ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (PSHOME:String) [], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotWritable

Preference variables store a default value but can be changed. These types of variables include the $MaximumAliasCount variable that stores the maximum number of aliases Windows PowerShell will store (the default value for this variable is 4096). This example shows how this variable’s value can be changed.

PS C:\> $MaximumAliasCount
4096
PS C:\> $MaximumAliasCount = 2000
PS C:\> $MaximumAliasCount
2000
PS C:\> $MaximumAliasCount = 4096

Variables are created by combining a dollar sign ($) and a text string. It is beneficial to name variables in such a way that the name helps define what the variable will store. Then use the = operator to assign, or set, the variable with a value. This example shows two variables, $Name and $Number, being set to two different values. To display the value assigned to a variable, type a dollar sign and the variable name and press Enter.

PS C:\> $Name = 'Macy Jones'
PS C:\> $Number = 10
PS C:\> $Series = 1,2,3
PS C:\> $Name
Macy Jones
PS C:\> $Number
10
PS C:\> $Series
1
2
3

The variable’s values can also be displayed using the Write-Output cmdlet, as well as the aliases for Write-Output, write and echo. This is used more often in scripts as opposed to the Windows PowerShell console.

PS C:\> Write-Output $Name
Macy Jones
PS C:\> write $Name
Macy Jones
PS C:\> echo $Name
Macy Jones

While the Write-Host cmdlet can also display a variable’s value, in most cases, it should not be used in place of Write-Output.

PS C:\> Write-Host $Name
Macy Jones

Variable names are not case-sensitive. The case of a variable name does not matter when it is assigned or used. This example also indicates how to assign a new value to a variable that already had a value.

PS C:\> $name
Macy Jones
PS C:\> $NAME
Macy Jones
PS C:\> $NamE
Macy Jones
PS C:\> $NAME = 'Lance Andrews'
PS C:\> $name
Lance Andrews
PS C:\> $name = 'Macy Jones'
PS C:\> $NAMe
Macy Jones

Variables can hold the results of commands. The first part of this example uses the Get-Process cmdlet to immediately display the first four running processes. In the second part of the example, the first four running processes are stored in a variable and then displayed when the variable is entered.

PS C:\> Get-Process | Select-Object -First 4

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    224      19     3436        772   110    16.80   4612 ALMon
    164      14     2476       2100    44     5.53   2744 ALsvc
     77       9     1336       5288    75   140.70   4076 ApMsgFwd
     90       8     1372       5852    76   162.11   4324 ApntEx

PS C:\> $Processes = Get-Process | Select-Object -First 4
PS C:\> $Processes

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    224      19     3436        772   110    16.80   4612 ALMon
    164      14     2476       2100    44     5.53   2744 ALsvc
     77       9     1336       5288    75   140.73   4076 ApMsgFwd
     90       8     1372       5852    76   162.11   4324 ApntEx

This examples sets, or assigns, the $Date variable to the results of the Get-Date cmdlet.

PS C:\> $Date = Get-Date
PS C:\> $Date

Thursday, May 01, 2014 9:20:30 PM

The Clear-Variable cmdlet, or clv alias, in this example, will remove the value that has been assigned to a variable without destroying, or removing, the variable itself. When referencing the variable, the dollar sign ($) is not used with either of these two cmdlets or with the Get-Variable cmdlet. The Get-Variable cmdlet will list all the variables in the session or list a single variable when a variable name is supplied.

PS C:\> $Name
Macy Jones
PS C:\> Clear-Variable Name
PS C:\> $Name
PS C:\> Get-Variable Name

Name                           Value
----                           -----
Name

The Remove-Variable cmdlet, or rv alias, in this example, will completely remove a variable and its stored value from memory.

PS C:\> $Color = 'Green'
PS C:\> $Color
Green
PS C:\> Remove-Variable Color
PS C:\> $Color
PS C:\>
PS C:\> Get-Variable Color
Get-Variable : Cannot find a variable with the name ‘Color’.
At line:1 char:1
+ Get-Variable Color
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Color:String) [Get-Variable], ItemNotFoundException
    + FullyQualifiedErrorId : VariableNotFound,Microsoft.PowerShell.Commands.GetVariableCommand

Variables can store different types of data. Normally they make their type determination based on the value(s) assigned to them. They can store integers, strings, arrays, and more. A single variable, when it is an array, can contain different types of data at the same time. The examples below use the Get-Member cmdlet to return properties (and more) about our variable. The Select-Object cmdlet has also been used to help filter what is returned.

PS C:\> $a = 12
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.Int32

PS C:\> $a = 'Word'
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.String

PS C:\> $a = 12,'Word'
PS C:\> $a | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.Int32
System.String

A variable can be forced to be a certain type by casting the variable. In the first part of the example below, the variable $Number will be cast with an int type (int, as in, integer). Even though the variable is cast as an integer, it is able to handle being assign a string value of “12345.” This is because the variable can change that string into a numeric value. It cannot do the same thing with the string “Hello.”

Further down in the example, the $Words variable has been cast as a string. When it is set to a numeric value it converts the numeric value into a string value. If the variable is used in a mathematical equation, such as an addition equation, it does not add the two values and instead will concatenate, or join them.

PS C:\> [int]$Number = 10
PS C:\> $Number
10
PS C:\> $Number = '12345'
PS C:\> $Number
12345
PS C:\> $Number = 'Hello'
Cannot convert value “Hello” to type “System.Int32”. Error: “Input string was not in a correct format.”
At line:1 char:1
+ $Number = ‘Hello’
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
PS C:\> [string]$Words = 'Hello'
PS C:\> $Words
Hello
PS C:\> $Words = 2
PS C:\> $Words
2
PS C:\> $Words + 10
210
PS C:\> $Number
12345
PS C:\> $Number + 10
12355

There are differences between using single quotes–which should be used as often as possible–and double-quotes. Single quotes around a variable will not expand the value stored in the variable; however, using double quotes will expand the variable.

PS C:\> $Name = 'Macy Jones'
PS C:\> 'Her name is $Name'
Her name is $Name
PS C:\> "Her name is $Name"
Her name is Macy Jones

Although variable names can include spaces and special characters, it should be avoided as it can quickly lead to confusion. Using spaces and special characters requires the variable name be enclosed in curly brackets {}.

PS C:\> ${!@#$} = 'Monday'
PS C:\> ${Favorite Day} = 'Friday'
PS C:\> ${!@#$}
Monday
PS C:\> ${Favorite Day}
Friday

Windows PowerShell creates a variable drive that looks and acts a lot like a file system drive. You can access data in the variable drive the same way things are accessed in a file system. The first example uses Get-ChildItem to get the first 4 folders in C:\Windows. The second example does the same thing but instead returns the first four variables in the variable drive.

PS C:\> Get-ChildItem C:\Windows | select -First 4

    Directory: C:\Windows

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         11/5/2013   3:31 PM            ADAM
d----         7/13/2009  10:32 PM            addins
d----         7/13/2009   8:20 PM            AppCompat
d----         4/11/2014   5:22 PM            AppPatch

PS C:\> Get-ChildItem variable:\ | select -First 4

Name                           Value
----                           -----
!@#$                           Monday
$                              4
?                              True
^                              Get-ChildItem

The only other variable cmdlet that was not discussed is the New-Variable cmdlet. This cmdlet is often not used since a variable can be created without it. The first example below shows how to return all the variable-related cmdlets. The second example shows how to use New-Variable.

PS C:\> Get-Command *-Variable

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Clear-Variable                                     Microsoft.PowerShell.Utility
Cmdlet          Get-Variable                                       Microsoft.PowerShell.Utility
Cmdlet          New-Variable                                       Microsoft.PowerShell.Utility
Cmdlet          Remove-Variable                                    Microsoft.PowerShell.Utility
Cmdlet          Set-Variable                                       Microsoft.PowerShell.Utility

PS C:\> New-Variable -Name DaysInYear -Value 365
PS C:\> $DaysInYear
365

Bonus Information

There may come a time when two (or more) variables need to be set to the same value. These do not need to be set individually. This first example shows how to set two variables at the same time and the second example shows how to set three variables at the same time.

PS C:\> $a = $b = 'Windows PowerShell'
PS C:\> $a
Windows PowerShell
PS C:\> $b
Windows PowerShell
PS C:\> $x = $y = $z = 42
PS C:\> $x
42
PS C:\> $y
42
PS C:\> $z
42

Real World

When values of a variable are displayed in the console, it will very rarely follow the Write-Output cmdlet. This cmdlet is most often used in scripts than it is with commands written in the console.

Learn More

This information, and more, are stored in the help file about_Variables 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_variables
PS C:\> Get-Help about_variables -ShowWindow
PS C:\> Get-Help about_variables| clip
PS C:\> Notepad $PSHOME\en-us\about_Variables.help.txt

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

Change the Console Window Title – Part 1

This post will introduce the $Host automatic variable, its properties, and how we can use it to display the date in the Window PowerShell console’s window title.

The $Host variable is an automatic variable and an automatic variable in Windows PowerShell stores “state information” about the PowerShell session. These types of variables are created and maintained by PowerShell. The example below shows the properties of the $Host automatic variable. We can return this same information by also using the Get-Host cmdlet, as seen in the second example.

PS C:\> $Host

Name             : ConsoleHost
Version          : 3.0
InstanceId       : 30d047c2-0565-4947-8f34-7ff2b42d3590
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

PS C:\> Get-Host

Name             : ConsoleHost
Version          : 3.0
InstanceId       : 30d047c2-0565-4947-8f34-7ff2b42d3590
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

Note: Please not use the $Host variable, or the Get-Host cmdlet, to determine the installed version of Windows PowerShell. This variable does not return the version of Windows PowerShell; it returns the version of the host. To determine the version of Windows PowerShell use the $PSVersionTable variable and the PSVersion property.

The UI property in the previous examples has several words separated by dots. This means that the UI property is actually a collection. In most cases, a collection stores a collection of properties. The example below shows how to enumerate the UI property so we can see the properties contained in this collection.

PS PS C:\> $Host.UI

RawUI
-----
System.Management.Automation.Internal.Host.InternalHostRawUserInterface

Wait, what? The UI collection contained RawUI – another collection. After further enumeration, this collection returns several properties. At the bottom of property list is, a property called, “WindowTitle.” This property stores the value used in the window title of the PowerShell console.

PS C:\> $Host.UI.RawUI

ForegroundColor       : DarkYellow
BackgroundColor       : DarkMagenta
CursorPosition        : 0,1
WindowPosition        : 0,0
CursorSize            : 25
BufferSize            : 120,3000
WindowSize            : 120,50
MaxWindowSize         : 120,85
MaxPhysicalWindowSize : 240,85
KeyAvailable          : False
WindowTitle           : Administrator: Windows PowerShell

In the image below, the window title accurately matches what is stored in this property.

Windows PowerShell Console Window Title 05 - Part 1

The title can be changed by assigning a different value to the property $Host.UI.RawUI.WindowTitle. In this example, the window title changes instantly when we assign a new value to the property.

PS C:\> $Host.UI.RawUI.WindowTitle = 'The new and improved title!'
PS C:\>

Windows PowerShell Console Window Title 06 - Part 1

Our goal is to keep the default value, Administrator: Windows PowerShell, append a space, and then the date, inside square brackets. We want it to look like this, “Administrator: Windows PowerShell: [06/19/2014].” To reset the value to its default, close the current PowerShell console and then open a new PowerShell console. Think about that for a moment… This value is going to reset itself to the default value every time a new PowerShell session is created, such as when a new console window is opened. We will discuss this more in a moment.

In the next two examples, the value of $Host.UI.RawUI.WindowTitle is changed by concatenating the date, the space, and those brackets, to the already existing value of this property. Notice that we do this using the += assignment operator. These two examples do the exact same thing.

PS> $Date = Get-Date
PS> $Host.UI.RawUI.WindowTitle += " [$Date]"
PS>

Windows PowerShell Console Window Title 07 - Part 1

PS C:\> $Host.UI.RawUI.WindowTitle += " [$(Get-Date)]"
PS C:\>

Windows PowerShell Console Window Title 08 - Part 1

The time indicates the time in which the PowerShell session started – pretty useless. Using the ToShortDateString method returns the date without the time. Both of the next two examples do the same thing.

PS C:\> $Date = (Get-Date).ToShortDateString()
PS C:\> $Host.UI.RawUI.WindowTitle += " [$Date]"
PS C:\>
PS C:\> $Host.UI.RawUI.WindowTitle += " [$((Get-Date).ToShortDateString())]"
PS C:\>

Windows PowerShell Console Window Title 09 - Part 1

As I mentioned previously, the value that is stored in $Host.UI.RawUI.WindowTitle returns to its default each time a new Windows PowerShell session is opened. In order for this to stick, it needs to be added to a profile. A profile runs each time you start a new PowerShell session. If you’re not already using a profile, then it’s time to begin. Start by reading this article: http://technet.microsoft.com/en-us/library/ee692764.aspx and then follow that up by reading the help file: Get-Help about_Profiles.

Edit: You can also read the recently added Help Rewrite for about_Profiles here: http://tommymaynard.com/hr-about_profiles/

PS C:\> Get-Help about_Profiles

That is all there is to change the Windows PowerShell console’s window title to the current date. Watch for an upcoming post that will help determine how to update the date if the Windows PowerShell session is open for more than one day.