Getting Started with Windows PowerShell

Can’t figure out how to get started in Windows PowerShell? Hmmm, if only we could find an article titled Getting Started ....

First you put the key in the ignition… No, wait, that’s really not the best place to start. That’s not the first thing you should do when you’re learning about your car, and it’s certainly not the first thing you should do when you’re just getting to know Windows PowerShell. So where should you start? How about right here…

About Windows PowerShell

When you buy things you typically have some idea what it is you’re buying; for example, if you go out to buy a cell phone you probably have a pretty good idea what a cell phone is and what it does. And, like those other things, you probably already have some idea what Windows PowerShell is. It’s just a command window, right? Oh, no, it’s actually a scripting language. Wait, hang on; it’s a set of command-line tools….

If you’re sufficiently confused as to what, exactly, Windows PowerShell is, we’ll clear up some of that confusion right now: It’s all of those things we just mentioned. (And more.) Windows PowerShell is a command window with its own built-in commands (called cmdlets) and its own scripting language. If that sounds powerful, well, that’s because it is. If that sounds just a little scary, well …that’s what this introductory section of our Web site is for. Once you get familiar with Windows PowerShell, learn what all the parts and accessories are and how they work, it’s really not scary at all. As a matter of fact, it turns out it’s one of the most useful – uh, things that a Microsoft Windows system administrator can have at his or her disposal.

 

A Brief History

If you’re not a history buff you can skip this section. But because some people find this interesting, we threw it in.

When Windows PowerShell was first conceived, it was supposed to be a replacement for the age-old Windows command window (Cmd.exe). For example, there were going to be improvements such as being able to use Ctrl+C and Ctrl+V to copy and paste. Well, that part never actually happened. Instead, over a period of several years it morphed into something else. For a while it was going to be a way for UNIX administrators to feel more comfortable using Windows. UNIX administrators typically spend more time at the command line than Windows administrators, who tend to rely primarily on the graphical user interface (GUI) provided by Windows. So PowerShell was going to provide a more robust command-line experience for UNIX administrators.

PowerShell had been in development for several years and was struggling to take hold within the Windows group. Then along came the Microsoft Exchange team. This team was looking for a better way to manage Exchange from outside the GUI. They decided to work with the PowerShell team to produce an Exchange-specific implementation of Windows PowerShell. Following the Exchange team’s example, several other Microsoft Server products began adopting Windows PowerShell. The product finally shipped with Windows as an add-on to Windows Server 2008, and became integrated into the system as of Windows 7. The rest, as they say, is history.

Windows PowerShell 1.0 was released in 2006. The Windows 7 release, in 2009, is version 2.0 and includes some much-anticipated functionality, not the least of which is remote management.

And that’s the end of our history lesson. Glad you stuck around for it?

Oh. Well then, let’s move on.

All About Cmdlets

We’re going to start our discussion of PowerShell by talking about cmdlets (pronounced command-lets). Cmdlets are really what make PowerShell work; without cmdlets, PowerShell is little more than cmd.exe. (It is more, but definitely little more.) Before we explain what cmdlets do and how they work, we need to explain the cmdlet naming convention.

One thing that distinguishes PowerShell cmdlets from standard command-line tools is the way they’re named. Every PowerShell cmdlet consists of a verb followed by a dash followed by a noun. This combination not only identifies something as a cmdlet but it will typically give you a pretty good idea of what the cmdlet does. For example, here’s a cmdlet you’ll probably use quite often:

Get-Help

Notice the verb (Get), the dash ( - ), and the noun (Help). And what does this cmdlet do? That’s right, it gets you some help. (And no, unfortunately it doesn’t automatically call up a PowerShell expert and send them straight to your office. It simply displays helpful information to the command window. We’ll talk more about Get-Help in just a bit.)

Okay, quick test to see if you were paying attention. Which of these is a PowerShell cmdlet?

GetProcess

EventLogFinder

Eat-Dinner

Ipconfig

Get-Service

Directory-Read

If you chose Get-Service you’re right. Extra credit for anyone who noticed that Eat-Dinner follows the PowerShell naming convention and therefore could be a cmdlet.

Note: The PowerShell team does have pretty strict guidelines as to what verbs can and can’t be used. As of this writing, Eat was not on the list of approved verbs.

As we’ve implied (or at least as we meant to imply), a cmdlet carries out a specific action. We already mentioned the Get-Help cmdlet, which displays help text. Here’s another example:

Get-Service

Type that at the command prompt and you’ll see output similar to this:

Status Name DisplayName

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

Stopped AdtAgent Operations Manager Audit Forwarding...

Running AeLookupSvc Application Experience

