Tag Archives: Select-Object

Return File Sizes in Bytes, KBs, MBs, and GBs, at the Same Time

I scanned a recent forum post on PowerShell.org where the user seemed (again, I scanned it) to want to run some files through Get-ChildItem and Select-Object, and report the size in something other than the bytes default. It didn’t appear he, or she, wanted all the files in one of the measurement groups: B, KB, MB, or GB, but instead in their proper measurement group, dependent on the file’s size.

That may be hard to understand at first read, so let me try and explain it another way. If a file has less than 1,024 bytes, then it should be reported in bytes, if it has 1,024 – 1,048,575 bytes, then it should be reported in Kilobytes, if it has 1,048,576 – 1,073,741,824 bytes then it should be reported Megabytes, and if it has 1,073,741,825 or more bytes, then it should be reported in Gigabytes.

I wrote a long, “one-liner” to do this and have included it, and some sample output, below. I don’t profess to guarantee this doesn’t have any errors, so if you find some, then let me know. In addition, it shows a nice example of a switch statement inside the Expression portion of a calculated property. Fancy.

Get-ChildItem -Path 'C:\test' |
    Select-Object Name,
        @{L='Size';E={
                switch ($_.Length) {
                    # Bytes
                    {$_ -eq 0} {"$('{0:N2}' -f $_) bytes"; break}
                    {$_ -eq 1} {"$('{0:N2}' -f $_) byte"; break}
                    {($_ -gt 1) -and ($_ -le 1023)} {"$('{0:N2}' -f $_) bytes"; break}

                    # Kilobytes
                    {$_ -eq 1024} {"$('{0:N2}' -f ($_/1KB)) Kilobyte"; break}
                    {($_ -gt 1024) -and ($_ -le 1048575)} {"$('{0:N2}' -f ($_/1KB)) Kilobytes"; break}

                    # Megabytes
                    {$_ -eq 1048576} {"$('{0:N2}' -f ($_/1MB)) Megabyte"; break}
                    {($_ -gt 1048576) -and ($_ -le 1073741824)} {"$('{0:N2}' -f ($_/1MB)) Megabytes"; break}

                    # Gigabytes
                    {$_ -eq 1073741825} {"$('{0:N2}' -f ($_/1GB)) Gigabyte"; break}
                    {$_ -gt 1073741825} {"$('{0:N2}' -f ($_/1GB)) Gigabytes"; break}

                    default {Write-Warning -Message 'Unknown Error.'}
                }
            }
        } | Format-Table -AutoSize

Name           Size
----           ----
My-A-File.txt  1.00 byte
My-A-File2.txt 445.00 bytes
My-B-File.txt  1.00 Kilobyte
My-B-File2.txt 1.30 Kilobytes
My-C-File.txt  2.09 Megabytes
My-D-File.txt  3.59 Gigabytes

I can easily see how someone might want to remove the singular vs. plural: Kilobyte vs. Kilobytes, and just use B, KB, MB, and GB, and so…

Update: I gave this some more thought today, and I really didn’t feel like it was okay to not include a modified version that uses abbreviations (B, KB, MB, GB) instead of the full words, as in the previous example. It has removed some complexity, as well, as you can see below.

Get-ChildItem -Path 'C:\test' |
    Select-Object Name,
        @{L='Size';E={
                switch ($_.Length) {
                    # Bytes
                    {($_ -ge 0) -and ($_ -le 1023)} {"$('{0:N2}' -f $_) B"; break}

                    # Kilobytes
                    {($_ -ge 1024) -and ($_ -le 1048575)} {"$('{0:N2}' -f ($_/1KB)) KB"; break}

                    # Megabytes
                    {($_ -ge 1048576) -and ($_ -le 1073741824)} {"$('{0:N2}' -f ($_/1MB)) MB"; break}

                    # Gigabytes
                    {$_ -ge 1073741825} {"$('{0:N2}' -f ($_/1GB)) GB"; break}

                    default {Write-Warning -Message 'Unknown Error.'}
                }
            }
        } | Format-Table -AutoSize

