The basics of PowerShell syntax - PowerShell fundamentals - PowerShell in Depth, Second Edition (2015)

PowerShell in Depth, Second Edition (2015)

Part 1. PowerShell fundamentals

Chapter 4. The basics of PowerShell syntax

This chapter covers

· Using commands in PowerShell

· Using command parameters

· Working with command aliases

· Using script blocks

Any time you’re learning to use a new tool, particularly one that involves typed commands, the syntax can be the biggest “gotcha.” We won’t pretend that every single bit of PowerShell’s syntax is easy to remember, makes perfect sense, and is totally consistent. In the end, the syntax is what it is—we (and you) have to learn it and deal with it.

If you’ve used PowerShell a bit already, and if you’ve picked up some of its syntax from reading other people’s blogs and articles on the internet, you may have an inaccurate view of the syntax. You also need to remember that best practice has evolved over the eight-plus years we’ve had between the original release of PowerShell and the latest version. This chapter will help set you straight.

4.1. Commands

PowerShell has four features that we think of as commands:

· Internal cmdlets, which only run inside PowerShell and are written in a .NET Framework language such as Visual Basic or C#

· Functions, which are written in PowerShell’s scripting language

· PowerShell v3 and v4 cmdlets, which are produced from WMI (Windows Management Instrumentation) classes using the “cmdlets over objects” capabilities

· External commands, such as ping.exe, which could also be run from the old cmd.exe shell

In this chapter, we’ll focus only on the first two command types.

Note

What’s in a name? Sometimes, a lot of cleverness. Microsoft chose the name “cmdlet” for PowerShell’s internal commands, because that word hadn’t been used for anything else, ever. If you hop on your favorite search engine and include “cmdlet” in your search query, the results you get will be almost 100% PowerShell-related, because the word “cmdlet” isn’t used in any other context.

PowerShell cmdlets have a specific naming convention. Functions should follow this same convention, but PowerShell doesn’t require them to do so. That convention is called verb-noun. A cmdlet name starts with a verb, which is followed by a dash, which is followed by a singular noun. PowerShell isn’t case sensitive, so capitalization of commands is a matter of personal preference and convention. Tab completion will capitalize for you according to convention. Consider some of these cmdlet names:

· Get-Service

· New-ADUser

· Set-Service

· Write-EventLog

· Enter-PSSession

Microsoft strictly controls the verbs that everyone can use for a cmdlet name. Although it’s possible for someone to create a cmdlet—or a function—that uses nonstandard verbs, PowerShell will display a warning when loading those into memory. You can find the official list of approved verbs at http://msdn.microsoft.com/en-us/library/windows/desktop/ms714428(v=vs.85).aspx, which is part of the PowerShell Software Development Kit (SDK) documentation. You can also see the list by running the Get-Verb cmdlet (Get-Verb is actually a function but it’s treated as a cmdlet).

Note

The approved verbs list hasn’t changed between PowerShell v3 and PowerShell v4.

Nouns aren’t controlled, but they should always be singular (“Service” versus “Services”), and they should clearly describe whatever it is they’re examining or manipulating. For example, we recommend using “Mailbox,” which is clearer than something like “mbx.”

Why are these rules in place? They’re for your benefit. If you’d never worked with System Center Virtual Machine Manager, you could guess that the cmdlet used to retrieve a list of virtual machines would be named something like “Get-VirtualMachine.” You could then use PowerShell’s help functionality to look for help on that cmdlet name, which would validate your guess.

Tip

Wildcard searching is often the best way to start. Get-Command *net* will give a significant number of responses but will enable you to quickly discover the networking cmdlets.

But with the exception of Microsoft Exchange Server, you’ll find that most products that offer PowerShell-based tools have cmdlet nouns that include a short prefix. It’s not “Get-User,” but rather “Get-ADUser.” The idea behind the prefixes is to tie a cmdlet to a specific technology or vendor. For example, Quest (now a part of Dell) has a set of cmdlets for managing Active Directory. Their user cmdlet is called “Get-QADUser.” By using a prefix, the cmdlet name is clear about what kind of user it’s working with or at least what product. It’s not a SQL Server user, it’s not a local user, it’s an ADUser or a QADUser. This is important because the Microsoft and Quest cmdlets produce different object types, which would confuse PowerShell’s formatting engine, along with everyone else. Exchange Server is an exception: It uses “Get-Mailbox” rather than “Get-ExMailbox.” If they had it to do over, we’re sure Microsoft would’ve chosen the latter, but Exchange Server shipped before anyone thought of using the noun prefixes.

