Essential PowerShell: To alias, or not to alias, that is the question

Recently there was a discussion between community experts and a product team about a module they are working on.  The topic being discussed was cmdlet aliases: whether or not they should provide aliases for their cmdlets out of the box and if so, how they should be provided.  Aliases are great for ad-hoc PowerShell work, which is what most PowerShell users do at this point, and incredibly useful when you’re trying to put out a fire and managing your infrastructure using PowerShell.  However, there are many important things that module authors need to consider when planning aliases for their cmdlets, as follows:

1. There are many cmdlets out now, and more and more every month.  Coming up with a vsa (very short alias) that is unique is a challenge at best, and the more time goes by the more tla’s (three-letter aliases) will get used up.  The likelihood of an alias conflict is already high, and increasing all the time given the number of commands that are available both from Microsoft and from third party vendors.

2. The land grab with alias names is worse than it is with functions or cmdlets.  With functions or cmdlets, you can have multiple modules loaded with conflicting names and access either command using the fully qualified command name.  With aliases though you are not provided this same capability – there can be only one.  Aliases are simply commands set to a single value and they cannot be qualified using a module name qualifier to disambiguate if a name conflict arises.

3. Depending on how careful (or not) that developers are, it is very easy for a module author to completely take over (overwrite) an existing alias with no warning or message indicating that this has happened, resulting in potential command hijacking between module teams.  A simple call to Set-Alias does this without warning.  On the flipside, if developers don’t hijack aliases, then some of the aliases they would otherwise create may simply not be defined.

4. When aliases are hijacked, unloading a module doesn’t correct the problem because an alias that was overwritten by a module alias will simply become completely unavailable when the alias is removed as the module is unloaded.

As far as I am aware, this situation does not improve with the next version of PowerShell either, so it’s years away from getting better.

Believe it or not, even with these things in mind, I’m actually still pro aliases.  I just think that some extra care/thought needs to be put into their definition.  There is no real standard here that both satisfactorily addresses the issues identified above and that allows for consistency across companies/teams at this time.  Given that is the current state of affairs, if you are considering aliases for your module I recommend one of the following approaches:

1. [SAFEST] Rather than trying to come up with something that can be shipped despite these issues, at this time I think aliases would be best addressed in a "tips and tricks" type of blog post, proposing a short script that defines some useful aliases for the module/snapin in question in order to allow admins to be able to deal with fires quickly using ad-hoc PowerShell commands via some aliases.  Such a script should generate warnings whenever a name conflict is discovered so that users are aware when an alias either cannot be created or is overwritten.

2. [EXPERIMENTAL] Ship aliases with your module, but try to make sure they really are unique.  For example, if you’re a vendor whose company name starts with Q, you could prefix all of your aliases with "q".  This is attractive because there are no verbs that start with "q", so right from the start you’ve dramatically reduced the chance that you’ll have a conflict, setting yourselves up better to have aliases that belong to you.  Then you would only have to coordinate within your company to make sure the aliases used across teams are unique.  This isn’t foolproof though because there may be multiple products/vendors that adopt the same standard, and if the name of your company or product starts with G, the likelihood of a conflict would be much higher (the alias prefix used for "get-*" cmdlets is "g") so you may want to choose a pair of letters instead.  Regardless, you’ve likely reduced the risk, and you could generate a warning whenever you run into a conflict that prevents an alias from being created.

3. [RECOMMENDED] Lots of 1 and a little bit of 2: use unique alias names that work for your product team/company, but don’t ship them with the module.  Instead, push them out as a value add on a blog post, and see how the community responds.  At the same time work with MVPs and Microsoft to get these issues addressed such that a shorthand system for command names does work.  Some MVPs, already proposed a few things to the Microsoft PowerShell team that could help here (aliases for module names for one — think PS\gsv for a core PowerShell version of Get-Service or EX\gu for the Get-User cmdlet that comes with the Microsoft Exchange module or AD\gu for the Get-User cmdlet that comes with the Microsoft Active Directory module, and so on), but more discussions need to happen and this will take more time.

I recommend the third option because given the current issues with alias hijacking and with no support for disambiguation, it seems to be the best solution for now (from my perspective at least).  If you have come up with other alternatives that resolve these issues, please share them with the community so that this improves going forward.

Hope this helps,

Kirk out.

Essential PowerShell: Know your operator and enclosure precedence

PowerShell version 1 comes with a lot of operators, and the list becomes even longer in version 2 with cool new operators like -split and -join.  Whether you’re writing scripts or using PowerShell interactively, dealing with multiple operators in an expression that possibly contains different enclosures (brackets, quotation marks, etc.) as well can be very tricky.  It is very important to know how the PowerShell interpreter processes the expression so that you can get your expressions right the first time or, if you’re not so lucky, so that you can identify the problem in your expressions later and fix them. 

Recently there have been several posts on the forums where the problem has been a lack of understanding of the operator and enclosure precedence in PowerShell.  That’s not too surprising because the precedence order used by the PowerShell interpreter doesn’t seem to be documented at this time.  You can find the precedence order of arithmetic operators through the about_arithmetic_operators help file, you can find out some precedence details for specific operators in various operator help files, and you can find out the precedence of command types through the about_command_precedence help file, but that’s about it.  There is no single help file that documents the overall operator and enclosure precedence.  It doesn’t seem to be listed in any of the PowerShell books I have read either. 

