Managing Perfmon Data Collector Sets with PowerShell

Whilst working with Microsoft Support on a performance case we needed to supply them with some Perfmon logs. To do so required creating a User Defined Data Collector Set containing a number of counters. You can obviously do this through the GUI, which is fine for one server, but we needed the logs from around 200 servers.

So we created a Data Collector Set on one server and then saved it out to a template which stores the data in an XML file. I then put together a script which read in the XML file and then used that data to create a Data Collector Set via the COM object Pla.DataCollectorSet. (There are currently no built-in Powershell cmdlets for doing this)

Since all of these servers were enabled for PowerShell remoting it was then very easy to execute that script on all 200 servers using Invoke-Command. I had issues reading in the XML file from a network location in my environment, so it first of all copies the file locally and removes it at the end. Note: it is important that you name the Data Collector Set the same as you did in the template, this allows for easier removal later on.

The resultant script is below. Most of the code around it is some basic error checking and using some of PowerShell 2.0’s built-in help and advanced function features. The key part that creates the Data Collector Set is here:


$datacollectorset = New-Object -COM Pla.DataCollectorSet $xml = Get-Content C:\\temp\\PerfmonTemplate.xml $datacollectorset.SetXml($xml) $datacollectorset.Commit("$DataCollectorName" , $null , 0x0003) | Out-Null $datacollectorset.start($false)

And the full script…….


\# Test for existence of supplied CSV and XML files if (Test-Path $CSVFilePath){ } else{ Write-Host "Path to CSV file is invalid, exiting script" Exit } if (Test-Path $XMLFilePath){ } else{ Write-Host "Path to XML file is invalid, exiting script" Exit }

\# Generate list of servers to create Perfmon Data Collector Sets on $servers = Get-Content $CSVFilePath

foreach ($server in $servers){

Write-Host "Creating Data Collector Set on $Server"

\# Test if the folder C:\\temp exists on the target server if (Test-Path "\\\\$server\\c$\\Temp"){

\# Copy the XML file to the target server Copy-Item $XMLFilePath "\\\\$server\\c$\\Temp"

\# Use PowerShell Remoting to execute script block on target server Invoke-Command -ComputerName $server -ArgumentList $DataCollectorName -ScriptBlock {param($DataCollectorName)

\# Create a new DataCollectorSet COM object, read in the XML file, # use that to set the XML setting, create the DataCollectorSet, # start it. $datacollectorset = New-Object -COM Pla.DataCollectorSet $xml = Get-Content C:\\temp\\PerfmonTemplate.xml $datacollectorset.SetXml($xml) $datacollectorset.Commit("$DataCollectorName" , $null , 0x0003) | Out-Null $datacollectorset.start($false) }

\# Remove the XML file from the target server Remove-Item "\\\\$server\\c$\\Temp\\PerfmonTemplate.xml" } else{ Write-Host "Target Server does not contain the folder C:\\Temp" } }

We calculated that this script would save 29 hours manual effort…….and that was just the first time we needed to do it. Later on we had to change some of the counters, so needed to first remove all of the Data Collector Sets and replace them with modified versions from a new XML file.

The following script removes an existing Data Collector Set and renames the folder it was storing logs in - this is because if you subsequently create a new one it will fail if you are using the same paths.


<# .SYNOPSIS Remove a Specified Data Collector .DESCRIPTION Remove a Specified Data Collector .NOTES Authors:  Jonathan Medd .PARAMETER CSVFilePath Path of CSV file to import .PARAMETER DataCollectorName Name of existing Data Collector .EXAMPLE Remove-DataCollectorSet -CSVFilePath C:\\Scripts\\Servers.csv -DataCollectorName CPUIssue #> param ( \[parameter(Mandatory=$True,HelpMessage='Path of CSV file to import')\] $CSVFilePath , \[parameter(Mandatory=$True,HelpMessage='Name of existing Data Collector')\] $DataCollectorName )

\# Test for existence of supplied CSV file if (Test-Path $CSVFilePath){ } else{ Write-Host "Path to CSV file is invalid, exiting script" Exit }

\# Generate list of servers to remove Perfmon Data Collector Sets from $servers = Get-Content $CSVFilePath

\# Create a string with the current date to append to the Perfmon folder name $today = Get-Date $RenameText = \[string\]$today.Day + \[string\]$today.Month + \[string\]$today.Year $NewnameText = $DataCollectorName + '\_' + $RenameText

foreach ($server in $servers){

Write-Host "Removing Collector Set for $Server"

\# Use PowerShell Remoting to execute script block on target server Invoke-Command -ComputerName $server -ArgumentList $DataCollectorName,$NewnameText,$Server -ScriptBlock {param($DataCollectorName, $NewnameText, $Server)

if (Test-Path C:\\PerformanceLogs\\$DataCollectorName) {

$datacollectorset = New-Object -COM Pla.DataCollectorSet $datacollectorset.Query("$DataCollectorName",$null) $datacollectorset.stop($false)

Start-Sleep 10

$datacollectorset.Delete()

Rename-Item -Path C:\\PerformanceLogs\\$DataCollectorName -NewName C:\\PerformanceLogs\\$NewnameText } else {

Write-Host "Collector Set for $Server Does Not Exist"

} }

}