The Top Ten PowerShell Best Practices for IT Pros

The Top Ten PowerShell Best Practices for IT Pros

  • Comments 5
  • Likes

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 scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • The Get-EventLog with -InstanceId will not necessarily match the EventID.  According to Technet (msdn.microsoft.com/.../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)

  • 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.

  • 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
    http://www.PowerShell-Group.eu

  • 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.