Fortunately through some ad hoc experimentation and through some reading of the help documentation that does exist it is possible to figure out how all of this works.  I’ve gone through that exercise recently and the resulting table of operator and enclosure precedence is below.  Before getting to the table though there are a few important things I should mention, as follows: 

  1. Any items that share the same row in the table have the same precedence and are evaluated from left to right when adjacent within an expression unless otherwise indicated.
  2. The intent of this table is to identify a precedence that can be used to create or troubleshoot more complicated expressions without a lot of guesswork.  It is not intended to explain what each of the operators are and how you can use them (although to help understand expressions you might have to deal with I do mention a few details about some operators that function differently than the majority of operators in PowerShell).
  3. If you want to learn about the individual operators and see examples showing how they can be used I recommend you consult the about_operators help file and all of its related files.

With that out of the way, here is the operator and enclosure precedence table for PowerShell:

[] Type enclosures
Any character placed inside of these enclosures is treated as part of a literal type name.  The contents are not evaluated like an expression would be.
” “ Double-quoted string enclosures
‘ ‘ Single-quoted string enclosures
@” “@ Double-quoted here-string enclosures
@’ ‘@ Single-quoted here-string enclosures
{} Script block enclosures
() Nested expression enclosures
@() Array subexpression enclosures
$() Subexpression enclosures
. Property dereference operator
:: Static member operator
[] Index operator
Cast operators
Multiple adjacent operators in this row have a right-to-left evaluation.
-split (unary) Split operator (unary)
-join (unary) Join operator (unary)
These operators can be used as unary or binary operators.  Their precedence varies depending on how they are used.
, Comma operator
This operator is the array element separator.  It can be used as an unary or binary operator.
++ Increment operator
– – Decrement operator
These unary operators can be used before or after a variable or property.  When used before the variable or property (as a prefix operator), the value is incremented or decremented first and then the result is passed into the expression in which it is contained.  When used after the variable or property (as a postfix operator), the value is passed into the expression in which it is contained and then the variable or property is immediately incremented or decremented.
Negate operator
-not Not operator
! Not operator
-bnot Bitwise not operator
Multiple adjacent operators in this row have a right-to-left evaluation.
.. Range operator
-f Format operator
* Multiplication operator
/ Division operator
% Modulus operator
+ Addition operator
Subtraction operator
-csplit (binary)
Split operator (binary)
-join (binary) Join operator (binary)
-is Type is operator
-isnot Type is not operator
-as Type as operator
Equal to operator
Not equal to operator
Greater than operator
Greater than or equal to operator
Less than operator
Less than or equal to operator
Like operator
Not like operator
Match operator
Not match operator
Contains operator
Does not contain operator
Replace operator
With the exception of the join operator and the type operators (-is, -isnot, and –as), each of the operators in this row has a case-sensitive and an explicit case-insensitive variant.  Case-sensitive variants are prefixed with c (e.g. -ceq) and case-insensitive variants are prefixed with i (e.g. –ireplace).
-band Bitwise and operator
-bor Bitwise or operator
-bxor Bitwise exclusive or operator
-and Logical and operator
-or Logical or operator
-xor Logical exclusive or operator
. Dot-sourcing operator
& Call operator
Unary operators that are only valid at the beginning of an expression, a nested expression, or a subexpression.
= Assignment operator
+= Assignment by addition operator
-= Assignment by subtraction operator
*= Assignment by multiplication operator
/= Assignment by division operator
%= Assignment by modulus operator
Multiple adjacent operators in this row have a right-to-left evaluation.

Since this table is created through experimentation and through snippets of information about precedence that I was able to find in the help files, it may not be entirely accurate.  If you find any problems with the precedence information provided here, please let me know and I’ll update this table accordingly. 

[Update 09-July-2009: Fixed table formatting, added an index operator, added all case-sensitive and case-insensitive variants and adjusted the precedence for the property dereference and static member operators.] 


Kirk out. 

Share this post:

Essential PowerShell: Define default properties for custom objects

After posting my blog entry about naming your custom object types on Thursday, Hal Rottenberg left me a comment saying how it’s a shame that you have to manually create ps1xml files to store your type data and format data extensions.  Hal’s right.  Having to create ps1xml files to accompany each script you make that generates custom objects is too much work for the script author, and the script consumer has more files to download each time.  But then I thought twice about what Hal said, and asked myself: Is creating the ps1xml files to get the output you want from custom objects really necessary?

Fortunately the answer to this is “No”.  But why not?  Before I answer that, I should give a short explanation about how PowerShell determines what properties it will display when an object is output and in what format that object will be displayed.

How PowerShell determines the default format for an object

Let’s use the WMI service object for the Windows Update service as an example.  You can get this object in PowerShell using this command:

$object = gwmi Win32_Service -Filter ‘name=”wuauserv”‘

This command calls Get-WmiObject (using the gwmi alias) and requests the Win32_Service object that has the name “wuauserv”.  The result object is stored in the $object variable.

Now that the object is stored, if you want to view it you simply need to enter “$object” (minus the quotes) in your PowerShell console and you’ll see the default representation of that object.  It looks like this:


Here you can see the ExitCode, Name, ProcessId, StartMode, State and Status properties for the Win32_Service object.  There are many more properties than these six though.  You can type “$object | Format-List *” in PowerShell for yourself to see them all…there is quite a long list.  So how did PowerShell decide that these six properties were the ones to display by default?  In this case, the object itself contained the list of properties that would be displayed by default.  In PowerShell, any object may have the set of properties that will be output by default when that object is displayed stored in a member on the object itself.  It’s not kept in the most obvious of locations, but you can find it when you need to.

For any object in PowerShell, you can access its PSStandardMembers.DefaultDisplayPropertySet property to see the properties that are default for that object, if they are defined.  They won’t be defined for all objects, but in our example, they happen to be.  I show the results of the command to see the default property set here:


In this output window, the ReferencedPropertyNames property contains the list of properties that are displayed in PowerShell by default (ExitCode, Name, ProcessId, …).

What caused our object to display the properties in list format though?  After the default properties are set on an object (assuming they are set), when you output an object to the console without any Format-verb cmdlets at the end of the pipeline, the PowerShell formatting engine looks in the format data it has loaded and finds the first format data specification whose object type matches the one of the types in the object hierarchy that can be found by accessing the PSObject.TypeNames parameter.  It doesn’t matter if it is for a list format, a table format, a wide format, or a custom format — the first one found is used.  The types in the object hierarchy are looked up starting with the lowest derived type (index 0 in that collection) and then moving on to the next lowest (index 1), and so on until the base type is reached.

For our Win32_Service object, there is no format data specification for any of the object types, in which case PowerShell applies a default formatting rule: if there are four properties or less in the list of properties to display (the default properties if they were assigned, all properties if they were not), display the object in table format; otherwise, display it in list format.  For other types of objects there may be formatting data found, and when this happens the default properties are ignored and the default format is derived using the first matching format data specification.  This simplifies this whole process, but it should give you an idea how it works.

How to define the default properties for any object

Now that you have a general idea how formatting works, do you see the shortcut to defining the default output for custom objects you create?  Here’s a hint: it isn’t through the creation of a ps1xml file.

The easiest way to define the default output for a custom object is to add a PSStandardMembers member to the object and set the default properties in that member.  For objects that don’t have their default properties defined in a type data file, this is very easy to do.  Assume you have a script that generates and returns one or more custom objects with six properties: Name, Property1, Property2, Property3, Property4 and Property5.  Here’s a script to create one such object:

$myObject = New-Object PSObject
$myObject | Add-Member NoteProperty Name ‘My Object’
$myObject | Add-Member NoteProperty Property1 1
$myObject | Add-Member NoteProperty Property2 2
$myObject | Add-Member NoteProperty Property3 3
$myObject | Add-Member NoteProperty Property4 4
$myObject | Add-Member NoteProperty Property5 5

To view this object, enter $MyObject in the console.  Here is the default output for that object:


There are no default properties assigned for this object and there are no type data or format data for the object type, so PowerShell resorts to determining the output format based on the number of properties that the object has.  This is fine for one object, like we have here, but if you have a script that returns a collection of these, having their default output in list format does not give users of your script a very good user experience because it is very hard to find information in a long list of objects output in list format in PowerShell.  To show the objects in table format users can simply pipe them to the Format-Table cmdlet where they can specify the properties to show, but they shouldn’t have to do that.  Instead, you can update your script so that it specifies the default properties when these objects are created.  Here are the additional commands required to specify the default properties for our sample object:

$defaultProperties = @(‘Name’,’Property2′,’Property4′)

$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$defaultProperties)

$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)

$myObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers

The first command sets the default properties.  Then in the next command we create a new property set containing those default properties.  With that property set, we can create the collection of member info objects we need.  And then once we have that collection we can add that as our member set to our object.

After you have done this your custom object will display the default properties you specified when you output it without any Format-verb cmdlets.  Here’s our $myObject default output after running the commands shown above:


That’s more like it!  Now we have a custom object with a predefined default property set, ready for users to start using, and our custom object still contains all of the properties for the object so that users can get additional fields if they want them!

Taking it further

Armed with this knowledge, you should be able to specify the default properties on any custom objects you create without using ps1xml files.  What if you wanted to take this further?  What functionality would be useful to have for this in a generic script so that you could get even more use out of it?

Using the knowledge derived above I was able to put together a script called Select-Member.ps1 that provides rich support for selecting the default properties for an object if none exist, or overriding the default properties for an object if they were defined in a type data file.  Select-Member can be used in a pipeline against a collection, or it can be used by itself passing the objects to process into the inputObject property.

Note that when you download this script, if you haven’t already you will also need to download Get-PSResourceString.ps1.  This is a simple utility script used to look up localized error messages, and it is used by Select-Member.

Here are the syntaxes supported by Select-Member:

Select-Member [-include] <string[]> [-exclude <string[]>] [[-inputObject] <psobject>]
Select-Member -exclude <string[]> [[-inputObject] <psobject>]
Select-Member -reset [[-inputObject] <psobject>]