Name           Size
----           ----
My-A-File.txt  1.00 B
My-A-File2.txt 445.00 B
My-B-File.txt  1.00 KB
My-B-File2.txt 1.30 KB
My-C-File.txt  2.09 MB
My-D-File.txt  3.59 GB

Give your Variable a Description

When we think of variables in Windows PowerShell, we often only consider two parts: the name of the variable, and the value of the variable. Well, it turns out that those aren’t the only properties; let’s discuss the description property.

I can’t say I’ve ever added a description to a variable until now, but I can think of times, when looking at someone’s code, where I wish I knew the reason why a variable existed. Best practice would indicate we use meaningful names for our variables, so it’s probably safe to assume that the same people that might use a poorly-named variable, probably don’t know or care that variables can have descriptions… but, I digress.

In this first example, we’ll create a new variable using what I’d call the standard method — the equal sign assignment operator.

PS C:\> $a = 12345
PS C:\> $a
12345
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description :
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

In line 1, we created a new variable, $a, and set its value to the numeric 12345. In the next line, we simply echoed the variable’s value. In line 4, we used the Get-Variable cmdlet and piped it to the Select-Object cmdlet and * so we were able to view all of its properties. If you take a look at the results, you’ll see the description property, and notice that it’s currently blank.

In the next example, we’ll use the Set-Variable cmdlet to modify the variable’s description.

PS C:\> Set-Variable a -Description 'This variable contains a 5-digit number.'
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description : This variable contains a 5-digit number.
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

PS C:\>

Once we use the Get-Variable cmdlet, and return all the properties again, we can see that our variable now contains a description value. Now, while many user-defined variables, such as we created here, don’t often contain descriptions, many of the automatic and preference variables do — take a look at a segment of the results returned by the next command.

PS C:\> Get-ChildItem variable: | Select-Object Name,Description | Format-Table -AutoSize

Name                       Description
----                       -----------
...
MaximumAliasCount          Maximum number of aliases allowed in a session
MaximumDriveCount          Maximum number of drives allowed in a session
MaximumErrorCount          Maximum number of errors to retain in a session
MaximumFunctionCount       Maximum number of functions allowed in a session
MaximumHistoryCount        Maximum number of history objects to retain in a session
MaximumVariableCount       Maximum number of variables allowed in a session
MyInvocation
NestedPromptLevel          Dictates what type of prompt should be displayed for the current nesting level
...

Well, there you go: something you might not have known about, and something you may never use.

Get Some Help for Later Reading

I’m just starting to get my hands wet with Microsoft Lync. As I often do, I use the Windows PowerShell cmdlets to help learn more about a product; I did this same thing with Hyper-V. The unfortunate thing about the GUI (think, an MMC snap-in for instance), is that the menu options don’t always tell you exactly what that option is going to do, or its exact purpose. While the GUI can be unclear, PowerShell tells you exactly what a cmdlet does. With that knowledge, I’ve often been able to relate a cmdlet, and its purpose, to its respective menu option in the GUI.

I wanted to read though the Lync cmdlet’s help files, but only the cmdlet name and its synopsis. Here’s the command I ran to extract this information for later reading.

PS C:> Get-Command -Module Lync | Get-Help | Select-Object Name,Synopsis | Export-Csv -Path C:\LyncCmdlets.csv -NoTypeInfomation

The command above works this way: it returns all the cmdlets included in the Lync Module and sends (pipes) those to the Get-Help cmdlet. The Get-Help cmdlet pipes its results to Select-Object which filters the returned properties to just the Name and Synopsis from each cmdlet’s help file. At the end, those filtered results are sent to Export-Csv which creates a file I can read at my leisure.

Although there’s over 500 cmdlets, it’s safe to say that many of the nouns (the part after the dash [-]) will be the same across some of the cmdlets. That means that many of the Get-* cmdlets will have a partnering Set-* cmdlet. Get reads information and Set changes it. These nouns may also have a matching New-*, Remove-*, and possibly even a Test-* cmdlet. Now off to do some reading…