Stopped ALG Application Layer Gateway Service

Running AppHostSvc Application Host Helper Service

Stopped Appinfo Application Information

Stopped AppMgmt Application Management

Stopped aspnet_state ASP.NET State Service

Running AudioEndpointBu... Windows Audio Endpoint Builder

Running AudioSrv Windows Audio

Running BFE Base Filtering Engine

Running BITS Background Intelligent Transfer Ser...

Stopped Browser Computer Browser

Running CcmExec SMS Agent Host

Running CertPropSvc Certificate Propagation

Stopped clr_optimizatio... Microsoft .NET Framework NGEN v2.0....

Stopped clr_optimizatio... Microsoft .NET Framework NGEN v2.0....

Stopped COMSysApp COM+ System Application

Running CryptSvc Cryptographic Services

Running CscService Offline Files

As you can see, this cmdlet retrieves a list of all the services on the local computer, along with certain information about those services (such as status).

Using Cmdlet Parameters

It’s possible there are a lot of services on your local computer. What if you’re interested in only one of those services? You don’t need a big, long scrolling list of all the services, you just want to see that one service. For example, let’s say you want to find out if the Windows Update service is running on your computer. You could type Get-Service at the command prompt, hit Enter, then search through the list for the row containing a DisplayName of Windows Update. But there’s an easier way:

Get-Service -DisplayName "Windows Update"

What we’ve done here is pass a parameter to the Get-Service cmdlet. A parameter is a way of handing additional information to a cmdlet. In this case we’ve used the –DisplayName parameter, followed by the value “Windows Update” to tell the Get-Service cmdlet to get only those services with a DisplayName property equal to Windows Update. (The quotes around Windows Update are required only because the string contains a space.)

Notice one very important thing: the parameter name begins with a dash (-). All cmdlet parameters begin with a dash. In addition, the value you want to assign to the parameter always immediately follows the name of the parameter.

Here’s what we get back from our Get-Service cmdlet with the parameter -DisplayName “Windows Update”:

Status Name DisplayName

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

Running wuauserv Windows Update

We can now easily see that our Windows Update service is Running. (Phew!)

Another way we could have accomplished this same thing would have been to pass the -Name parameter and specify the Name value (which is different from the DisplayName) we’re looking for:

Get-Service -Name wuauserv

And once again, here’s what we get back:

Status Name DisplayName

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

Running wuauserv Windows Update

Still running.

Note: We’ve been showing all our cmdlets and parameters in mixed case. And that’s fine: PowerShell is not case-sensitive. Type this at the command prompt and your results will be the same:

get-service –name wuauserv

Or even this:

geT-sERVICE –naMe WUAuserv

Wildcards

Another thing you can do in PowerShell to further refine your results is to use wildcards. The primary wildcard characters in PowerShell are the asterisk (*), representing one or more characters, and the question mark (?), representing a single character. For example, suppose we want to find all the services whose DisplayName starts with the word Windows. All you need to do is include the wildcard:

Get-Service -DisplayName windows*

Depending on which services you have on your computer, you’ll get back something like this:

Status Name DisplayName

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

Running AudioEndpointBu... Windows Audio Endpoint Builder

Running AudioSrv Windows Audio

Running Eventlog Windows Event Log

Stopped FontCache3.0.0.0 Windows Presentation Foundation Fon...

Stopped idsvc Windows CardSpace

Running MpsSvc Windows Firewall

Stopped msiserver Windows Installer

Running RapiMgr Windows Mobile-based device connect...

Stopped SDRSVC Windows Backup

Running stisvc Windows Image Acquisition (WIA)

Stopped TrustedInstaller Windows Modules Installer

Notice that the DisplayName in each row begins with the string “windows”. The string “windows*” tells the cmdlet to get all services where the DisplayName begins with the characters windows followed by one or more other characters.

You can also put more than one wildcard character within your value:

Get-Service -DisplayName *audio*

Here we’re simply saying “return all services where the DisplayName starts with any character or characters, contains the string audio, then ends with any character or characters.” Here’s what we got back on our test machine:

Status Name DisplayName

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

Running AudioEndpointBu... Windows Audio Endpoint Builder

Running AudioSrv Windows Audio

Stopped QWAVE Quality Windows Audio Video Experience

Multiple Parameters

Now that you know how wildcards work, that will help us demonstrate the next thing you need to know about parameters: multiple parameters. Depending on the cmdlet and the parameters available to it, you can specify more than one parameter at a time. For example, suppose we want to display all the services that have a display name beginning with windows (remember we saw how to do that: -DisplayName windows*). But wait: we don’t really want all those services. Instead, we want to exclude any that contain the word audio in the Name or DisplayName. Here’s how we do that:

Get-Service -DisplayName windows* -Exclude *audio*

And here’s what we get back:

Status Name DisplayName

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

Running Eventlog Windows Event Log

Stopped FontCache3.0.0.0 Windows Presentation Foundation Fon...

Stopped idsvc Windows CardSpace

Running MpsSvc Windows Firewall

Stopped msiserver Windows Installer

Running RapiMgr Windows Mobile-based device connect...

Stopped SDRSVC Windows Backup

Running stisvc Windows Image Acquisition (WIA)

Stopped TrustedInstaller Windows Modules Installer

Running W32Time Windows Time

As you can see, we once again have a list of services whose DisplayNames begin with windows; however, this list does not include those services that have the word audio anywhere within their names. We did this by specifying first the DisplayName value using the –DisplayName parameter, then specifying the string we want to exclude (*audio*) as the value for the –Exclude parameter.

That’s what we said: wow.

Positional vs. Named Parameters

Here’s a question for you: Let’s say you’re driving your car and you make a right turn. The road you’re turning onto has two lanes going that direction, and you will shortly need to be in the left-hand lane. Do you dutifully turn into the right lane (the lane closest to you), drive for a bit, turn on your left turn signal and carefully change lanes? Or do you simply turn right into the left lane?

Go ahead, you can admit it; you turn directly into the left lane, don’t you? While this may or may not be a legal move where you live, in PowerShell it’s not only legal but you’re encouraged to take as many shortcuts and wide turns as are convenient to you. (And you don’t even need to use your turn signal.) Positional parameters are an example of this.

Take a look at this example:

Get-Process

When you type this cmdlet at the PowerShell command prompt and press Enter you’ll get back a list of all the processes running on the local computer. Now let’s add a parameter, the process name:

Get-Process -Name svchost

This will return a list of all processes where the Name of the process is svchost:

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

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

 324 5 3496 6972 47 2.28 864 svchost

 492 8 4364 7908 46 0.09 924 svchost

 349 14 57624 42824 133 1.36 1036 svchost

 503 14 14292 12768 72 0.11 1208 svchost

 757 17 76256 82296 184 8.76 1264 svchost

2571 52 185500 195380 347 3.77 1276 svchost

 569 25 7548 13388 79 4.15 1468 svchost

1017 27 16332 20852 117 3.33 1720 svchost

 318 25 53524 57428 116 9.96 1956 svchost

Now let’s call Get-Process with a different parameter, this time looking for a process with the ID of 864:

Get-Process -Id 864

And here’s what we get:

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

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

 324 5 3496 6972 47 2.28 864 svchost

You’re probably wondering where the shortcuts and wide turns come in. Be patient, we’re getting there.

Try this:

Get-Process svchost

Notice that we left off the -Name parameter, we specified only the value. And what happened? We got the exact same results we got when we did included the -Name parameter:

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

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

 324 5 3496 6972 47 2.28 864 svchost

 492 8 4364 7908 46 0.09 924 svchost

 349 14 57624 42824 133 1.36 1036 svchost

 503 14 14292 12768 72 0.11 1208 svchost

 757 17 76256 82296 184 8.76 1264 svchost

2571 52 185500 195380 347 3.77 1276 svchost

 569 25 7548 13388 79 4.15 1468 svchost

1017 27 16332 20852 117 3.33 1720 svchost

 318 25 53524 57428 116 9.96 1956 svchost

The reason we can do this is because the -Name parameter is a positional parameter. Get-Process knows that the first value following the cmdlet name (the value at parameter position 1) is the value for the -Name parameter. You can see how this works by trying the same thing with the ID:

Get-Process 864

What did you get back? Hey, that’s what we got back, too:

Get-Process : Cannot find a process with the name "864". Verify the process name and call the cmdlet again.

Get-Process assumes that if a parameter name isn’t specified then the first value is the Name. What it’s trying to do here is find a process with the name 864, which, of course, it couldn’t do; that’s because there is no such process. What all this means is that if you’re going to specify an ID, you have to tell Get-Process that you’re specifying an ID by including the -Id parameter. There’s no other way for Get-Process to know that the value you’ve put in your command is the ID. The -Id parameter is a named parameter (you must include the parameter name before the value), while the -Name parameter is a positional parameter (the cmdlet can identify the parameter based on where the value is positioned in the command).

Finding Cmdlets

Okay, so we’ve talked about cmdlets, explained what they are, and even showed you a couple of them. One of the things we noted about cmdlets is that they are the heart and soul of Windows PowerShell. Well, that’s great, but how do you find out what cmdlets there are? After all, cmdlets don’t do you much good if you don’t know about them.

