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?