Warning

When people speak aloud about cmdlets, they tend to be a bit lazy. They’ll say, “Get Service,” which might lead you to believe that you could type “Get Service” and have it work. Nope. Never forget that there’s always a dash between the verb and noun. Even though people might not say “Get dash Service,” you’d type Get-Service.

You might feel that cmdlet names are long and hard to type. They certainly can be—Reset-ADAccountPassword is a mouthful whether you’re saying it or typing it. PowerShell offers two features to help make typing easier.

4.1.1. Aliases: nicknames for commands

An alias is a nickname for a command name. Aliases can point to cmdlets or to functions, and they provide a short way to type the command’s name. Typing dir is a lot easier than typing Get-ChildItem, for example.

An alias is only a shortcut for a command’s name. As you’ll learn in a moment, commands can be accompanied by parameters, which specify and modify a command’s behavior. An alias never includes any parameters. You can’t create an alias to run dir $env:temp –File –Recurse, although you could create a simple function and define an alias for the function.

We strongly recommend using aliases only when you’re interactively typing commands into the PowerShell console. If you decide to create a script, or even if you copy and paste a command into a script, use full command names (some commercial editors can expand aliases into their full command names for you).

Warning

Never use your own created aliases in scripts that you’re distributing to others. They may not have those aliases or, even worse, they may have defined those aliases to something else. Never assume the presence or meaning of an alias.

Although the aliases are easy to type, they’re more difficult to read, particularly for someone with less PowerShell experience. Using full command names helps make it clearer what a script is doing, making the script easier to maintain.

4.1.2. Command name tab completion

Most PowerShell hosts—including the console and ISE provided by Microsoft—provide a feature called tab completion. It’s a way of letting the shell type for you. For example, open a PowerShell console window and type Get-P. Then, press the Tab key on your keyboard. Keep pressing Tab, and you’ll see PowerShell cycle through all of the available commands that match what you’d already typed. Press Shift+Tab to cycle backward.

We think this is a great way to use full command names without having to type so much.

4.2. Parameters

Even if you’ve never used PowerShell before, we can guarantee you’ve used parameters. Take a look at figure 4.1, a dialog box you’ve probably seen before. It shows the User Properties dialog box from Active Directory Users and Computers.

Figure 4.1. Even dialog boxes have parameters.

The labels in the dialog box in figure 4.1—“First name,” “Last name,” “Description,” and so forth—are parameters. What you type into the text boxes are parameter values. PowerShell uses a more text-friendly way of representing parameters and values. Take a look at figure 4.2 and you’ll see what we mean.

Figure 4.2. Graphical parameters map to the text-based parameters used by PowerShell.

In figure 4.2, we’re running a command called New-ADUser that’s part of Microsoft Active Directory module. It has several parameters, which all start with a hyphen or a dash, followed by the parameter name. Because parameter names can’t contain spaces, the parameter names sometimes look a little strange, like –GivenName. After the parameter name you have a space and then the parameter value. You always have to enclose string values in quotation marks (either single or double, it doesn’t matter) when the string contains a space. None of our values included spaces, so we didn’t have to use the quotes, but it doesn’t hurt to do so anyway.

Tip

PowerShell’s cmdlet and parameter names aren’t case sensitive. If you use tab completion, you’ll get capitalization, but if you type the names, any old case will do. We regularly work interactively in lowercase. We will say that capitalization of cmdlet and parameter names makes your scripts easier to read.

PowerShell v3 introduced a new cmdlet called Show-Command (also present in v4 and later), which takes another PowerShell command and displays its parameters in a graphical dialog box. You can fill in the dialog box and either run the command or click a different button to see what the command would look like written out in text. Figure 4.3 shows the Show-Command cmdlet in action on Windows 8.

Figure 4.3. PowerShell’s Show-Command cmdlet graphically prompts you to fill in a command’s parameters.

This cmdlet is also turned on in the ISE, which makes it easy to create a command by checking parameters and inserting it into your script. Show-Command is available as a docked window in the ISE; see chapter 2 to learn more.

We sometimes see people struggle with parameters. For example, if they want to get a service named BITS, they’ll type “Get-Service –BITS.” That’s not correct. The correct command would be Get-Service –Name BITS. Remember, after the hyphen comes the parameter name—the piece of information you’re setting. That’s followed by a space, then the value you want to give to the parameter. In his classes, Don makes students chant “dash name space value, dash name space value, dash name space value” for several minutes, to be sure the pattern sinks in.

