Introduction to Windows PowerShell

1 2 3 4 5 6 7 8 9 10 11 12 Page 8
Page 8 of 12

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 as Wait-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. Rename-Item isn’t some sort of combination of a Rename command and an Item 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.

    Yes, the names tend to be long and cumbersome to type. A Unix programmer would have chosen a name like ri for that Rename-Item command. But, ri doesn’t really tell what it does. As it turns out, PowerShell does have a built-in alias for Rename-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:

$_.LastWriteTime

$_ is a placeholder for the object that where-object is examining. $_.LastWriteTime picks up the LastWriteTime property from that object. For a file or folder object, it’s the date and time that the file was last modified.

-lt

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 -lt b}, is true if value a is less than value b. In this instance, the test is true if the file’s LastWriteTime is less than (earlier than) the time that comes after -lt.

(get-date).addmonths(-6)

This is the oddest part, but watch how it works: The get-date cmdlet is run. With no arguments, it spits out a .NET System.DateTime object representing the current date and time. In this simplest form, it’s like Now() in VBScript. The parentheses around it indicate that we are going to treat the result of the cmdlet as a value. addmonths is one of the standard methods of the System.DateTime object. In this case, we end up with the current date with six months subtracted from it—in other words, the date six months back.

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.

1 2 3 4 5 6 7 8 9 10 11 12 Page 8
Page 8 of 12
It’s time to break the ChatGPT habit
Shop Tech Products at Amazon