It’s time to tell you something about Windows PowerShell, something we haven’t mentioned yet: PowerShell has a bit of an ego. Yes, it’s true. After spending a little time with PowerShell you’ll find that one thing it’s very, very good at is telling you all about itself. You can try talking about yourself now and then, but PowerShell will largely ignore you. Ask it about itself, however, and you’ll get an earful (or at least a screenfull). One example of this is how much PowerShell will tell you about its cmdlets. Do you want to know all of the cmdlets available in Windows PowerShell? Well, there’s a cmdlet for that:

Get-Command

Type Get-Command at the command prompt and you’ll get a big, long scrolling list of not only all the cmdlets available but also all of the functions, applications, and various other things. If you want to see only the cmdlets, type this:

Get-Command –CommandType cmdlet

Once again you’ll get a big, long scrolling list (there are over 200 cmdlets, after all), starting something like this:

CommandType Name Definition

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

Cmdlet Add-Computer Add-Computer [-DomainName] <String> [-Cr...

Cmdlet Add-Content Add-Content [-Path] <String[]> [-Value] ...

Cmdlet Add-History Add-History [[-InputObject] <PSObject[]>...

Cmdlet Add-Member Add-Member [-MemberType] <PSMemberTypes>...

Cmdlet Add-PSSnapin Add-PSSnapin [-Name] <String[]> [-PassTh...

Cmdlet Add-Type Add-Type [-TypeDefinition] <String> [-La...

Here’s a little trick that might come in handy: to keep the list from scrolling by too quickly to read, add the pipeline symbol (|) and the word more to the end of your command (we’ll explain the pipeline symbol later):

Get-Command –CommandType cmdlet | more

This command will show you all the cmdlets one screen at a time; simply press the spacebar when you’re ready to move on to the next page.

Another thing you can do is narrow down your list a bit. For example, maybe you only want to retrieve the cmdlets that start with the verb New (and yes, in the PowerShell world “New” is a verb). To do this you use the -Verb parameter with the value New:

Get-Command -Verb new

From that you get back a list something like this:

CommandType Name Definition

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

Cmdlet New-Alias New-Alias [-Name] <String> [-Value]...

Cmdlet New-Event New-Event [-SourceIdentifier] <Stri...

Cmdlet New-EventLog New-EventLog [-LogName] <String> [-...

Cmdlet New-Item New-Item [-Path] <String[]> [-ItemT...

Cmdlet New-ItemProperty New-ItemProperty [-Path] <String[]>...

Cmdlet New-Module New-Module [-ScriptBlock] <ScriptBl...

Cmdlet New-ModuleManifest New-ModuleManifest [-Path] <String>...

Cmdlet New-Object New-Object [-TypeName] <String> [[-...

Cmdlet New-PSDrive New-PSDrive [-Name] <String> [-PSPr...

Or maybe you want to find all the cmdlets that have to do with the event log. That’s easy:

Get-Command -Noun eventlog

And look what we get back:

CommandType Name Definition

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

Cmdlet Clear-EventLog Clear-EventLog [-LogName] <String[]> ...

Cmdlet Get-EventLog Get-EventLog [-LogName] <String> [[-I...

Cmdlet Limit-EventLog Limit-EventLog [-LogName] <String[]> ...

Cmdlet New-EventLog New-EventLog [-LogName] <String> [-So...

Cmdlet Remove-EventLog Remove-EventLog [-LogName] <String[]>...

Cmdlet Show-EventLog Show-EventLog [[-ComputerName] <Strin...

Cmdlet Write-EventLog Write-EventLog [-LogName] <String> [-...

You can also use wildcards with Get-Command. Let’s find all cmdlets with the word Item in them:

Get-Command -CommandType cmdlet *item*

Notice that we didn’t specify a parameter name before the *item* string; that’s because the -Name parameter is a positional parameter, which means that Get-Command knows that *item* is the value for the -Name parameter. Once again, take a look at the output:

CommandType Name Definition

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

Cmdlet Clear-Item Clear-Item [-Path] <String[]> [-For...

Cmdlet Clear-ItemProperty Clear-ItemProperty [-Path] <String[...

Cmdlet Copy-Item Copy-Item [-Path] <String[]> [[-Des...

Cmdlet Copy-ItemProperty Copy-ItemProperty [-Path] <String[]...

Cmdlet Get-ChildItem Get-ChildItem [[-Path] <String[]>] ...

Getting Help

This is all making perfect sense so far, right? (Just nod your head and keep reading.) But how are you ever going to know which parameters do what, where they go, or even which parameters are available? How are you going to figure out exactly how to use each cmdlet, or what each cmdlet is supposed to do?

Remember how we told you about PowerShell’s ego? Once again, PowerShell is more than happy to tell you all about itself, including just about anything you could want to know about its cmdlets. All you need to do is ask for some help:

Get-Help

Type Get-Help at the command prompt and press Enter and PowerShell will display help on the screen. As you’ll see, typing Get-Help by itself simply gives you some help on the Get-Help cmdlet. If you want help with a different cmdlet, type the cmdlet name in as the first parameter. For example, to find out about the Get-Process cmdlet, type this at the command prompt:

Get-Help Get-Process

This will give you some help. You’ll get a description and some syntax statements. But that’s not really much help. What you’d really like to see are some examples of how to use the cmdlet. For that you can add the -Examples parameter. Give it a try and see what you get:

Get-Help Get-Process –Examples

That’s more like it. Of course, now all you have is examples, you don’t have a full description anymore. And you still don’t know what all the parameters are or what they do. If you want all the available help on a cmdlet – including examples – use the -Full parameter, like this:

Get-Help Get-Process –Full

Now, all that is great when you want to know about a specific cmdlet. But what if you want some general PowerShell information? Suppose, for example, you want to know more about how parameters work. (Yes, there is even more than what we’ve told you. Hard to believe, isn’t it?) To get more general information, you can check the “about” help topics. Want to know more about parameters? Type this:

Get-Help about_parameters

If you want to know which topics are available as about topics, as usual, just ask PowerShell. Use the wildcard character to retrieve a list of all about help topics:

Get-Help about*

This will retrieve a list which starts out something like this:

Name Category Synopsis

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

about_aliases HelpFile Describes how to use alternat...

about_Arithmetic_Operators HelpFile Describes the operators that ...

about_arrays HelpFile Describes a compact data stru...

about_Assignment_Operators HelpFile Describes how to use operator...

about_Automatic_Variables HelpFile Describes variables that stor...

about_Break HelpFile Describes a statement you can...

about_command_precedence HelpFile Describes how Windows PowerSh...

about_Command_Syntax HelpFile Describes the notation used f...

Getting Around

We’ve talked a lot about cmdlets (they are, after all, the heart and soul of PowerShell – did we mention that?), but we haven’t talked about the PowerShell window itself. For example, how do you navigate your way around the file system? The good news is, if you know how to navigate around the file system in the Cmd.exe window, then you know how to navigate around the file system in Windows PowerShell. The better news is that, if you know how to navigate around the file system, you also have a pretty good idea how to navigate around the registry. Yes, you read that right, the Windows system registry. But first things first.

To change from one directory to another, you can use the cd command, like this:

PS C:\> cd scripts

Press Enter and you’ll navigate to the Scripts folder:

PS C:\Scripts>

Tip: In PowerShell, cd is actually an alias for the Set-Location cmdlet. (Remember, we told you it was all about cmdlets in PowerShell.) So the command Set-Location scripts is the same as cd scripts. To find out more about aliases, see the Aliases article

You can also display the contents of the current directory with the dir command:

PS C:\scripts> dir

Directory: C:\scripts

Mode LastWriteTime Length Name

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

d---- 5/29/2008 8:37 PM audio

d---- 9/6/2007 2:14 PM begin

-a--- 5/20/2008 12:46 PM 26 application.log

-a--- 10/31/2007 9:58 PM 155 Audits.xml

-a--- 2/5/2008 11:00 AM 54 computers.txt

-a--- 5/8/2008 1:27 PM 19 conv.ps1

Tip: The dir command is an alias for the Get-ChildItem cmdlet. If you’re used to working with UNIX, you might want to use the ls command, which is also an alias for Get-ChildItem and, like dir, will retrieve the contents of the current directory.

We mentioned you can do the same thing with the registry. Suppose you want to take a look at the HKEY_CURRENT_USER hive of the registry. You can start by moving out of the file system and into that hive, like this:

PS C:\Scripts> cd HKCU:

Press Enter and notice the command prompt:

PS HKCU:\>

Try typing dir and you’ll see that you really are in the registry. Simply type C: and press Enter to return to the file system.

Start Your Engine

Now it’s finally time to get your key out and put it in the ignition. You’ve learned how to start up Windows PowerShell and drive responsibly. But don’t worry: we have plenty of additional articles that will teach you much more (and trust us, there really is a lot more to lear)n. For example, we haven’t even mentioned the tailpipe – er, the pipeline – in Windows PowerShell. You’ll definitely want to know about that. (See Piping and the Pipeline. )

Hey, we haven’t steered you wrong yet, have we?