Evaluate Weigh the pros and cons of technologies, products and projects you are considering.

Extending your toolset with Windows PowerShell

Sometimes the operating system has the information you want, but it doesn't group it in a way that answers your questions. Here you'll learn one example of how to use Windows PowerShell to read performance data and gather intelligence about the server.

I recently worked on a new book, the Windows Server 2008 Terminal Services Resource Kit from Microsoft Press with my co-author Kristin Griffin. We developed some Windows PowerShell scripts for the book that allow you to create features that don't currently exist in Terminal Services but would be useful to have. In this column, I'll show you how we created one of these scripts and what we had to do to get to the performance data that this tool requires.

There are a few steps involved in creating your own tools for performance data:

  1. Identify the question you want to answer.
  2. Find the counters that can help you answer that question.
  3. Write the script to help you collect those counters and store the results for analysis.

This article will help you with the third item. You'll still need to review the Performance Monitor tool in the Windows Reliability and Performance Monitor to help you find the right objects and counters.

Finding performance counters

In this example, we will set the script to get the MemoryCommitted Bytes from terminal server HELEN. The System.Diagnostics namespace provides classes that allow you to interact with system processes, event logs and -- most important for this column -- performance counters.

First, list the available performance counter categories and format them so they're easy to read.

PS C:\windowsSystem\32>[System.Diagnostics.PerformanceCounterCategory]::GetCategories() | format-list

Once you know the name of the category, create a new object and assign it to a variable. Place the category name in the parentheses as we do here with the category "memory":

PS C:\windows\System32>$category = new-object System.Diagnostics.PerformanceCounterCategory("memory")

Assign a performance counter object to a variable and look at its counters. Use the NextValue property instead of the RawValue property, as the latter is not yet processed and will sometimes return values that you can't read.

PS C:\windows\System32>$perfcounter = new-object system.diagnostics.PerformanceCounter
PS C:\windows\System32>$perfcounter
CategoryName        :
CounterHelp         :
CounterName         :
CounterType         :
(this is how the data is formatted)
InstanceLifetime    : Global
InstanceName        :
ReadOnly            : True
MachineName         : .
RawValue            :
(This is the raw, unprocessed data retrieved by this counter)
Site                :
Container           :

Next, get the instance names available for the specified category. There may or may not be any instances depending on the counter you have chosen and what you're doing on that server. For example, a terminal server with no active connections will naturally have no instances of active connections.


If the counter has instances, then add the instance name (in quotations) between the parentheses of the following the command. This will yield the counters for that instance. If there are no instances, then run the command with no instance entered, like so :


Find the counter name in the listed results. Now you have all of the pieces necessary to populate the following script to make it collect performance data for a named server.

# This script gets Memory Committed Bytes for a named server # and writes the date and the count to a CSV file.

######Configuration Area#######
$PerfObj = "Memory" # Performance Object Category
$PerfCounter = "Committed Bytes" # Performance Counter
$PerfCounterInst = "" # Performance Instance
$Server = "OZARK" # Server
$LogPath = "\\ozark\it$\Logs\"
$LogFileNAme = "-Memory-Committed-Bytes.csv"

$LogFile = "$LogPath$Server$LogFileName"
$MonthDay = get-date -format "ddMMM"
$Year = get-date -format yyyy
$Time = get-date -format "HH:mm:ss"

$objPerfCounter = New-Object

$objPerfCounterData = "$MonthDay" + "," + "$Year" + "," + "$Time" + "," +$objPerfCounter.NextValue() | out-File "$LogFile" –append

This script will save the contents of this counter to the file whose names is stored as $LogFile.

What's the logon rate?

With Windows Terminal Services, the most common questions usually involve how many people a given server can support and when it's time to add more hardware capacity to the server farm. Before adding capacity, you need to know how much stress the servers are under. One way to do this is to measure connections in two contexts: the rate of new connections added during logon times and the number of connections each terminal server sustains at a time when you'd expect people to already be logged on and working.

Both numbers are important for different reasons. You need to know the rate of logons to help determine one kind of server stress. Process creation is expensive in terms of resources, and the beginning of a session requires a lot of process creation. You need to know the number of concurrent sessions to help you see trends in server usage. Are more or fewer people using each terminal server, or is the rate of usage staying pretty steady?

Both questions -- the rate at which users are logging on in the morning and the number of people using the terminal servers -- can be answered using the script below, which creates a file with entries as shown in the example. This script reads the Active Sessions counter of the terminal server object at a given time and date and then writes that information to a comma-separated value (CSV) file that you can open in programs such as Microsoft Excel.

# This script gets the number of active sessions # for a named server and writes the date and the count to a CSV file.

######Configuration Area########
$PerfObj = "Terminal Services" # Performance Object
$PerfCounter = "Active Sessions" # Performance Counter
$PerfCounterInst = "" # Performance Instance
$Server = "HELEN" # Server
$LogPath = "\\ozark\it$\Logs\"
$LogFileNAme = "-ActiveSessions.csv"
$LogFile = "$LogPath$Server$LogFileName"
$MonthDay = get-date -format "ddMMM"
$Year = get-date -format yyyy
$Time = get-date -format "HH:mm:ss"

$objPerfCounter = New-Object System.Diagnostics.PerformanceCounter($PerfObj,$PerfCounter,$PerfCounterInst,$Server)

$objPerfCounterData = "$MonthDay" + "," + "$Year" + "," + "$Time" + "," +$objPerfCounter.NextValue() | out-File "$LogFile" –append

Every time you run the script, it appends a new line to the file in the location specified in the script. Opening the report in Microsoft Excel will show you data similar to the output here.

     A B C D
1 9-Sep 2008 8:30:00 26
2 9-Sep 2008 9:00:00 43
3 10-Sep 2008 8:30:00 27
4 10-Sep 2008 9:00:00 40

To get the information you want, you will need to run this script at least three times a day. Run it twice (or more often) during the time you would expect most users to log on, separated by a reasonable interval to help you see the rate of logons during that time.

Keep in mind that you may need to play with this interval to get the shape of the curve; the more often you run the script during this period, the more data points you'll get to draw the curve accurately.

Run the script an additional time during a period when you would expect most users to be logged on, such as mid-afternoon on a Tuesday. Obviously, you'll need to experiment with the timing according to the way your organization works, but the basic idea is simple: Identify a time when most people should be at work and do your best to determine the greatest number of concurrent connections you're likely to see.

I recommend creating two versions of the script: one to store logon rates and another to store concurrent connections when the server is working. This will make it easier for you to find the data you need.

Miss a column? Check out the Scripting School archive.

Christa Anderson
A former Terminal Services MVP, Christa Anderson is a program manager on the Terminal Services team at Microsoft and author of the forthcoming Windows Terminal Services Resource Kit from Microsoft Press. She is an internationally known authority on scripting, the author of Windows Terminal Services, The Definitive Guide to MetaFrame XP, and co-author of the book Mastering Windows 2003 Server .

Dig Deeper on Windows Server deployment

Join the conversation

1 comment

Send me notifications when other members comment.

Please create a username to comment.

what is a powershell script for add mapped/shared drives