Interacting with Data Collector Sets via Powershell

Background:

In an earlier post I talked about some new features for Windows 2008 and Vista.  One of those new features that is often overlooked are the data collector sets (DCS).  One particular role that leverages data collector sets is active directory.  Active directory has put “hooks” into tracing that can really take a lot of the thinking out of the question “why is my domain controller sluggish”.  For those of you still running Windows 2003 I go over a similar concept called Server Performance Advisor

Anyways, you can play around with DCS by typing perfmon and then traversing to the section called Data Collector Sets (shocking).  If you have performance issues, go here first as it’s like combining a netmon capture with a kernel trace and then handing you the smoking gun. 

 

Challenge:

In my current role, we have a need to automate things quite a bit and so one of the actions I was looking at solving was collecting diagnostic information when a server is performing poorly.  Usually when a high CPU alert comes in, someone would need to logon to the server and go to perfmon and start at DCS collection.  More often is the case that by the time someone had been alerted and went to the server the sluggish behavior had subsided (the dreaded “close ticket, no problem found”).

My solution was to try and figure out a way to start a DCS collection remotely at the time of event so that the data was present when an actual human became engaged.

After some hard work, here is the code to do so!  You can create your own XML file (your own DCS template) and pass it in, but more than likely you’ll be happy at just kicking off one of the built-in templates (AD/System Perf/System Diags).

Running it via powershell:

First, how to do it on the fly:

 ## PLA.dll lives under system32 on Vista and 2k8.  This will create a powershell com object.
$datacollectorset = new-object -COM Pla.DataCollectorSet
##This is the name of the predefined DCS collector.  It's read-only and will always be System\<something>
$name = "System\Active Directory Diagnostics"
##If you make the second param $null it will be the local machine.
$datacollectorset.Query($name,"serverA") 
$datacollectorset.start($false)
## Status ReturnCodes: 0=stopped 1=running 2=compiling 3=queued (legacy OS) 4=unknown (usually autologger)
$datacollectorset.status
##When you're ready to stop it call stop.
$datacollectorset.stop($false)
##If you call status here, it will probably be '2' for a while as the server compiles the report.
$datacollectorset.status

And like so, you started and stopped a collection for Active Directory on you’re local computer or a remote server!  Like I said though, you can create you’re own templates too.  You might want to do this if you want to setup a built-in template to be scheduled to run daily, or perhaps you want to send the data to a network location, run more tasks at completion, etc.  If you do want to create a custom template then the code changes a bit:

 $datacollectorset = new-object -COM Pla.DataCollectorSet
## If you're making you're own (shows up under user defined).  
$xml = get-content C:\custom.xml #You're custom exported XML file.
$datacollectorset.SetXml($xml)
##Commit codes: https://msdn.microsoft.com/en-us/library/aa371873(VS.85).aspx this is add or modify.  Can't do this on a system created PLA instances (read only).
$datacollectorset.Commit($DCSPath , $null , 0x0003)     
$datacollectorset.Query($DCSPath,$null)
$datacollectorset.start($false)
#Runs...
$datacollectorset.stop($false)

Scripting a solution:

Finally if you wanted to script this you could do something like what I’ve done below.  This would collect for a desired interval (in seconds) and then when compilation completed display the path to the report.  I wrote this in CTP3, but you can easily take the concepts and backport them.  If the destination server is inaccessible, or you don't have permissions, then the script will blow up…

 <#
    .SYNOPSIS
    This will fire up a PLA (Data Collector Set collection on a server and then copy it to the proper debug server
 
    .DESCRIPTION
    This is a proof of concept and only acceppts System defined collections.  No error handling so I hope you type well.

#>

##Inputs
[CmdletBinding()]
param(
   [Parameter(Mandatory = $true)]
   <#A system provided report to run like "System\System Performance", System\System Diagnostics, etc. #>
   [string]$DCSPath,
   [Parameter(Mandatory = $true)]
   <# This is how long you want the DCS collection to run in seconds#>
   [int32]$time,
   [Parameter(Mandatory = $false)]
   <#If you don't pass in a server name it will be $null and run on the local system#>
   [string]$serverName
    )

    $datacollectorset = new-object -COM Pla.DataCollectorSet  
    $datacollectorset.Query($DCSPath,$serverName)
    $datacollectorset.start($false)
    Start-Sleep $time
    $datacollectorset.stop($false)
    
    ##Now we'll loop while the report compiles.
    $retries = 0
    do 
        {sleep 30; $returnCode = $datacollectorset.Status ; $retries++} 
    while ($returnCode -eq 2 -and $retries -lt 60)
    
    if ($retries -eq 60)
    {
        Write-Warning "Compiling has been running on the server for 30 minutes!  You'll need to check the following location on the server later for the report:"
        Write-Warning $datacollectorset.OutputLocation
        break
    }
    
    ##Compiling has finished, now we can copy the folder to some location
    $path = $datacollectorset.OutputLocation
    if ($serverName)
    {
    $path = $path.Replace(":","$")
    Write-Host "`nReport complete and can be viewed at \\$serverName\$path\report.html on the server.`n" 
    }
    else
    {
    Write-Host "`nReport complete and can be viewed at $path\report.html`n"
    }
    
   

The result:

More info:

PLA reference: https://msdn.microsoft.com/en-us/library/aa372634(VS.85).aspx

 

Technorati Tags: Powershell,Windows 2008,Active Directory,Windows