What PowerShell Modules does the RSAT Provide (on Windows 8.1)

I built a new Windows 8.1 machine recently, and as we all know, doing that requires new software installations. In my case, that included the RSAT. The RSAT, or Remote Server Administration Tools, allow IT admins the ability to remotely manage features on Windows Server operating systems from a client operating system—here’s a link to the RSAT for Windows 8.1.

Prior to running the RSAT installer, I wanted to collect the currently available Windows PowerShell modules that I already had on my computer. This would allow me to know exactly what modules were added after the RSAT installer finished. The command below collects all the modules, returns only their name, and then drops that into a file on my computer. We’ll use the file in a moment, as part of a comparison.

PS C:\> Get-Module -ListAvailable | Select-Object -ExpandProperty Name | Out-File C:\Users\tommymaynard\Pre-RSAT-PowerShell-Modules.txt

I verified the file contained the module names by using the Get-Content cmdlet. In addition, I ran a slightly modified command to get the item count in the file—both can be seen below. The output created by the first command has been truncated to save space.

PS C:\> Get-Content C:\Users\tommymaynard\Pre-RSAT-PowerShell-Modules.txt
AppBackgroundTask
AppLocker
Appx
AssignedAccess
...
PS C:\> (Get-Content C:\Users\tommymaynard\Pre-RSAT-PowerShell-Modules.txt).Count
57

Once this file was in placed, and I was satisfied that it contained what I wanted, I went ahead with the RSAT install. Upon completion, I reran the Get-Module command above, after modifying the name of the file it would create (pre vs. post). I then read in the contents of the new file (which has been truncated again), and checked the number of modules listed in the file. There were now 75 modules where there had only been 57 before the RSAT install.

PS C:\> Get-Module -ListAvailable | Select-Object -ExpandProperty Name | Out-File C:\Users\tommymaynard\Post-RSAT-PowerShell-Modules.txt
PS C:\> Get-Content C:\Users\tommymaynard\Post-RSAT-PowerShell-Modules.txt
ActiveDirectory
AppBackgroundTask
AppLocker
Appx
...
PS C:\> (Get-Content C:\Users\tommymaynard\Post-RSAT-PowerShell-Modules.txt).Count
75

Knowing that there’s 18 new modules is helpful, but which ones were added? The Compare-Object cmdlet can tell us. As seen below, we have the cmdlet read in the lines of each file and then determine which ones aren’t included in both files.

PS C:\> Compare-Object -ReferenceObject (Get-Content C:\Users\tommymaynard\Desktop\Pre-RSAT-PowerShell-Modules.txt) -DifferenceObject (Get-Content C:\Users\tommymaynard\Desktop\Post-RSAT-PowerShell-Modules.txt)

InputObject                                                 SideIndicator
-----------                                                 -------------
ActiveDirectory                                             =>
BestPractices                                               =>
ClusterAwareUpdating                                        =>
DFSN                                                        =>
DFSR                                                        =>
DhcpServer                                                  =>
DnsServer                                                   =>
FailoverClusters                                            =>
GroupPolicy                                                 =>
IpamServer                                                  =>
IscsiTarget                                                 =>
NetworkLoadBalancingClusters                                =>
NFS                                                         =>
RemoteAccess                                                =>
RemoteDesktop                                               =>
ServerManager                                               =>
ServerManagerTasks                                          =>
UpdateServices                                              =>

As we can see above, our Compare-Object results indicate that the difference object (the post file, or the file on the right) has new modules—now we know which ones were added since installing the RSAT.

Write-Host, Does it Have a Place?

I’ve been working on an advanced function that I can’t wait to share (and no, it’s not the one in this post). I really think it’s something that the Windows PowerShell community has been missing. Okay fine, maybe it’s just something I’ve been missing.

I noticed in development that my Write-Output messages to the user were crossing the pipeline, when the custom object (created by the function), was passed to Select-Object (in certain manners). I have a function below that does the same thing as the one in development.