Like command names, parameter names can get a bit tedious to type. As with commands, PowerShell provides some shortcuts.

4.2.1. Truncating parameter names

PowerShell requires that you type only enough of the parameter name to differentiate it from the other parameters available to the command. For example, consider the Get-Service cmdlet, which has the following syntax:

Get-Service [[-Name] <string[]>] [-ComputerName <string[]>]

[-DependentServices] [-RequiredServices]

[-Include <string[]>][-Exclude <string[]>]

[<CommonParameters>]

Get-Service -DisplayName <string[]> [-ComputerName <string[]>]

[-DependentServices] [-RequiredServices]

[-Include <string[]>][-Exclude <string[]>]

[<CommonParameters>]

Get-Service [-InputObject <ServiceController[]>]

[-ComputerName <string[]>]

[-DependentServices] [-RequiredServices]

[-Include <string[]>][-Exclude <string[]>]

[<CommonParameters>]

Only one parameter starts with the letter “C,” and that’s –ComputerName. Therefore, instead of typing Get-Service –ComputerName SRV23 you could type Get-Service –c SRV23. Two parameters start with the letter “D,” though: -DependentServices and -DisplayName. You couldn’t shorten those to only one letter; you’d need to type –de or –di at a minimum.

As with command aliases, shortened parameter names are easy to type but hard to read. When someone else comes along and reads a script with lines like the following:

gsv –di BITS –c SERVER2 -de

they’re likely to be a little confused, don’t you think? Coming back to that code six months after writing it, you may be confused as well. That’s why we suggest including full, complete parameter names when you’re putting commands into a script. With tab completion available it’s just as easy to use the full name and saves having to remember all of the aliases.

4.2.2. Parameter name tab completion

The good news is that tab completion works for parameter names, too. Type Get-S, press Tab multiple times to complete the command name to Get-Service, and then type –c and press Tab. PowerShell will fill in –ComputerName for you. You can still truncate your parameter names when you’re typing, or one or two extra keystrokes on the Tab key will get you the fully spelled-out name that’s easier to read. Not sure about any of the parameters? After entering a cmdlet name, if you type a dash and then press Tab you can cycle through all the parameters.

While we’re talking about parameter completion, later versions of PowerShell can also guess what value you want. Try this: At a PowerShell prompt type Get-Service –n and press Tab. That should complete –Name. Then press the spacebar and hit the Tab key again. PowerShell should display the first service. You can keep pressing Tab to find the service you want. Use Shift-Tab to go backwards. This even works for positional parameters. At a new prompt type Get-Service followed by a space. Then start pressing the Tab key. How cool is that!

Tip

This tab completion trick works with other things in PowerShell like WMI classes. Start typing a command like Get-WmiObject win32_ then wait a few seconds and start pressing Tab. You should be able to cycle through the class names. The names should be cached so that the next time you use Get-WmiObject or Get-CimInstance you can start tabbing immediately.

4.3. Typing trick: line continuation

Sometimes, typing in PowerShell can be frustrating. For example, you might find yourself looking at a strange prompt, like the following:

PS C:\> Get-Process -Name "svchost

>>

What the heck?

That “>>” prompt is PowerShell’s way of telling you, “I know you’re not finished typing, so keep going!” If you look carefully, you’ll notice that we forgot to include the closing quotation mark after “svchost.” PowerShell knows that quotes always come in pairs, so it’s waiting for us to finish typing the last quote. In this case, we goofed, so we press Ctrl-C to break out of that “continuation prompt” and try our command again.