The first variation allows you to specify which properties you want to include and optionally which properties you want to exclude.  If you exclude properties, those will be removed only after the list of properties to include have been processed.  Both the include and the exclude parameters support wildcards as well.

The second variation allows you to specify which properties you want to exclude from the default without including any parameters.

The last variation allows you to reset the object so that it will use the default property set as defined by the type data files and throw away any default property set that was added with Select-Member.

Here’s a screenshot showing some cool things you can do with this script and WMI objects:


Here’s another screenshot showing how you can get better formatting on ADSI objects:


Note that in both these examples, the value isn’t simply in being able to specify the defaults ad-hoc like this; format-table can allow you to specify which properties you see.  The real value lies in writing scripts or functions that output objects already formatted a certain way.  You could have a script that would set the default properties for a bunch of WMI objects you use, or a script that creates its own objects and outputs them with default properties defined.  There are other opportunities with this cmdlet as well, but this should get you started.

What’s missing from this?

The Select-Member script doesn’t yet support specifying the parameter sort order, nor does it support specifying the single default parameter that is used when using wide format.  These could be easily added in the future, and I will look into that as time permits.

Give feedback!

As with all scripts I write, I’d love to hear what you think.  Whether you use the simple solution to specify default properties for custom objects or the more advanced Select-Member script, let me know how well it works out for you.


Kirk out.

Share this post:

Essential PowerShell: Use non-portable console customizations sparingly

Isn’t it odd how issues with software are often raised in groups?  I’ve been helping people use software for a long time and I find it uncanny how when I come across an issue once, there are bound to be two or three other occurrences of the same issue just about to be brought to my attention.  Maybe it just seems that way because once I’m on track to discovering the issue I notice other occurrences of the same issue more easily.  All I know is that this happens all the time.

Recently one such issue came to my attention quite a few times and it needs to be talked about.  Any of the following questions were used by those facing the issue:

  • Why doesn’t this command work in that PowerShell console?
  • Why did my PowerShell script work when I ran it here but it doesn’t work when I run it there?
  • Why can’t I find command commandName?  It worked fine when I used it in the other console.
  • I used to be able to use drive driveName, but I can’t anymore.  Why?

The answer to these questions lies in the recognition of one area where PowerShell is not very consistent: through the use of customized PowerShell consoles.

Since PowerShell has been out now for over a year, many product teams now provide PowerShell snapins for their products.  This includes Microsoft products like Exchange, System Center Operations Manager, System Center Virtual Machine Manager, SQL Server and IIS (among others) as well as ISV products like VMware ESX and Server (the VI toolkit) and Quest ActiveRoles Server (the QAD cmdlets).  And there are others who provide PowerShell snapins for a particular business need, like SDM Software’s Group Policy Management Console (GPMC) Cmdlets, /n software’s NetCmdlets, and SoftwareFx’s PowerGadgets.  Many (the majority, in fact) of these snapins come with their own customized PowerShell console.  These customized console are designed to do one or more of the following:

  1. Display welcome text with help.
  2. Show a tip of the day.
  3. Run in elevated mode on Windows Vista and Windows Server 2008.
  4. Load the PowerShell snapin(s) relevant to the product that the shell customization came with.
  5. Change the current location to a provider that was included with the snapin(s) or a drive that was created within the customized shell.
  6. Create custom commands (functions and aliases) to make it easier to use the snapin(s).
  7. Prompt the user for connection-related information to establish a connection required for the cmdlets to work.

There are definitely other possibilities of how these customized consoles might be used, but this list gives you the general idea.  Most of these customizations are helpful because it gives the PowerShell newcomer a starting point; however, more than half of them can give users the wrong impression and cause them to ask the questions listed above when they use other PowerShell consoles.  Let’s look at some examples.

One thing in common among each of the customized consoles is that they load the PowerShell snapin(s) relevant to the product that the shell customization came with.  The Exchange Management Shell loads the two snapins that come with Exchange, so that users don’t have to do this to use Exchange cmdlets:

Add-PSSnapin -Name `
Add-PSSnapin -Name `

This might not seem like a big issue, however in practice it seems to give users the false impression that they can simply call the cmdlets they need from any PowerShell script or console, which ultimately results in head-scratching when commands or a script don’t work somewhere else.  And as indicated, this is common among each of the customized consoles, so the IIS PowerShell Management Console, System Center Operations Manager Command Shell, Windows PowerShell with PowerGadgets, and others all do the same thing, loading their respective snapin automatically.

Another customization that seems to be common is for consoles to provide custom commands (aliases and functions) that are only available in that particular console.  VMware does this in their VMware VI Toolkit (for Windows).  When you open that console, you are presented with a message that shows you four commands as useful starting points, three of which only work in the VMware VI Toolkit (for Windows) shell (FYI, the commands I’m referring to are Get-VICommand, Get-VC and Get-ESX).  You can imagine that causes confusion when someone is trying to use one of these commands in another console.  Of course VMware isn’t the only one that does this.  The Exchange Management Shell creates three commands that are only available by default in that console (Get-ExCommand, quickref and Get-ExBlog) and the System Center Operations Manager Command Shell creates 10 commands that are only available by default in that console.  I won’t bother listing all of those here because I’m sure you get the picture by now.  Trying to use these commands in other consoles without adding them to the profile or explicitly creating them results in an error indicating that the command was not found and invariably some head scratching for the individual who is trying to run then.

