Get-BLGPerfmonSummarizedCounterStats.ps1

<#PSScriptInfo
 
.VERSION 1.1
 
.GUID f3261388-a3f9-4589-87fe-5384b5e9be6a
 
.AUTHOR Sam Canada Drey
 
.COMPANYNAME Microsoft Canada
 
.COPYRIGHT None
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
#>


<#
.SYNOPSIS
      This script spits out a CSV file with the Min, Avg, Max of desired counters inside a BLG file.
      Using -ArrayFilter "substring1","Substring2","substring3" enables to get counters even when we
      don't remember the exact names of counters.
 
.DESCRIPTION
      This script analyses the counters we find with substrings (example: you are looking for Available Memory stats like Min, Avg, Max on a BLG,
      but don't know the exact counter name, you'll use the -ArrayFilter parameter with an array of substrings like "Memory", "Available" to find
      all counters within the BLG you specify that have these words in their path. On this example, it's "\\ServerName\Memory\Available MBytes" counter.
 
 
.EXAMPLE
      .\Get-BLGPerfmonSummarizedCounterStats.ps1 -BLGFolder "C:\temp\" -ArrayFilter "I/O Database Reads (Attached) Average Latency", "DB"
      Here we didn't specify the -BLGFileName, that Will analyze the oldest BLG file found on C:\temp\, and dump the Min, Avg, Max values for all the "I/O Database Reads (Attached)
      Average Latency" counters for all the databases with "DB" in their full counter path names.
 
.EXAMPLE
      .\Get-BLGPerfmonSummarizedCounterStats.ps1 -BLGFolder "c:\temp" -CountersFile .\counterslist.txt
      Here we specified again the C:\temp folder to find the BLG oldest BLG file (as we didn't specify the -BLGFileName parameter), and we want to get
      the summary of the counters stored in the counterslist.txt file located on the local directory where we execute the script from.
 
.INPUTS
      A BLG file containing Windows performance counters data
 
.OUTPUTS
      A CSV file with counters path and their Min, Avg, Max values
 
.NOTES
      Common counter substrings to search for:
        -ArrayFilter "I/O Database Reads (Attached) Average Latency"
        -ArrayFilter "Memory", "Available MBytes"
        -ArrayFilter "% processor time", "Total"
        -ArrayFilter "domain controllers", "ldap", "time"
 
        v1.01 : added script info for PSGallery publishing
 
.LINK
      https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/import-counter?view=powershell-5.1
      https://github.com/SammyKrosoft/Collect-Performance-Counter-Statistics-From-BLG
#>


[CmdletBinding(DefaultParameterSetName="ParamArrayFilter")]
Param([Parameter()][string]$BLGFileName,
      [Parameter(ParameterSetName="ParamArrayFilter")][string[]]$ArrayFilter,
      [Parameter(ParameterSetName="ParamFile")][string]$CountersFile, #Note: Haven't tested the -CountersFile feature yet
      [Parameter()][string]$BLGFolder = "$($env:exchangeinstallpath)Logging\Diagnostics\DailyPerformanceLogs\"
      )

#Setting up global variables that we'll reuse
#Output file to local user launching the script's "My Documents" folder
$OutputFile = "$($env:USERPROFILE)\Documents\CountersSummary_$(Get-Date -Format yyyMMdd_hhmmss).csv"

# Defining and starting stopwatch to measure script execution time
Write-host "Starting..." -ForegroundColor Green
$StopWatch = [System.Diagnostics.Stopwatch]::StartNew()

#region BLG folder check
If (!(Test-Path $BLGFolder)){
      Write-Host "Folder $BLGFolder doesn't exist ... please run the script from an Exchange server which DailyPerformanceLogs folder is located in the Exchange Install path\Logging\Diagnostics folder, or specify an existing folder with .BLG files on it" -ForegroundColor Red
      $StopWatch.Stop();
      $StopWatch.Elapsed.totalseconds | Out-Host
      Exit
}
#endregion BLG folder check

#region Set BLG File Name if blank, and display parameters
If ([String]::IsNullOrEmpty($BLGFileName)){
      $BLGFileName = (Get-ChildItem -Path "$BLGFolder\*.blg" | Sort-Object LastWriteTime | Select -First 1).Name
      }
      Write-Host "Current Parameters" -ForegroundColor Yellow -BackgroundColor Blue
      Write-host "BLG File : $BLGFileName" -ForegroundColor Yellow
      Write-Host "BLG folder path : $BLGFolder" -ForegroundColor Yellow
      Write-Host "User Parameter Set: $($PSCmdlet.ParameterSetName)" -ForegroundColor Magenta

#region BLG file check
#Verifying if BLG file(s) exist - doesn't apply if no BLG specified, as took the oldest one
$BLGDiagnosticsFilesPath = "$BLGFolder\$BLGFileName"
If (!(Test-Path $BLGDiagnosticsFilesPath)){
      Write-Host "File(s) $BLGDiagnosticsFilesPath not found. Please specify valid BLG file" -ForegroundColor Red;
      $StopWatch.Stop();
      $StopWatch.Elapsed.totalseconds | Out-Host
      exit;
}
#endregion BLG file check

If ($CountersFile){
      #Validate the file exists
      if (!(Test-Path($CountersFile))){
            Write-Host "The file $CountersFile doesn't exist ! Specify a valid file or use -CounterFilterX to search for counters..." -ForegroundColor Red -BackgroundColor Blue
            $StopWatch.Stop();
            $StopWatch.Elapsed.totalseconds | Out-Host
            Exit
      } Else {
            Write-Host "File $CountersFile found, loading counters from file..." -ForegroundColor Green
            $CountersListFromFile = Get-Content $CountersFile
      }
} Else {
      If ([string]::IsNullOrEmpty($ArrayFilter)){
            $ArrayFilter = "*"
            Write-Host "No CountersFile and no ArrayFilter specified... using ArrayFilter = $ArrayFilter"
      } Else {
            $NbFilterStrings = $ArrayFilter.Count
            for ($i=0;$i -lt $NbFilterStrings;$i++) {
                  Write-Host "Processing Index of ArrayFilter #$i - From $($ArrayFilter[$i]) to *$($ArrayFilter[$i])*" -ForegroundColor Green
                  $ArrayFilter[$i]="*" + $ArrayFilter[$i] + "*"
            }
      }
}

#Loading all counters present in the target BLG:
Write-Host "Loading counters list from BLG file, please wait..." -ForegroundColor DarkRed
#$CounterList = @(Import-Counter -path "$BLGDiagnosticsFilesPath" -ListSet * | Foreach-Object {If ($_.CounterSetType -eq "SingleInstance"){$_.Paths} Else {$_.PathsWithInstances}})
$CounterList = @(Import-Counter -path "$BLGDiagnosticsFilesPath" -ListSet * | Foreach-Object {If ($_.CounterSetType -eq "SingleInstance"){$_ | Select -ExpandProperty Paths} Else {$_ | Select -ExpandProperty PathsWithInstances}})

$Tick = $StopWatch.Elapsed.totalseconds
Write-host "Took $Tick seconds to load all counters from $BLGFileName"
Write-Host "Found $($CounterList.count) counter(s) !" -ForegroundColor DarkRed -BackgroundColor DarkBlue
Write-Host "Counters path loaded ! Filtering these as per ArrayFilter or Counters from file..." -ForegroundColor DarkRed

$CounterListFiltered = $CounterList

If ($CountersFile){
      $CounterListFiltered = $CountersListFromFile
}ElseIf (!($ArrayFilter -eq "*")){
      Foreach ($Item in $ArrayFilter){
            Write-Host "Filtering with $Item" -ForegroundColor Yellow
            $CounterListFiltered = $CounterListFiltered | ? {$_ -like $Item}
      }
}Else{
      Write-Host "-ArrayFilter is unspecified, using ArrayFilter = $ArrayFilter"
      $CounterListFiltered = $CounterList
}

$NumberOfCountersFromBLG = $CounterListFiltered.count

If ($NumberOfCountersFromBLG -eq 0){
      Write-Host "No counters found with the chosen filter or counter files"
}

Write-Host "List of counters filtered:"
Foreach ($item in $CounterListFiltered){
      write-host $Item -ForegroundColor Green
}

#import counters this time not only the paths, but all the values as well, for filtered counters
$Data = Import-Counter -Path "$BLGDiagnosticsFilesPath" -Counter $CounterListFiltered -ErrorAction SilentlyContinue

$AllResults = @()
$Data | Select -ExpandProperty CounterSamples | Group-Object Path | Foreach {   $Stats = $_ | Select -ExpandProperty Group | Measure-Object -Average -Minimum -Maximum CookedValue
                                                                                $AllResults += [PSCustomObject]@{
                                                                                Counter=$_.Name
                                                                                Instance = $_.Group.InstanceName[0]
                                                                                Minimum=$Stats.Minimum
                                                                                Average=$Stats.Average
                                                                                Maximum=$Stats.Maximum
                                                                                Samples=$Stats.Count
                                                                                                                  }                                                                                        
                                                                            }
$StopWatch.Stop()
$FinalTime = $StopWatch.Elapsed.totalseconds

Write-Host "Took $FinalTime seconds in total to run the script"

$AllResults | Select Counter, Samples, Instance, Minimum, Average, Maximum | Export-CSV -NoTypeInformation -Path $OutputFile
notepad $OutputFile