Sometimes, this can be a useful trick. PowerShell will let you “continue” like this whenever you have an unclosed structure: Quotation marks, square brackets, curly brackets, and parentheses all enclose a structure. PowerShell will also let you “continue” when a line ends in a comma, pipe character, or semicolon, because those all tell it that there’s “more to come.” Finally, if a line ends in a backtick (`) and a carriage return, that also tells the shell to let you continue typing. Using these tricks, you can break a long, complex command onto several lines, as follows:

PS C:\> Get-Service -Name B*,

>> A*,

>> C* |

>> where {

>> $_.Status -eq 'Running'

>> } |

>> sort Status

>>

Status Name DisplayName

------ ---- -----------

Running COMSysApp COM+ System Application

Running CryptSvc Cryptographic Services

Running BFE Base Filtering Engine

Running ADWS Active Directory Web Services

Running AppHostSvc Application Host Helper Service

We ran the following command in the example:

Get-Service –Name B*,A*,C* | where { $_.Status –eq 'Running' } | sort Status

But we used PowerShell’s little “continuation” tricks to break it onto several lines. Notice that we had to press Enter on the final, blank line, to tell the shell that we were finally finished typing and that it should execute the command.

These same “continuation rules” apply when you’re in a script, too, and folks will use these rules to help format a script’s commands so that they’re more readable. In our case, we use them to help keep each line of the script short enough to fit in this book. In scripts we recommend the pipe character, braces, and commas. The backtick is usually not needed unless you have a very long line of code.

4.4. Parenthetical commands and expressions

Do you remember algebra? Whether you loved it or hated it, we hope you remember one thing: parentheses. In algebra, parentheses mean “do this first.” Take a mathematical expression like this one:

(5 + 5) * 10

The answer is 100, because you first add the 5 and 5, getting 10, and then multiply that by 10. When you were first learning algebra, you probably wrote out each step:

(5 + 5) * 10

10 * 10

100

PowerShell works the same way, both with mathematical expressions and with more complex commands.

For example, use Notepad to create a simple text file that includes one computer name per line. Figure 4.4 shows the text file.

Figure 4.4. Creating a list of computer names in Notepad

Next, return to PowerShell and display the contents of the file. You do this by running the Get-Content cmdlet, although you may be more familiar with the type or cat alias:

PS C:\> Get-Content names.txt

localhost

server-r2

windowsdc1

Suppose you want to retrieve a list of running processes from each of those computers. One way to do so involves typing their names:

Get-Process –ComputerName localhost,server-r2,windowsdc1

That’s going to become tedious if you have to keep doing it over and over. Because you’ve got the names in a text file, why not let PowerShell type the names for you?

Get-Process –ComputerName (Get-Content names.txt)

Think about algebra when you read this: PowerShell executes whatever’s inside the parentheses first. The parentheses will, in effect, be replaced by whatever is produced. So if you were going to write this out, step by step, as you would in algebra, it might look like the following:

Get-Process –ComputerName (Get-Content names.txt)

Get-Process –ComputerName localhost,server-r2,windowsdc1

That second version is exactly what you could’ve typed manually—but you let PowerShell arrive at that on its own. This demonstrates that a parenthetical expression, or parenthetical command, can stand in for any manually typed data. You only need to make sure that the command is producing the exact type of data that you’d have provided manually.

You’ll see a lot more examples of parenthetical commands as we progress through this book. It’s an important technique in PowerShell and one that we’ll reinforce as we go.

4.5. Script blocks

PowerShell supports a special kind of structure called a script block. A script block can contain any set of PowerShell commands, and it can contain as many of them as you need. In the same way that strings are enclosed in quotation marks, a script block is enclosed in curly brackets, or braces:

$sb={ Get-CimInstance –ClassName Win32_OperatingSystem ; Get-CimInstance

–ClassName Win32_ComputerSystem }

This example uses a semicolon to separate two commands, which allows them to each execute sequentially and independently. The script block has been saved to a variable, $sb. You could also have written the script block as follows:

$sb={

Get-CimInstance –ClassName Win32_OperatingSystem

Get-CimInstance –ClassName Win32_ComputerSystem

}

Separate code lines like the second example are generally easier to read if you have a complicated block of code. In any event, both commands are contained within that same script block. This can be passed as a single unit to anything capable of accepting a script block such as Invoke-Command. Script blocks can also be invoked using the call operator (&). We’re a bit early in the book to provide a real-world example of using script blocks, but we want to bring them to your attention. We’ll remind you of them when we’re ready to put them to use.

4.6. Summary

We’ve looked at some of the basics of PowerShell’s syntax. We have more to cover, but most of what’s ahead will build on these basics. Yes, PowerShell uses a lot of punctuation in its syntax: You’ve seen dashes, curly brackets, parentheses, semicolons, quotation marks, and a bit more in this chapter. Keeping track of all of them is the price of admission for using PowerShell. The shell can do a lot for you, but only after you learn to speak its language, so that you can tell it what you need. You’re on the right track, and this chapter covered some of the most important bits that you’ll need.

PowerShell is an extensible environment. We’ve mentioned the Active Directory and Exchange cmdlets in this chapter, both of which are delivered as extensions to the PowerShell base. In chapter 5 you’ll learn how to work with the PowerShell snap-ins and modules used to provide these extensions.