A third type of customization is to check for the presence of a connection and then to prompt users for connection information if a local connection was not detected.  The System Center Operations Manager 2007 Command Shell provides connection management like this in its console.  The connection that is established is not usable outside of that console, nor is it documented accordingly, so users need to be aware that their scripts will have to include commands to make the required connections in order to work in any PowerShell environment.

There are surely going to be other examples of this as different teams customize their console environment to meet their needs.  As a PowerShell end user, when these customized consoles are very convenient, what can we do to make sure we’re aware of what customizations are being made?

Fortunately the console customizations are easy to discover.  Every customized console uses PowerShell’s command line parameters to perform the customizations.  This means viewing the properties of any of the shortcuts used to launch a customized console allows you to see what customizations are being performed by examining the command line parameters for powershell.exe.  The customizations that you need to look at are the PowerShell console file that is used (as identified by the -psconsolefile argument) and the script that is executed (as identified by the -command argument).  The PowerShell console file (psc1 file) is an xml document that defines which snapins should be automatically loaded by PowerShell when it starts.  The snapins identified in this file are silently added to the PowerShell session when it is opened.  The command argument identifies the PowerShell script or PS1 file that will be run after the snapins are loaded.  This script is used to customize the look of the console, create custom commands, manage connections, etc.

Now that you have this information, all you need to do is make sure you are aware of the customizations in the console you are using, particularly those that are not portable to other consoles, so that you don’t make incorrect assumptions when you write your scripts.

Before I close this off, I have a request that I’d like to put out there for snapin developers.  If you’re creating a customized PowerShell console when your snapin is installed, please make an effort to make those customizations self documenting.  I don’t want you to hurt the end user experience your after, but I think a bit of carefully worded output that identifies your console customizations as customizations that are specific to that console would go a long way to educate beginner PowerShell users about how consoles can be customized and what they need to be aware of when switching from one console to the next.  Without that information, users simply aren’t getting the information that they need to use your commands in other console that they might use.  And of course, if you are making custom function that are only available in your customized console, ask yourself, should those function only be available in one console, or should they be available all the time.  Often times I bet the answer is the latter, so please consider making cmdlets for those function you feel are necessary for the right experience when using your snapin.  Otherwise you’re just making it more difficult for your users to have the experience that you want them to have.

Thanks for reading!

Kirk out.

Share this post:

Essential PowerShell: Learn how to find what you are looking for

As silly as this may sound, learning how to find what you’re looking for in PowerShell is key if you want to learn PowerShell quickly and easily.  PowerShell is a rather unique language in that most of the information you will need to use the language is retrievable by using the language itself.  The problem for newcomers to PowerShell who like to dive right in when learning something and who don’t want to read through lots of documentation to get started is that they need to know some PowerShell to learn more about PowerShell and what it can do.

When I first started learning PowerShell I was fortunate to be able to see PowerShell presented twice, both times by Jeffrey Snover, the “father” of PowerShell.  In both presentations as he wrapped things up he mentioned that if there’s one thing you should make sure that you take with you about PowerShell it’s a set of five cmdlets that are key to learning more about PowerShell.  They are (in no particular order): Get-Help, Get-Command, Get-Member, Get-PSDrive and Get-Alias.

Rather than pulling the documentation about these cmdlets into this article, I thought it would be more useful to follow the KISS principle and list a series of questions you might ask yourself about PowerShell accompanied with the PowerShell script (mostly one-liners) that can be used to answer those very questions primarily using the cmdlets I mentioned above.  Here are the questions and their answers to help get you started.

I’ve heard PowerShell cmdlets all follow a verb-noun syntax.  What verbs are available in PowerShell?

Get-Command -CommandType Cmdlet | Group-Object -Property Verb -NoElement

What cmdlets use the verb “out”?

Get-Command -Verb Out

What cmdlets use the noun “command”?

Get-Command -Noun Command

What examples are available for the Tee-Object cmdlet?

Get-Help Tee-Object -examples

What is the full help information for Tee-Object?

Get-Help Tee-Object -Full | Out-Host -Paging
# Note: I could have replaced “Out-Host -Paging” with “more” and the result would have been the same

What are the non-common parameters of Set-Location (with their documentation)?

Get-Help Set-Location -Parameter *

What cmdlets have a parameter like “path”?

Get-Help * -Parameter *path* | Sort-Object -Property Name

What general PowerShell help topics are available?

Get-Help -Category HelpFile,Provider

I need general help on operators.  Where can I find that information?

Get-Help -Category HelpFile,Provider | Where-Object { (Get-Help $_.Name | Out-String).Contains(“operator”) }

Now that I see the help topics and providers that reference the keyword “operator”, how do I see the details?

Get-Help about_operator
Get-Help Variable
# etc.

What aliases are defined for the ForEach-Object cmdlet?

Get-Alias | Where-Object {$_.Definition -eq “ForEach-Object”}

I’ve heard PowerShell even treats the registry as a drive.  What other drives are there?


How do I start browsing the Registry in PowerShell?

Set-Location HKLM: # or cd HKLM:
Get-ChildItem # or dir
Set-Location Software # or cd Software
# etc.

