Cmdlets and Objects and Scripts, Oh My!
The PowerShell world introduces new, somewhat confusing concepts and terminology, and I suspect that your first reaction will be similar to mine: I looked at a few PowerShell scripts; scratched my head; and thought, “I wonder if there are any donuts left in the kitchen?” At first, it all seemed pretty opaque and possibly not worth investigating. Fortunately, this feeling didn’t last long. (Neither did the donuts.)
The biggest obstacles are the strange names of the cmdlets and the unusual command-line syntax. Cmdlets have names like Remove-ItemProperty, Get-Content, Wait-Job, New-Alias, and so on. This can help make sense of it:
- Cmdlet names are case insensitive. You can type
wait-job
just as well asWait-Job
. The capitalization is used to make the words more distinct when you read the documentation. -
Microsoft’s programmers chose to use a noun-verb convention for naming the cmdlets to make the names more clearly say what the cmdlets actually do. The dash is just part of the name.
Yes, the names tend to be long and cumbersome to type. A Unix programmer would have chosen a name likeRename-Item
isn’t some sort of combination of aRename
command and anItem
command. The name is all one word:Rename-Item
, and you can guess from this name that it probably renames whatever items it’s given.ri
for thatRename-Item
command. But,ri
doesn’t really tell what it does. As it turns out, PowerShell does have a built-in alias forRename-Item
, and the alias is...ri
. As you learn PowerShell’s commands, you might start by using the long names to help remember what the commands do and then scan through the alias list and start learning their shorter abbreviations. - The names of cmdlet command-line options are similarly long. For example, the
get-process
cmdlet can take the following optional arguments:
-Name “string”<br> -ComputerName “string”<br> -FileVersionInfo<br> -Module<br> -Id integer<br> -InputObject object
Again with the long names! Who can type -InputObject quickly without making three typos along the way? Well, it turns out that you don’t have to type the entire option name, just enough to distinguish the desired option from any others that start with the same letters. So, you can type -input or even -in instead of -InputObject. You just can’t shorten it to just -i because that’s not enough to distinguish between -Id and -Inputobject.
Some command can be shortened even more. For example, a typical new-alias
command looks like this:
new-alias -name shortname -val realcommandname -descr “Brief description”
But, you even can omit the parameter switches, in this really short version of the command:
new-alias shortname realcommandname
The two arguments in this case are called positional parameters because PowerShell has to figure out what they are based on their position in the command line. You can see which parameters can be specified this way by looking at a cmdlet’s syntax description. If you type new-alias -?
, you can see that the syntax is
<strong>New-Alias [-Name]</strong> <em><string></em> <strong>[-Value]</strong> <em><string></em> <strong>[-Description</strong> <em><string></em><strong>]</strong> <strong>[-Force] [-Option {None | ReadOnly | Constant | Private | AllScope}]</strong> <strong>[-PassThru] [-Scope</strong> <em><string></em><strong>] [-Confirm] [-WhatIf]</strong> [<em><CommonParameters></em>]
Notice that the -Name option indicator itself is listed in [ ] brackets, so it’s optional, but the <string> value after it isn’t. This argument must always be there, so it can be interpreted by its position. The -Value string is listed the same way, but none of the other arguments are.
The other main obstacle to learning to use PowerShell is the strange syntax with commands like the example I gave earlier
dir | where-object {$_.LastWriteTime -lt (get-date).addmonths(-6)} | remove-item
The dir and remove-item parts are self-explanatory, but the middle part is, well, non-obvious. This where you hit the PowerShell learning curve, and the only thing to do is expose yourself to a lot of it. It will start to make sense pretty quickly. My advice is to read as many PowerShell scripts as you can. Read them like literature, get a feel for the language, and work out what they do. I’ll just point out a couple of things about that example command here.
The where-object
cmdlet is a filter. It reads a stream of objects from the previous command in the pipeline, evaluates a true/false value for each one, and passes along only the objects for which the value is true. In the example, the true/false value is provided by the part within curly brackets:
{$_.LastWriteTime -lt (get-date).addmonths(-6)}
Caution - It’s important to know that this expression isn’t handled directly by
where-object
. If it was, then conceivably every cmdlet might have a different way of constructing these expressions, which make would things inconsistent and difficult to master.
Instead, this expression format is part of the PowerShell language itself. Technically, where-object
expects the body (code) of a function on its command line. The curly brackets signify that you’re typing the body of a function that you’re defining on-the-fly without giving it a name, and that function is given to where-object
to use to evaluate each of the file objects it scans. (This little function is technically called a lambda, but that’s not too important here.)
Let’s pick it apart. There are three parts:
|
|
|
This does a comparison of two values, and it’s true if the first value is less than the first. In other words, the expression {a |
|
This is the oddest part, but watch how it works: The |
The end result is that this expression is true if the file was last written more than six months ago. The curly brackets turn this expression into a function so that where-object
can evaluate it for each of the objects it examines.
The output of this where-object
command is just those file objects that were last modified more than six months ago. The rest of the command line feeds that stream of objects to remove-item
, which deletes the files they represent. The end result is that this command purges a directory of old, abandoned files.
Now, I didn’t just write that command off the top of my head. I had to learn the basics of cmdlets first, so I knew to write:
dir | where-object {some expression} | remove-item
Then, I had to learn about the properties of the file and folder objects to know to use LastWriteItem and the System.DateTime object to find the addmonths property. To help with that job, interestingly enough, there are cmdlets that describe the properties of any object they encounter. I describe that next.