The Top Ten PowerShell Best Practices for IT Pros

Summary: Microsoft Scripting Guy, Ed Wilson, summarizes the Windows PowerShell Best Practices Talk from Microsoft TechEd 2012.

Microsoft Scripting Guy, Ed Wilson, is here. Wow, what an exciting week the Scripting Wife and I had last week. We began with Microsoft TechEd 2012 in Orlando, and we concluded the week with the IT Pro Camp in Jacksonville, Florida. During that 7-day period, we talked to literally thousands of people who are actively using Windows PowerShell, or are in the process of learning Windows PowerShell. I presented two talks at TechEd about Windows PowerShell Best Practices; one with Microsoft Windows PowerShell MVP, Don Jones, and one with Microsoft Windows PowerShell MVP, Jeffery Hicks. I thought that today, I would provide a summary of those two talks.

1. Read all of the Help. Windows PowerShell has very sophisticated Help for cmdlets and for concepts. By default, the Get-Help cmdlet does not return all of the available information. Although this works well for many situations, you must use the –full switched parameter to see information about which parameters accept pipelined input or wild cards, or to find information about default parameters. The following command illustrates this technique

Get-Help Get-Process –full | more

2. In a script, always use full parameter names. Whether at the Windows PowerShell console or in the Windows PowerShell ISE, you only need to use enough of the parameter to disambiguate it from other available parameters. It is a best practice to use the complete parameter name. This will proof your script in the future from possible new conflicting parameters that are introduced in new versions of Windows PowerShell.

3. In a script, never rely on positional parameters. Windows PowerShell cmdlets often define position numbers for parameters. An example of this is Copy-Item, which uses -path in position 1, and –destination in position 2. This makes the cmdlets very difficult to read—and worse, it makes it difficult to understand what the cmdlet actually accomplishes. For example, with Copy-Item, both parameters use a path string, and therefore the syntax is something that must be memorized.

4. Do not use Write-Host. One of the great features of Windows PowerShell is that it is object oriented. This means that cmdlets return objects, such as Get-Process, which returns an instance of the System.Diagnostics.Process object. The great thing about objects is that they have lots of methods and properties. In Windows PowerShell, these objects flow along the pipeline. Using Write-Host interrupts the pipeline, and destroys the object. There are times to use Write-Host, such as producing status messages in different colors, but do not use Write-Host to simply write textual output. Instead, directly display the contents of variables, and write your strings directly.

5. Save Format* cmdlets until the end of the command line. Similar to the previous best practice, the Format* cmdlets (such as Format-Table, Format-List, and Format-Wide) change the object (from, for example, a System.Diagnostic.Process object) to a series of Format* objects. At this point, you are done. You can do nothing else with your pipeline.

6. Do not use Return. Functions automatically return output to the calling process. In fact, it is best if you configure your functions so that they return objects. In this way, you enable the user to utilize your functions just like Windows PowerShell cmdlets.

7. Filter on the left. It is more efficient to filter returning data as close to the source of data as possible. For example, you do not want to return the entire contents of the system event log across the network to your work station, and then filter events for a specific event ID. Instead, you want to filter the system event log on the server, and then return the data.

The following command filters the system event log on a computer named RemoteServer for events with the event id of 1000. This illustrates filtering to the left.

Get-EventLog -LogName system -InstanceId 1000 –computername RemoteServer | sort timewritten

The following command illustrates filtering on the right by using the Where-Object. This command returns all of the events from the system event log across the wire, and then it filters. This is much less efficient.

Get-EventLog -LogName system –computername remoteserver | where { $_.instanceID -eq 1000 } | sort timewritten

8. Pipe to the right. When writing code in the Windows PowerShell ISE, you want to format the code so that it is easy to read. This means avoiding really really long lines of code. The best way to break up your lines of code into readable chunks is to break on the right-hand side. The following code illustrates this.

Get-EventLog -LogName system -InstanceId 1000 –computername RemoteServer |

Sort-Object timewritten

9. Use –whatif. The –whatif switch is a great way to see what a command will accomplish prior to actually executing the command. You should always use this switch when a command will change the system state. For example, the following command informs me that it will stop every process on my system.

Get-Process | stop-process -whatif