I noticed that there is a drive for environment variables.  How do I use that to check the value of my Path environment variable?

(Get-Item env:Path).Value

How do I add all of my installed PowerShell snapins to the current session so that I can use their cmdlets too?

Get-PSSnapin -Registered | ForEach-Object { if ((Get-PSSnapin $_.Name -ErrorAction SilentlyContinue) -eq $null) { Add-PSSnapin $_.Name } }

(Note: More useful one-liners using Get-PSSnapin can be found here.)

I need to enumerate a bunch of services and then do other things.  Since these are enumerated as objects, how can I tell what I can do with them (i.e. how can I tell what properties and methods they have)?

Get-Service | Get-Member

Are there other basic questions that you think should be on this list?  After learning how to find the information you need within PowerShell, what has been your biggest stumbling block?  Let me know in the comments!

Kirk out.

Technorati Tags: , , , ,

Essential PowerShell: Know your system variables

By default PowerShell v1.0 comes with 44 variables preinstalled.  Some of these variables are used to configure the maximum number of objects that PowerShell supports, others are used to configure output preferences for scripts, and there are more with many other purposes.  As a script author, it is very useful to understand what the variables are used for so that you can take advantage of them in your scripts.

Fortunately, the wonderful folks at Microsoft who created PowerShell embedded tons of help documentation about PowerShell directly within the shell.  So learning what variables are used for is simple as long as you know how to get the information (which isn’t always that simple for newcomers).

Here’s a useful one-liner that can be used to produce a detailed list of all PowerShell variables.  The output includes the variable name, type, description, value, and options set on the variable.  It also includes a custom member called DisplayValue which is a more detailed view of the data that the variable contains.  Here’s the one-liner, split across multiple lines to improve readability:

