Windows

Top 10 Tips for Using Windows PowerShell

_침묵_ 2006. 11. 13. 19:03
사용자 삽입 이미지
   
 Published onWindows DevCenter(http://www.windowsdevcenter.com/)
 http://www.windowsdevcenter.com/pub/a/windows/2006/11/07/top-10-tips-for-using-windows-powershell.html
 See thisif you're having trouble printing code examples


Top 10 Tips for Using Windows PowerShell

byJeff Cogswell
11/07/2006

PowerShell is Microsoft's newest replacement for the command line. It's still in beta, andthe latest version is available free for download here. For us older folks, we've had to deal with DOS in the past, and then we've held on to the CMD.exe program, which is pretty much the same as a DOS command prompt running under Windows. PowerShell is not an updated version of DOS. Rather, it's a complete command-line system that is far more powerful than any command-line prompt Microsoft has given us before. Starting to learn it, unfortunately, can be a bit overwhelming at first. After you've installed it and explored it a bit, the following tips will help make your life much easier.

1. Remember the consistencies

Remember that commands have a verb-noun format and parameter names start with a -. You can use either / or \ in paths.

Probably the most basic, fundamental rule in using PowerShell is that the commands all have a common format. When you remember the format, you can more easily remember the commands.

The format is verb-noun. For example:

Set-DateWrite-DebugGet-ItemGet-WmiObject

Each of these is a verb followed by a hyphen followed by a noun. Further, the noun is singular, even if it seems like it should be plural. Thus:

Get-Process

returns all the running processes.

But the consistency goes beyond just the names. Parameters are consistent. In the worlds of DOS and Unix, commands either use - or / to denote a parameter name. In PowerShell, all parameter names start with -.

However, path names, on the other hand, can be separated by either a forward slash or a backward slash. You can use either, whichever you're most comfortable with. If you need to combine paths, however, you can easily use the built-in command join-path like so:

join-path c:\ \temp

which results in c:\temp. (This is handy because you don't have to manually remove the extra slashes that might result in just combining the two strings.)

2. Remember the useful commands

UseGet-Commandto get a list of commands andGet-Helpto find out help on the commands. You can also pass-?as a parameter to a command to obtain help. UseTabExpansion(and, optionally, find aTabExpansionreplacement).

Whenever you're using a new language, you want to know the vocabulary. The second release candidate of PowerShell contains 129 commands. That's a lot to learn and memorize. But you'll want to be at least familiar with what's available, and you'll want to make sure you know some of the more common ones. To see all the commands type

Get-Command

One command isGet-Help. You can use this to find out help on a particular command:

Get-Help Get-Member

will display help on the commandGet-Member. Or you can pass-?as a parameter like so:

Get-Member -?

The built-in commands also provide different levels of help. The default help provides basic information. You can get more help providing details on the parameters along with examples by adding-detailedto theGet-Helpcommand:

Get-Help Get-Member -detailed

And you can get even more help by typing-full:

Get-Help Get-Member -full

Since many commands are long and we, as computer people, usually don't want to type huge commands, PowerShell includes an alias feature along with several built-in aliases. You can list all the aliases like so:

PS C:\WINDOWS\system32> Get-AliasCommandType     Name            Definition-----------     ----            ----------Alias           ac              Add-ContentAlias           asnp            Add-PSSnapinAlias           clc             Clear-ContentAlias           cli             Clear-ItemAlias           clp             Clear-ItemProperty...

The Tab key has a special usage that helps you find commands. If you remember the verb, you can type the verb then the hyphen, and press Tab repeatedly to cycle through the different possible commands starting with that verb. If you type:

Get-

and then start pressing Tab, you'll seeGet-Acl, thenGet-Alias, thenGet-AuthenticodeSignature, and so on.

However, the built-in tab expansion feature isn't that sophisticated, and Microsoft knows it. That's why it made a function called TabExpansion that can be modified. Search the web for PowerShell TabExpansion (no space in the second word) and see what's out there. People have written TabExpansion replacements and there are some pretty good ones out there. Find one that suits your needs. (Incidentally, you can see the source for the TabExpansion function usingGet-Content function:TabExpansion.)

Here's a list of some of the commands I find myself using often. When you use commands, you'll probably want to know any available aliases as well.

Command Aliases

CommandAliases
Copy-Itemcpi, cp, copy
ForEach-Objectforeach, %
Get-ChildItemdir, ls
Get-Commandgcm
Get-Contentcat, type
Get-Contentgc, type, cat
Get-Helphelp
Get-Locationgl, pwd
Move-Itemmi, mv, move
Remove-Itemri, rd, del, rm, rmdir
Rename-Itemrni, ren
Set-Locationcd, chdir
Where-Objectwhere

Get-Commandtakes some parameters to help you find the commands you need. For example, if you're looking for commands that have the word Format in them, you can type:

Get-Command *Format*

However, you might only want the commands that start with the verb Format (such asFormat-Table). This will work:

Get-Command -verb Format

That will return the commands whose verb is exactly Format. If you type

Get-Command -verb Form

you will not get back those with the verb Format unless you use a wildcard pattern:

Get-Command -verb Form*

You can similarly specify the noun:

Get-Command -noun Alias

will list all commands dealing with aliases.

There's also a couple handy single-character aliases.%is an alias forForEach-Objectand?is an alias forWhere-Object.

3. Learn the fundamental types and built-in variables

Learn the fundamental types and how the parser recognizes them. Master regular expressions so your life will be complete.

The PowerShell scripting language includes several basic types that are useful in your work. And, you can create variables of these types. You have at your disposal all the built-in types in .NET. This includes, for example, strings, numbers, arrays, and dictionaries (which some people know as hashes or maps). The types are all built around the .NET types. (I talk about .NET in the next section.)

The command parser will decide the types based on what you type. For example, if you type

5

you will be specifying an integer. Variable names get a$before them, and you can store the integer like so:

PS C:\> $a = 5PS C:\> $a5PS C:\>

You can determine the built-in .NET type by callingGetType():

PS C:\> $a.GetType()IsPublic IsSerial Name              BaseType-------- -------- ----              --------True     True     Int32             System.ValueType

The parser also recognizes other basic types. Doubles can be created with a decimal point:

PS C:\> $b = 3.1415926PS C:\> $b3.1415926PS C:\> $b.GetType().NameDouble

Like many of today's scripting languages, you can use either single or double quotes for strings, whichever is convenient for the problem at hand. For example, if you need double-quotes in the string, you can use single quotes for the string itself:

$c = '<span style="border:1px solid none">'

To create an array, just provide a list of comma-separated items:

PS C:\> $d = 1,2,3,"Hello"PS C:\> $d123HelloPS C:\> $d.GetType()IsPublic IsSerial Name                                     BaseType-------- -------- ----                                     --------True     True     Object[]                                 System.Array

If necessary, you can put parentheses around the array. This is useful for arrays of arrays:

$e = (1,2,3,(4,5,6))

You can specify ranges of integers using the .. operator like so:

$f = 1..5

will create an array containing 1,2,3,4,5.

To create a dictionary, use the@symbol like so:

PS C:\> $myhash = @{ 'one'=1; 'two'=2; 'three'=3 }PS C:\> $myhashName                           Value----                           -----two                            2three                          3one                            1PS C:\> $myhash['one']1PS C:\> $myhash['four']PS C:\>

Since .NET includes powerful regular expression capabilities, PowerShell includes a regex type. Just put the wordregexin brackets ([]) before a string to create a regular expression. Then you can use the regular expression with the -match operators. Here's an example:

PS C:\> $re = [regex]"abc[123]"PS C:\> "abc1" -match $reTruePS C:\> "abc4" -match $reFalsePS C:\>

If you're not familiar with regular expressions, then now is a great time to learn them. The more you know regular expressions, the easier time you'll have with PowerShell as well as many programming languages. Go to your favorite search engine and type in "learn regular expressions". There are several good pages out there. But probably the best source is the O'Reilly bookMastering Regular Expressionsby Jeffrey Friedl. This is one of the few books that should be required reading for every computer professional.

The shell includes some built-in variables that you can use, too. Here are some of them:

  • $$: Last token of previous line
  • $?: Last success/fail status
  • $^: First token of previous line
  • $pshome: The installation directory of PowerShell. This is useful if you're going to modify some of the configuration files, such as types.ps1xml, like so:

    scite (join-path $pshome types.ps1xml)

(Sciteis the free text editor I use.)

If you want to use a specific type without relying on the parse, PowerShell comes with several built-in type shortcuts. A type shortcut is a shortened form of a type name. The Microsoft PowerShell's blog includes anentry listing some of them.

Learning and understanding the types can be unwieldy, however, especially if a command returns an object of a type you're not familiar with. If you're savvy with reading online helps,this blog entryis a way to enhance your PowerShell so you can access the online help for any object's type.

(If you make this change, you'll have to re-sign your file. See the tip "Customize your environment" for more information.) When you implement this modification, you can find the online help for any object's type. The technique isn't perfect and doesn't work for every object, but it does work most of the time.

4. Know your .NET

The .NET framework is the foundation on which PowerShell runs. The more you know about .NET, the better your PowerShell experience will be.

To get the most out of PowerShell, you should be familiar with the .NET framework. The framework's help is available online in its entirety at. Scroll down to the System heading. This is where you'll find the basic types such as Int32, String, and Array.

Remember, the framework is simply a huge collection of classes and types that you can use in your PowerShell work. The more you know of these types, the better off you are. If you look up entries on your types, you'll know what you can do with objects. For example, if you click the page for System, scroll down and click String, you'll get the entry for the String class.

Most of the commands return an object (or a set of objects) that are, in fact, .NET objects. For example, theGet-Datecommand on the surface may appear to just print out the current date and time. But in fact, it returns an object of typeDateTime, which is part of the .NET framework. Similarly, if you typeGet-ChildItem(or an alias,dir), you see a directory listing, but in fact, are looking at a list of objects, each of which is either aDirectoryInfoor aFileInfoobject. These are .NET classes.

The .NET framework is organized into a huge hierarchy, with all classes being derived fromObject. TheObjectclass provides some base functionality common to every single class in .NET. One base functionality is a function calledToString. This function returns a text representation of an object. The way this pertains to PowerShell is that given any object, you can always get a string representation of it. (In fact, this is exactly how PowerShell prints out an object to the console.)

5. Understand the pipeline is object-based not text-based

Remember that objects are passed through the pipeline, not just text, which means a great deal of information is available to you at any point in the pipe.

If you've worked with other shells such as cmd in Windows or any of the Unix-based shells, you know that commands can output text, which can in turn be passed (piped) to other commands. For example, in cmd and DOS, thedircommand prints out a list of files. This list is in the form of text. If you just run thedircommand, you'll see the list appear in the console window. However, you can instead send that text as input into another command; this is called piping. The more command, for example, reads in text and writes out only a page worth, and then waits for a keypress before writing another page worth of text:

C:\WINDOWS >dir /ad | more Volume in drive C has no label. Volume Serial Number is BCFB-2313 Directory of C:\WINDOWS11/04/2006  10:59 PM    <DIR>          .11/04/2006  10:59 PM    <DIR>          ..06/07/2004  07:03 PM    <DIR>          $NtUninstallKB824105$06/07/2004  07:05 PM    <DIR>          $NtUninstallKB824141$10/15/2004  09:06 PM    <DIR>          $NtUninstallKB824151$06/07/2004  07:01 PM    <DIR>          $NtUninstallKB825119$06/07/2004  07:00 PM    <DIR>          $NtUninstallKB828035$06/07/2004  06:58 PM    <DIR>          $NtUninstallKB828741$06/07/2004  06:59 PM    <DIR>          $NtUninstallKB833407$-- More  --

Over the years, people have taken the fact that this pipe is text and written some really powerful utilities to manipulate the text. Years ago, awk and grep arrived, which let you process the text. (awk, for example, could easily take the preceding text and break up the lines into records divided by spaces. grep lets you search through the text for patterns; people still use grep a lot.) Today we have even more powerful languages for text processing, such as Perl.

While simple commands in DOS such asdiruse text, more powerful tools work with objects. If you're managing a set of processes on a Windows system, a single process is not just a line of text. A single process is an object made up of more objects such as the ID for the process, the security settings, and so on. These are more than just text.

If a tool retrieves a set of processes and then writes the information out just as text for another tool to use, the second tool is getting cheated. The tool is only getting a text-based form of the processes, not the actual objects.

A better approach, then, is to simply let the first tool pipe the actual objects on to the second tool. At first this might seem like a problem since ultimately we are dealing with a console window which displays text. But if you think about thedir | morecommands working together, the only output that finally makes it to the console window is the output from the more. The information passed fromdirtomoreis never displayed on the console.

Of course, eventually the objects do have to be displayed as text in the console window. That's where theToStringmethod comes in that I mentioned in the previous section. At the end of the pipeline the console can simply callToStringto get a text-representation of the object, and write that text to the console window.

Here's an example:

PS C:\WINDOWS> dir | sort LastWriteTime | more    Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWSMode                LastWriteTime     Length Name----                -------------     ------ -----a---          7/4/1995   1:33 PM      11776 Ckrfresh.exe-a---         7/31/1995   5:44 PM     212480 PCDLIB32.DLL-a---          5/3/1996  10:36 AM      18432 Setup_ck.dll-ar--          5/3/1996  12:21 PM      27648 Setup_ck.exe-a---         7/22/1998  12:29 AM         21 CS_SETUP.ini-a---        10/29/1998   3:45 PM     306688 IsUninst.exe-a---         1/12/1999  10:39 AM       6656 delttsul.exe-a---         1/12/1999  10:40 AM      29184 rmud.exe-a---         6/18/1999   4:49 PM     165888 Ckconfig.exe-a---        11/10/1999   3:05 PM      86016 unvise32qt.exe...

(diris an alias forGet-Children, sort is an alias forSort-Object, and more is a function that callsOut-Host -paging. Thus,dir | sort LastWriteTime | moreis shorthand forGet-ChildItem | Sort-Object LastWriteTime | Out-Host -Paging.)

This example lists the directory contents, sorts it on theLastWriteTimefield, and then writes it out per page. But since the objects pass through the pipeline and are only converted to text at the end, you can save the results of any output into a variable, preserving the types, like so:

PS C:\WINDOWS> $a = dir | sort LastWriteTime

The variable$anow contains the results of the Sort-Object command, but the contents of$ais not text. The data is preserved. Thedircommand (Get-ChildItem) returned an array ofFileInfoandDirectoryInfoobjects, which was piped through thesort(Sort-Object) command. Thus,$ais an array ofFileInfoandDirectoryInfoobjects. You can access the individual elements using brackets like so:

PS C:\WINDOWS> $a[0]    Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWSMode                LastWriteTime     Length Name----                -------------     ------ -----a---          7/4/1995   1:33 PM      11776 Ckrfresh.exePS C:\WINDOWS> $a[1]    Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWSMode                LastWriteTime     Length Name----                -------------     ------ -----a---         7/31/1995   5:44 PM     212480 PCDLIB32.DLL

In the next section I talk about calling methods on objects in more detail but here you can see that if you callGetTypeon the objects you can see for sure the type of objects you have (and that they definitely aren't text strings). Here I find out the type of my$avariable:

PS C:\WINDOWS> $a.GetType()IsPublic IsSerial Name                BaseType-------- -------- ----                --------True     True     Object[]            System.Array

The $a object is an array. Let's see what the first element is:

PS C:\WINDOWS> $a[0].GetType()IsPublic IsSerial Name                BaseType-------- -------- ----                --------True     True     FileInfo            System.IO.FileSystemInfo

6. Make use of the objects and their members

The objects that pass through the pipe are instances of classes. You can make use of their methods and data.

Don't forget that your objects, including those that are the results of the commands, have members that you can make use of. You can find an object's members using theGet-Membercommand:

PS C:\Documents and Settings\Jeff> $a = "abc"PS C:\Documents and Settings\Jeff> Get-Member -InputObject $a   TypeName: System.StringName             MemberType            Definition----             ----------            ----------Clone            Method                System.Object Clone()CompareTo        Method                System.Int32 CompareTo(Object value),...Contains         Method                System.Boolean Contains(String value)CopyTo           Method                System.Void CopyTo(Int32 sourceIndex,...EndsWith         Method                System.Boolean EndsWith(String value)......

If you pipe the output from one command throughGet-Member,Get-Memberwill list the members for each type of object that comes through. If two objects come through and they are of the same type,Get-Memberwill only list the members once for that type. For example, if you want to know what members are available of the objects returned by theGet-Processcommand, pipe the results throughGet-Member, like so:

PS C:\Documents and Settings\Jeff> Get-Process | Get-Member   TypeName: System.Diagnostics.ProcessName                           MemberType     Definition----                           ----------     ----------Handles                        AliasProperty  Handles = HandlecountName                           AliasProperty  Name = ProcessNameNPM                            AliasProperty  NPM = NonpagedSystemMemorySizePM                             AliasProperty  PM = PagedMemorySizeVM                             AliasProperty  VM = VirtualMemorySizeWS                             AliasProperty  WS = WorkingSetadd_Disposed                   Method         System.Void add_Disposed(Event...add_ErrorDataReceived          Method         System.Void add_ErrorDataRecei......

TheWhere-Objectcommand can be used to filter objects in the pipeline, allowing only objects through that meet the criteria you specify. To specify criteria, you will access the members of the objects passing through the pipeline.

For example, although I didn't include the full output here, theGet-Process | Get-Memberresults showed me the objects in the results ofGet-Processeach have a member calledVirtualMemorySize. Suppose, then, I want to list all processes that have a virtual memory size greater than 100 MB (which is 104,857,600 bytes). Here's how I can do it:

PS C:\Documents and Settings\Jeff> Get-Process | Where-Object {$_.VirtualMemorySize -gt 104857600}Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName-------  ------    -----      ----- -----   ------     -- -----------    948      15    38928      52788   346    12.23    712 dexplore    256      10    72624      81592   194   136.00   2664 firefox    350      14    30948      44268   133     7.06   3576 OUTLOOK    309       8    31928       6404   833   221.14    356 sqlservr    334       9    22188      14784   817     0.53    852 sqlservr   1598      91    18668      27404   142   156.75   1864 svchost    356      24    15708      23740   169   201.47   1536 WINWORD

TheWhere-Objectcommand takes a parameter that is a script in curly braces. The script runs for each object passing through the pipeline. As each object passes through, it gets placed in the variable called$_. Thus,$_.VirtualMemorySizerefers to theVirtualMemorySizemember of the object currently in the pipeline. The-gtis the comparison operator for greater than; thus, I'm testing if the current object has a virtual memory size of greater than 104,857,600 bytes.

Get-ChildItem | foreach { $_.Fullname }

As you can see, you should be familiar with the members of the objects, which can be found in the online help. If you go to the online help page, scroll down and click on System, scroll down and click on String, you'll be at the help page for the String class. At the very bottom (as well as in the tree in the left pane) is an item called String Members. That page lists all the members for the String class.

For example, one member is EndsWith. This tells you if a string ends with a given set of characters. You're free to use this member. Here's a quick example:

PS C:\> $a = "This is a test"PS C:\> $a.EndsWith("test")TruePS C:\> $a.EndsWith("this")FalsePS C:\>

7. Format your output

You have full control of how the format looks of your output using the variousFormat-commands.

PowerShell shuttles objects through the pipeline and only obtains the text version of the objects when ready for display, unless told to do otherwise with the commands. If you look at the list of members in the objects that come out ofGet-Process, however, you'll see far more than what you see in the output. Which members appear in the output? The answer comes from the system configuration. Inside the Windows PowerShell directory is a file calleddotnettypes.format.ps1xml. This is an XML file that describes the formatting to be used in the output of various types. There are actually several such files, each describing different types, each with the filename pattern*.format.ps1xml. Others includepowershellcore.format.ps1xmlandfilesystem.format.ps1xml. You can learn more about these fileshere.

To format the output, PowerShell users a command calledFormatTable. This command takes a pipeline of objects and writes them out using the format defined as the*.format.ps1xml files.

You can, however, override the settings and choose which members appear in the output, like so:

Get-Process | Format-Table Id, Name  Id Name  -- ----2876 alg 532 ApntEx2044 Apoint3448 calc1824 CFSvcs2176 cmd3760 cmd1640 Crypserv1316 csrss

This will display the Id and Name columns in the table, regardless of the default settings.

PowerShell has four different Format commands:

  • Format-Custom
  • Format-List
  • Format-Table
  • Format-Wide

You can explore each of these withGet-Help.

8. Remember everything is a hierarchy

PowerShell Drives exist for more than just the file system. You can access the registry, the environment, and other data as a drive.

The idea of a computer being arranged hierarchically has been around a long time. Unix has always treated all the hardware as being part of the hierarchical filesystem, for example. Similarly, PowerShell treats various aspects of the computer as drives. You can see what all drives are currently available with theGet-PSDrivecommand:

PS C:\Documents and Settings\Jeff> Get-PSDriveName       Provider      Root                       CurrentLocation----       --------      ----                       ---------------Alias      AliasC          FileSystem    C:\                        Documents and Settings\Jeffcert       Certificate   \D          FileSystem    D:\Env        EnvironmentFunction   FunctionHKCU       Registry      HKEY_CURRENT_USERHKLM       Registry      HKEY_LOCAL_MACHINEVariable   Variable

The list of aliases, for example, is a drive. You can switch to that drive as you would any other drive like so:

PS C:\WINDOWS\system32> cd alias:PS Alias:\>PS Alias:\> dirCommandType     Name                  Definition-----------     ----                  ----------Alias           ac                    Add-ContentAlias           asnp                  Add-PSSnapinAlias           clc                   Clear-ContentAlias           cli                   Clear-ItemAlias           clp                   Clear-ItemPropertyAlias           clv                   Clear-Variable

Thealias: drivedoesn't provide subdirectories. Others, however, such as theRegistry, do:

PS Alias:\> cd HKCU:PS HKCU:\> dir   Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USERSKC  VC Name                           Property---  -- ----                           --------  2   0 AppEvents                      {}  1   0 CLSID                          {}  4  32 Console                        {ColorTable00, ColorTable01, ColorTab... 24   1 Control Panel                  {Opened}  0   8 Environment                    {BAKEFILE_PATHS, INCLUDE, LIB, PROMPT...  0   1 HBA                            {Version}  1   5 Identities                     {Identity Ordinal, Migrated5, Last Us...  3   0 Keyboard Layout                {}  0   0 Movie Magic Screenwriter       {} 19   0 Movie Magic Screenwriter Vo... {}  0   0 Network                        {}  1   1 Note-It                        {(default)}  4   1 Printers                       {DeviceOld}  1   1 RemoteAccess                   {InternetProfile}  1   7 S                              {AutodiscoveryFlags, DetectedInterfac...100   1 Software                       {(default)}  0   0 UNICODE Program Groups         {}  2   0 Windows 3.1 Migration Status   {}  1   0 Win_32                         {}  0   1 SessionInformation             {ProgramCount}  0   7 Volatile Environment           {LOGONSERVER, CLIENTNAME, SESSIONNAME...PS HKCU:\> cd Software\MicrosoftPS HKCU:\Software\Microsoft> dir   Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\MicrosoftSKC  VC Name                           Property---  -- ----                           --------  1   0 Active Setup                   {}  3   0 ActiveMovie                    {}  2   0 Advanced INF Setup             {}  1   0 ASF Stream Descriptor File     {}  1   0 Automap                        {}  1   4 Broadband Networking           {StatusTimeout, InternetStatusTimeout...  1   1 ClipArt Gallery                {UserAdded}  0   5 Clipbook                       {WindowsClipBook Viewer, WindowsClipb...  0   2 Clock                          {iFormat, {CCF5A555-D92E-457b-9235-2B...

Just as you could in DOS, you can use filename patterns:

PS HKCU:\Software\Microsoft> dir *windows*   Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\MicrosoftSKC  VC Name                           Property---  -- ----                           --------  3   0 Windows                        {}  0   1 Windows Genuine Advantage      {code}  0   5 Windows Help                   {Maximized, Xl, Xr, Yd...}  1   0 Windows Media                  {}  1   0 Windows NT                     {}  1   0 Windows Script                 {}  1   0 Windows Script Host            {}

The?character will match a single character. For example,abc?will match all items starting withabcfollowed by a single character. You can also use brackets to specify a set of characters to match. For example,abc[123]will matchabc1,abc2, andabc3.

9. Use flow controls and scripts

The PowerShell language is powerful and supports scripting.

Many commands take scripts as parameters. TheWhere-Objectcommand is one example. I showed you this code earlier:

Get-Process | Where-Object {$_.VirtualMemorySize -gt 104857600}

TheFor-Eachobject can execute a script for each item in a list. Here's a simple example:

PS C:\WINDOWS\system32> 1..10 | foreach { $_ * 2 }2468101214161820

This isn't particularly useful by itself. But the technique is applicable in many places. For example, suppose you want to copy every text file in a directory that has the string#backupin the first line to the c:\backups directory. Here's how you could do it:

dir *.txt | foreach { if ((Get-Content $_ -totalCount 1) -eq "#backup") { copy $_ c:\backups } }

This line starts withdir(orGet-ChildItem) and pipes the results through the foreach command. Theforeachcommand runs the script shown in curly braces for each file encountered. The script reads the first line of each file (viaGet-Content, passing-totalCount 1to get only the first line), and compares it to the string#backup. If the string matches, the script copies the file.

10. Customize your environment

You can customize your environment by saving functions and changes in theprofile.ps1files.

When you develop your own scripts to do the work you need, you'll probably want to save them for later. You might also want to create more aliases of the commands you find userful. For example, in the previous section I created a script that will back up text files that start with#backup.

You can put your customizations in your own profile. The previous script would need to be a function such as this:

function Backup-TextFiles {    dir *.txt | foreach {        if ((Get-Content $_ -totalCount 1) -eq "#backup") {             copy $_ c:\backups }         }    }

This function would then go in your profile. The profile is a file calledProfile.ps1, and it goes in your home directory, which is\Documents and Settings\<username>\My Documents\WindowsPowerShell\profile.ps1where<username>is replaced by your actual username.

However, before you can run the script, it must be signed for security. (Alternatively, you can turn off the security restrictions. Several blogs are saying to do this, but that's a really bad idea.) This is agreat linkthat explains how you can sign your script. (In the article, the author mentions adding a snap-in to MMC. To get there inmmc.exe, click File->Add/Remove Snap-in. Make sure when you run themakecert.exeutility, you're in the directory that the author mentions containsmakecert.exe. Also, I had to refresh the MMC window before my changes appeared.)

Conclusion

The new Windows PowerShell is big, but don't be overwhelmed by it. When I first started using it, I couldn't imagine how it could make my life easier. There were too many unfamiliar commands and the commands seemed very long to type. But in a short time, I started to learn the commands and aliases, and understand the whole way of thinking in the PowerShell world. I'm glad Microsoft has finally given us this tool and excited to see what new tools the community will build around PowerShell to help make our lives easier. Enjoy!

Jeff Cogswelllives near Cincinnati and has been working as a software engineer for over 15 years.


Return to theWindows DevCenter.

Copyright © 2006 O'Reilly Media, Inc.

//-->