Here’s how this thing works: The function requires the user to provide the value Write-Output (or, wo), or Write-Host (or, wh) for the -Option parameter. This will determine how the message to the user is written inside the Begin block. The only other thing that’s happening in this function, is that a custom object is being created in the Process block, based on some properties of Win32_BIOS.

Function Test-TMWriteOutputVsHost {
    [CmdletBinding()]
    Param (
    [Parameter(Mandatory=$true,
        HelpMessage="Enter Write-Output or Write-Host")]
    [ValidateSet('Write-Output','wo','Write-Host','wh')]
    [string]$Option
    )

    Begin {
        If ($Option -eq 'Write-Output' -or $Option -eq 'wo') {
            Write-Output 'Inside the Begin block (using Write-Output).'

        } ElseIf ($Option -eq 'Write-Host' -or $Option -eq 'wh') {
            Write-Host 'Inside the Begin block (using Write-Host).'
        }
    } # End Begin

    Process {
        $CollectionVariable = Get-WmiObject -Class Win32_BIOS
        $Object = @()
        $Object += [pscustomobject]@{
            Manufacturer = $CollectionVariable.Manufacturer;
            Name = $CollectionVariable.Name;
            Version = $CollectionVariable.Version
        }
    } # End Process

    End {
        Write-Output $Object
    }
    # End, End
} # End Function

As we can see below, everything works great with both Write-Output or Write-Host, when we don’t pipe the function to the Select-Object cmdlet.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output
Inside the Begin block (using Write-Output).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

Now, let’s pipe our object to some variations of the Select-Object cmdlet and watch some things blow up (when using Write-Output).

PS C:\> # Use the horizontal scrollbar to see the results...
PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select *

                                                                                                                 Length
                                                                                                                 ------
                                                                                                                     44

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | select Name,Ver*

Name                                                        Ver*
----                                                        ----

BIOS Date: 08/27/13 11:12:44 Ver: A13.00

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select *
Inside the Begin block (using Write-Host).

Manufacturer                            Name                                    Version
------------                            ----                                    -------
Dell Inc.                               BIOS Date: 08/27/13 11:12:44 Ver: A1... DELL   - 1072009

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | select Name,Ver*
Inside the Begin block (using Write-Host).

Name                                                        Version
----                                                        -------
BIOS Date: 08/27/13 11:12:44 Ver: A13.00                    DELL   - 1072009

The problem with Write-Output, is that the object it’s producing is crossing our pipeline and causing unpredictable behavior—something we can’t include in a function we want to distribute. Here’s the proof: When we pipe our function to Get-Member, we reveal the objects that show up on the other side, and we don’t want the string object coming over with us.

PS C:\> Test-TMWriteOutputVsHost -Option Write-Output | Get-Member | Select-Object TypeName -Unique

TypeName
--------
System.String
System.Management.Automation.PSCustomObject

PS C:\> Test-TMWriteOutputVsHost -Option Write-Host | Get-Member | Select-Object TypeName -Unique
Inside the Begin block (using Write-Host).

TypeName
--------
System.Management.Automation.PSCustomObject

I don’t profess to know it all, so if there’s a way to get around this using Write-Output, then I’d love to hear about it. While I haven’t tried it, I suspect I may be able to create an embedded function—that might be the trick I need. Perhaps I’ll play with that option at another time. Thanks for reading!

Oh, and before someone mentions it, I explained how I feel about Write-Verbose in the comments on a post by Adam Bertram: http://www.adamtheautomator.com/use-write-host-lot.

Using Replace() to Fix Split() (and Convert-Path)

I was working on a recent project that required scripting ACLs, and so I had a Windows PowerShell console open in addition to the ISE. This allowed me to quickly check the owner of a directory (or folder). I could press the up arrow to rerun my command, and I could quickly see if the owner had changed according to my script. Let’s say my directory is called ‘TestFolder’ and is located at the root of the C:\ drive.