Get-ChildItem -Path Variable: `
       | Add-Member `
              -Name Type `
              -MemberType ScriptProperty `
              -Value { $this.GetType().FullName } `
              -PassThru `
       | Add-Member `
              -Name DisplayValue `
              -MemberType ScriptProperty `
              -Value { (Get-Variable -Name $this.Name -Scope 1 -ValueOnly | Format-List -Property * | Out-String).Trim("`r`n") } `
              -PassThru `
       | Sort-Object -Property Name `
       | Format-List -Property Name,Type,Description,Value,DisplayValue,Options `
       | Out-Host -Paging

For the most part, the output of this one-liner provides enough of a description for each variable to explain what it is used for.  Some variables that don’t have descriptions are easily understood by looking at their DisplayValue.  A few might be confusing though.  The $ variable (which you would use in your script as $$) contains the last token in the last command that was run.  The ^ variable ($^ in your script) contains the first token in the last command that was run.  The error variable ($error) contains the history of errors encountered during the current PowerShell session.  You can clear this history at any time by running the $error.Clear() command.

If you are authoring a PowerShell extension (an extension may be a PowerShell snapin, a set of functions, PowerShell scripts, etc) and if your extension adds additional global variables that will be useful to consumers of your extension, I strongly encourage you to provide enough details in the variable description that PowerShell continues to be a self-documenting scripting environment.  The self-documenting nature of PowerShell is unique and incredibly beneficial to PowerShell users.  Please continue to promote this through your own PowerShell work.

If there are any system variables that you are having a hard time with, or that you feel I should have described in more detail in this post because they just aren’t intuitive, feel free to let me know in the comments and I’ll help you out as best as I can.

Kirk out.

Technorati Tags: , , ,

Essential PowerShell: Beware of promiscuous types

[Updated: 01-Oct-07] 

PowerShell is a type-promiscuous language.  That means that objects in expressions may be converted to other types as long as the PowerShell interpreter determines that it can convert them without any loss in precision.  The PowerShell interpreter does this to give you the result that it thinks you would expect.  For instance, you can perform mathematical operations mixing integers, floating point numbers and string representations of numbers and get the result as if they were all entered in numeric format on a calculator.  An example of this is 14 + 41.555 + “44.444”.  Running this command in PowerShell will return the floating point value of 99.999.  The order of these objects in the mathematical operation isn’t important because the PowerShell interpreter will determine what conversions can be done without losing the floating point precision.

Similarly, you can compare objects of different types and the comparison will evaluate to true if those objects are logically equivalent after run through the PowerShell interpreter.  Or you can perform boolean logic using objects that can be converted to boolean values by the PowerShell interpreter.  Here are some comparisons that evaluate to true:

1 -eq “1”
$true -eq “$true”
$true -eq “True”
$true -and “True”

All of these comparisons also evaluate to true regardless of which object is on the left-hand side of the equals operator and which object is on the right-hand side of the equals operator.  This makes working with types in PowerShell very easy because the script author doesn’t have to spend as much time converting types to get the results they are looking for.  Instead they are free to concentrate on the core script functionality.

Script authors need to beware, though.  There is a feature in the PowerShell interpreter in PowerShell v1.0 that can result in unexpected behaviour in your PowerShell scripts if you’re not careful.

If you convert any non-empty string to a boolean value in PowerShell, the resulting boolean value will be boolean True.

Always.  For every string.  This happened for every string I tried, including “0”, “1”, “$true”, “$false”, “True”, “False”, “Poshoholic” — all of these will convert to boolean true if prepended with [Boolean].  This was very unexpected to me.  I would have expected errors to be raised for strings that didn’t nicely convert to a boolean value (such as “Poshoholic”) because there will be a loss in precision, and for strings that do convert to a boolean value, that they would convert into the appropriate boolean value (True for “1”, “$true” and “True”, False for “0”, “$false” and “False”).  I would also have expected that I could do this and get back the same value I started with:


Unfortunately that is not the case.  The conversion above will return $true.

Since this has to do with converting a string to a boolean value, it is only likely to show itself in a select few circumstances, such as:

  1. Using the string representation of False by itself in an expression.  e.g. if (“$false”).
  2. Comparing a boolean value to a string representation of False.  e.g. $myBooleanValue -eq “$false”

In the first example, the script author might expect that the if statement would fail but instead it succeeds.  In the second example, the script author might expect that the if statement would succeed if $myBooleanValue was equal to boolean False, but it will fail.  This can result in scripts running incorrectly.

Fortunately, there are a few ways to workaround this.  The PowerShell interpreter converts the string into a boolean value when the boolean value is the first in the comparison.  Similarly, the PowerShell interpreter will convert a boolean into a string value when the string is the first in the comparison.  Since the boolean values of true and false convert correctly into “True” and “False”, respectively, a script author simply has to switch the sides in the comparison to make it work.  So, for the two examples shown above, they can be corrected as follows:

  1. “$false” -eq $false
  2. “$false” -eq $myBooleanValue

Alternatively, you can  just pass your string representation of a boolean value into a System.Convert static method called ToBoolean, like this:


This will give you back the boolean value of $false as you might have been expecting.

If you are authoring PowerShell scripts and working with expressions containing mixed types, I recommend testing those expressions to ensure that they are giving you the results you would expect.  It’s very likely that they are, but as this article illustrates there are some cases where they might not be working as expected. 

That’s it for this post.  Thanks for reading!

Kirk out.

Technorati Tags: , , ,

Effective PowerShell

Keith Hill has started an “Effective PowerShell” series on his blog that allows you to learn from his experiences working with PowerShell for the past couple of years.  He has published 6 articles in this series so far, including:

  1. Effective PowerShell Item 1: The Four Cmdlets That are the Keys to Finding Your Way Around PowerShell
  2. Effective PowerShell Item 2: Use the Objects Luke. Use the Objects!
  3. Effective PowerShell Item 3: Know Your Output Formatters
  4. Effective PowerShell Item 4: Commenting Out Lines in a Script File
  5. Effective PowerShell Item 5: Use Set-PSDebug -Strict In Your Scripts – Religiously
  6. Effective PowerShell Item 6: Know What Objects Are Flowing Down the Pipe

These articles are very similar to the articles in my Essential PowerShell series.  There is a lot of useful information in these articles.  I encourage you to take the time and read them.

Kirk out.

Technorati Tags: , , ,

Essential PowerShell: Avoid shorthand in shared PowerShell scripts

While this topic may be the subject of debate and it has certainly been discussed to some extent before, I am a firm believer that PowerShell script authors should completely avoid shorthand in their shared PowerShell scripts.  Shorthand should only be used when using PowerShell interactively from the console.  I consider this a best practice when working with PowerShell.  There are four reasons for this that all boil down to providing a better user experience: readability, integrated help support, portability and upgradability.  I’ll explain.


PowerShell scripts written without any shorthand are as close to self-documenting as you can get.  If the cmdlets and parameters (and variables!) being used are intelligently named, you should be able to read a script containing cmdlets and/or parameters (and variables!) that you haven’t used before and have a general idea what the script is going to do.  PowerShell’s verb-noun format for cmdlets goes a long way to facilitate that.  Having readable scripts is also necessary for maintenance reasons so that scripts maintained by multiple authors are understandable to all authors.

Integrated Help Support 

PowerShell is still new and will likely be new for a while yet.  Many people new to PowerShell will use sample scripts to learn the language, and it will be much easier for them to learn from sample scripts if they use full cmdlet and parameter names.  That way they can take full advantage of the rich help system that is integrated within PowerShell by using it to learn more about PowerShell scripts they find on the web or in products that expose integrated PowerShell scripts such as PowerGUI.  To illustrate this point, let’s look at a sample script where using shorthand can harm the user experience of other PowerShell users.

Here’s a sample script using shorthand that will retrieve the expanded parameter sets for the get-command cmdlet:

gcm -name get-command -type cmdlet | select -expand parametersets

And here’s that same sample script without any shorthand:

Get-Command -name Get-Command -commandType Cmdlet | Select-Object -expandProperty ParameterSets

If someone new to PowerShell is trying to figure out what the different parts of this script do, they can use the get-help cmdlet or help alias on the parts of the script.  This can be especially important if English isn’t their first language (the integrated help documentation in PowerShell has already been localized in many different languages to reduce the learning curve for people whose first language is not English).  For the sample script, they might try to look up help for the gcm command, the name parameter, the type parameter, the select command, or the expand parameter.  Here are the PowerShell commands to do just that:

  1. Get-Help gcm
  2. Get-Help gcm -parameter name
  3. Get-Help gcm -parameter type
  4. Get-Help select
  5. Get-Help select -parameter expand

Of these 5 commands, 2 will fail.

The third command fails because the Get-Command cmdlet does not have a Type parameter.  Type is the alias for the CommandType parameter, and PowerShell 1.0 does not resolve alias names when passed in as the value of the Parameter parameter.

The fifth command fails because the Select-Object cmdlet does not have an expand parameter.  But expand isn’t an alias for a parameter either.  In PowerShell 1.0, part of the parameter name resolution logic includes support for identifying parameters by the shortest substring that uniquely identifies the parameter or an alias to the parameter when compared with a list of parameters and aliases for the cmdlet.  In this case, expand is a substring of expandProperty and there are no other parameters beginning with “expand”, so PowerShell deduces that the script author is referring to expandProperty and lets the script run accordingly without warnings or errors.

Had the script been written without any shorthand, as in the second sample, then all attempts to look up the same help information would succeed.  Here are the same Get-Help commands but without any shorthand:

  1. Get-Help Get-Command
  2. Get-Help Get-Command -parameter name
  3. Get-Help Get-Command -parameter commandType
  4. Get-Help Select-Object
  5. Get-Help Select-Object -parameter expandProperty

 All 5 of these commands work as expected.


As Jeffrey Snover indicated in his blog post titled “Is it safe to use ALIASES in scripts?“, aliases are not constant and can be removed.  While this would likely only happen rarely in practice, PowerShell scripts using aliases are not guaranteed to be portable to other environments and should be avoided.


As I mentioned earlier in this post, part of the parameter name resolution logic in PowerShell 1.0 includes support for identifying parameters by the shortest substring that uniquely identifies the parameter or an alias to the parameter when compared with a list of parameters and aliases for the cmdlet.  This means we could have written the above sample script like this:

 gcm -na get-command -ty cmdlet | select -exp parametersets

In this case, “na” is the shortest substring that uniquely identifies the name parameter, “ty” is the shortest substring that uniquely identifies the type alias for the commandType parameter, and “exp” is the shortest substring that uniquely identifies the expandProperty parameter.  While this works fine just now, you cannot depend on this sample continuing to work in future releases of PowerShell.  Why?  Because there is no guarantee that another parameter or alias will not be added in a future release that would make one of these substrings ambiguous.  In fact, you cannot depend on this sample working in the current release of PowerShell for users who have added parameter aliases that would make one of these substrings ambiguous either.

For these four reasons, PowerShell authors should be diligent about avoiding use of shorthand in shared PowerShell scripts.  While using aliases for cmdlets, parameters and functions and shorthand to identify parameters is very useful when using PowerShell interactively, it can negatively impact the user experience of others when used in PowerShell scripts and therefore should be avoided (with few exceptions, if any).

Kirk out.

Technorati Tags: , , ,

Essential PowerShell: Understanding foreach (Addendum)

I need to add an important addendum to the Essential PowerShell: Understanding foreach article I posted (if you haven’t read it already, you might find it worthwhile to start with that article first before reading this article).

As Dmitry Sotnikov discovered first-hand and blogged about earlier today, there is another important difference between what might appear as two similar constructs in PowerShell: the foreach statement and the foreach alias (which is an alias to the ForEach-Object cmdlet).  The foreach statement is a loop construct.  The foreach alias (and therefore the ForEach-Object cmdlet) is not a loop construct.  It’s a cmdlet.  Why is this important?  Because you can control the logic within a loop construct using the break and continue statements, but not within a cmdlet.

Let’s examine this in more detail using a new example.  This time I’ll write a PowerShell script that will take in a string and output each character of that string that is not a vowel.  Note that this is just an example and it is not necessarily the best way to do this sort of thing.  I’m just using it to get the point across.

Here is the foreach statement example:

foreach ($character in [char[]]”Poshoholic”) { if (@(‘a’,’e’,’i’,’o’,’u’) -contains $character ) { continue } $character }

And now what appears to be the equivalent foreach alias example:

[char[]]”Poshoholic” | foreach { if (@(‘a’,’e’,’i’,’o’,’u’) -contains $_ ) { continue } $_ }

If you run each of these two examples, you’ll quickly see that they don’t function the same way at all.

In the foreach statement example script you get what you would expect: each consonant in the string “Poshoholic” is output to the host, so you’ll see P, s, h, h, l and c, each on a separate line.  In the foreach alias example script, though, only the consonant characters that were before the first vowel in the string are output to the host.  In this case, all that is output is P.  Why?  Because the continue statement (and the break statement) only affect the logic of the program loop in which they are contained.  Since the second example doesn’t actually contain a program loop (remember that the foreach alias and ForEach-Object cmdlet are not a loop construct), the continue statement will apply to the entire script in which it is contained.

You could correct this by removing the continue statement and changing the script as follows:

[char[]]”Poshoholic” | foreach { if ((@(‘a’,’e’,’i’,’o’,’u’) -contains $_) -eq $false ) {$_} }

This can be confusing, so if you have any questions feel free to post them in the comments and I’ll respond as quickly as I can.  And with a little luck, Microsoft will use this information to clarify their documentation in the about_foreach help topic in a future release of PowerShell.

Kirk out.

Technorati Tags: , ,