10. Steal from the best, write the rest. Many scripts have already been written for Windows PowerShell. The Scripting Guys Script Repository has thousands of scripts for many different topics. There is absolutely no reason to rewrite a perfectly good script that is already written. In addition, you might find a script that does nearly what you want, and all you need to do is make a few minor changes.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Comments (10)

  1. jrv says:

    Behavior of output from functions in PowerShell:

    function foo{
    PS C:scripts> 1|foo
    PS C:scripts> 1|foo
    PS C:scripts> 1,2,3,4|foo
    PS C:scripts>

  2. Point 6. Do not use Return
    This is a point to discuss.
    If you use Return without an Object as an Argument, I agree!
    Return is a valid word, to to control when to leave a Function, so you can prevent excecution of unaccesary following code.
    But you have to provide an Object as Returning Argument with Return. Then it is rock valid!
    Returning an Object with return is best practice! Not to demonize the Keyword Return 😉

    Greets Peter Kriegel
    Founding member of the European, german speaking, Windows PowerShell Community

  3. jrv says:

    @Kitt – nothing at all like references. In PowerShell [ref] is a reference object type. A PowerShell function is nothing like a ‘C’ function. It is capable of sending back anything we want as often as we want. It sits in the "pipeline" which is it greatest
    power. By default a function takes input from the pipeline and send output to the pipeline. The console is just the end of the pipeline.

    PS C:scripts> function foo{Process{2*$_}}
    PS C:scripts> 1|foo|foo
    PS C:scripts> 1|foo|foo|foo
    PS C:scripts> 1|foo|foo|foo|foo
    PS C:scripts>

  4. The Get-EventLog with -InstanceId will not necessarily match the EventID.  According to Technet (…/system.diagnostics.eventlogentry.instanceid.aspx):

    "The InstanceId property uniquely identifies an event entry for a configured event source. The InstanceId for an event log entry represents the full 32-bit resource identifier for the event in the message resource file for the event source. The EventID property equals the InstanceId with the top two bits masked off. Two event log entries from the same source can have matching EventID values, but have different InstanceId values due to differences in the top two bits of the resource identifier."

    So this cannot be relied upon to actually find matches for EventID.

    In testing that I've done – there are really two main ways to collect EventLog data from remote servers (filtering by EventId).

    1) gwmi -Query "Select * from win32_NtlogEvent where Logfile = 'application' and EventCode = EventId" -computername computer

    2) Get-EventLog -ComputerName computer -LogName application | ? {$_.EventId -eq EventId }

    I ran each one of these against a remote service with "Measure-Command" to see what the times looked like. Here are the results:

    1) Average of 62.93 seconds (over 5 samples)

    2) Average of 107.41 seconds (over 5 samples)

  5. jrv says:

    Behavior of functions with return statements.

    function foo{
    return 2*$_
    return 4*$_
    return 10*$_
    PS C:scripts> foo
    PS C:scripts> 1|foo
    PS C:scripts> 1,2,3,4|foo
    PS C:scripts>

    We normally would like to design functions to have a more deterministic outcome. The old C++ rule that the return should be at the end of the function is very helpful in preventing errors and spaghetti code. The same holds for PowerShell but in a slightly different

    In the end it is a design consideration but "return" should be used very carefully in PowerShell.

  6. jrv says:


    The same function in PowerShell with no return statement. PowerShell does not work like other languages. C languges require the use of a return statement.

    #// It is good form to return the value at the end of the function.
    function max([int] $a, [int] $b) {
    if($a -gt $b){
    $maxval = $a;
    } else {
    $maxval = $b;
    } #//end max

    PowerShell functions can return many objects throughout their lifetime. This makes them very flexible. "return" is NEVER required for returning values or objects.

  7. jj says:

    True, there are some circumstances that it’s faster to run one command and then pipe it to another. It’s better to use .net to get folder sizes and wmi to do certain tasks among many computers. write-host is in powershell for legacy reasons only, and shouldn’t
    exist except for debugging and verbose reasons. Again, there is no reason to try to pipe out to the prompt vs pass the object to a file type and move it somewhere.

  8. JV says:

    Absolutely do not use "return". It is a bad design crutch in nearly all cases. Learn to design so that a function returns the result of its design purpose or nothing. It is unfortunate tat functions are not strongly typed but then this is scripting.

    So for those that do not see the sense in not using return as a BP I suggest browsing the history of debate over good programming practices.

  9. Kitt says:

    Having a lot of experience with C++ and PHP programming, its a bit odd hearing the comments to not use return. In my experience there are valid instances of wanting to return an object. In C++ its considered more efficient to pass by reference or use a
    data pointer, but its seldom said to never use a capability the language offers. Most of my Computer Science instructors have mentioned camps of people that will tell you to never do one thing or the other. They mention these are typically holy wars with people
    on both sides, and their input is typically, 1.) do what your employer expects, and 2.) write efficient code that is easy to read and maintain, if the involves a return statement instead of a pointer, then so be it. It sounds like Power Shell automatically
    handles returns to some degree, I can imagine return being used to highlight a variable of importance. A lot of languages use return, I imagine their must be a reason for this. In my experience, blanket statements are typically incorrect.

    Here is a version of the max function that uses only one return statement by saving the result in a local variable. Some authors insist on only one return statement at the end of a function. Readable code is much more important than following such a fixed rule.
    The use of a single return probably improves the clarity of the max function slightly.
    // Single return at end often improves readability.
    int max(int a, int b) {
    int maxval;
    if (a > b) {
    maxval = a;
    } else {
    maxval = b;
    return maxval;
    }//end max

  10. Kitt says:

    Not using a return feels a lot like passing reference values through void functions in C++, no return but still changes the variable. This is typically recommended over returning a value because it does not create a copy, I seldom return values in C++. Occasionally
    I might though. I realize this might be akin to apples to oranges, a lot of times a function can be made into a reference or pointer function. So I would hard pressed to give an example of a function that has to have a return as well in c++. I’m told that
    there are many ways to accomplish the same thing, ideally you will aim for the most efficient & maintainable method, whatever that may contain. That is what I have been taught, I might have a more broad ideology in that my computer science classes have gone
    over multiple languages.

    void AddOne(int &y) <- "&" indicates passing the variables memory address, directly affecting the variable . . instead of making a copy and returning the copy

    int main()
    int x = 5;

    cout << "x = " << x << endl; x=5
    AddOne(x); <—— No Return
    cout << "x = " << x << endl; x=6

    return 0;

Skip to main content