PS C:\> New-Item -Path TestFolder -ItemType Directory

    Directory: C:\

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        10/21/2014   9:19 PM            TestFolder

To get the ACL information for the folder, you can use the Get-Acl cmdlet, as in the example below.

PS C:\> Get-Acl -Path .\TestFolder

    Directory: C:\

Path                                    Owner                                   Access
----                                    -----                                   ------
TestFolder                              BUILTIN\Administrators                  BUILTIN\Administrators Allow  FullCo...

Being the PowerShell enthusiast that I am, I modified my command so that only the information I wanted (the path and the owner) was being returned. This is done using the Select-Object cmdlet. Unfortunately, when the command returned those two properties, the Path property was no longer what I was expecting – take a look below. While the example above only returned the name of the folder (TestFolder), I thought I would change this to show the full path (C:\TestFolder) since I was now dealing with a string that included it.

PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property Path,Owner

Path                                                        Owner
----                                                        -----
Microsoft.PowerShell.Core\FileSystem::C:\TestFolder         BUILTIN\Administrators

The first thing I thought to do was to split the path at the two colons (::) and grab the second element, which I thought would end up being C:\TestFolder. The split method didn’t work so well; here’s what I ended up with.

PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={($PSItem.Path).Split('::')[-1]}},Owner

Path                                                        Owner
----                                                        -----
\TestFolder                                                 BUILTIN\Administrators

The reason this didn’t work is because the Split() method doesn’t split on each occurrence of two, back-to-back colons like you might expect, it splits on every colon. Since C:\ has a colon, it split there as well. FYI: The use of [-1] returns the last element in an array – good to know, I know. Here’s an example that may help better explain. In this example below, the string is split on every exclamation point (!) and every question mark (?) – not only on the combination of both (!?).

PS C:\> $String = 'Today is the 21st! That is great news, right?'
PS C:\> $String
Today is the 21st! That is great news, right?
PS C:\> $String.Split('!?')
Today is the 21st
 That is great news, right

PS C:\>

What I then decided to do to get this the way I wanted it, was to first replace the two, back-to-back colons with a single character (that was not a part of the string), and then split on that single character. It worked, and here’s what that looks like.

PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={(($PSItem.Path).Replace('::','@')).Split('@')[-1]}},Owner

Path                                                        Owner
----                                                        -----
C:\TestFolder                                               BUILTIN\Administrators

PS C:\>

It was about this point, that I wanted to see if the -split operator would have handled this the same way and required the additional work that the Replace()/Split() methods did. Of course, after all I did to get this to work how I wanted, I determined I should have started with the -split operator. The -split operator isn’t looking at the characters individually, but instead of, as a whole – two, back-to-back colons is two back-to-back colons.

PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={(($PSItem.Path) -split '::')[-1]}},Owner

Path                                                        Owner
----                                                        -----
C:\TestFolder                                               BUILTIN\Administrators

A note, if the @{N=…;E={…}} syntax is confusing, or new to you, then spend some time reading this: http://technet.microsoft.com/en-us/library/ff730948.aspx, and then run Get-Help about_Hash_Tables.

This happens just about every time I get to ready to publish a new post. I discovered a better way to handle the problem – much like I did when I considered the -split operator.  It turns out that I could have used a built-in cmdlet to convert the path for me. That’s right, there’s a cmdlet that would have handled everything. Using the Convert-Path cmdlet will convert something like this: Microsoft.PowerShell.Core\FileSystem::C:\TestFolder to this: C:\TestFolder. Here’s the example.

PS C:\> Get-Acl -Path .\TestFolder | Select-Object -Property @{N='Path';E={Convert-Path $PSItem.Path}},Owner

Path                                                        Owner
----                                                        -----
C:\TestFolder                                               BUILTIN\Administrators

PS C:\>

Well, that’s it for this one. As much as I might seem irritated about how I did this three different ways – from the most work to the least – I understand how important this learning process is, and that one day I will be grateful for having gone down this path… (pun intended).

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