Public/Get-ServerMetrics.ps1
|
Function Get-ServerMetrics { [CmdletBinding()] param( [Parameter( Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [int]$ThrottleLimit = 10, [Parameter(Mandatory = $false)] [string]$CSVPath ) BEGIN { # Define the exact operational script block to execute per server inside the Runspace $ScriptBlock = { param($Computer) $Session = $null try { $Session = New-CimSession -ComputerName $Computer -ErrorAction Stop -OperationTimeoutSec 15 # 1. Hardware Inventory Properties $CPUInfo = Get-CimInstance -CimSession $Session -ClassName Win32_Processor -ErrorAction Stop $SumCores = ($CPUInfo.NumberOfCores | Measure-Object -Sum).Sum $OSInfo = Get-CimInstance -CimSession $Session -ClassName Win32_OperatingSystem -ErrorAction Stop $MemInfo = Get-CimInstance -CimSession $Session -ClassName Win32_PhysicalMemory -ErrorAction Stop $PhysicalMemory = ($MemInfo | Measure-Object -Property Capacity -Sum).Sum / 1GB $PhysicalMemory = [math]::Round($PhysicalMemory, 2) # 2. Gather Storage & Calculate Metrics $RawDisks = Get-CimInstance -CimSession $Session -ClassName Win32_LogicalDisk -ErrorAction Stop | Where-Object { $_.DriveType -eq 3 } $TotalAllocatedRaw = ($RawDisks | Measure-Object -Property Size -Sum).Sum $TotalFreeRaw = ($RawDisks | Measure-Object -Property FreeSpace -Sum).Sum $TotalUsedRaw = $TotalAllocatedRaw - $TotalFreeRaw $TotalAllocatedGB = [math]::Round(($TotalAllocatedRaw / 1GB), 2) $TotalUsedGB = [math]::Round(($TotalUsedRaw / 1GB), 2) $TotalDiskPercentUsed = if ($TotalAllocatedRaw -gt 0) { [math]::Round(($TotalUsedRaw / $TotalAllocatedRaw * 100), 2) } else { 0 } # 3. Live OS Performance Metrics $CpuSamples = for ($i = 1; $i -le 3; $i++) { Get-CimInstance -CimSession $Session -ClassName Win32_PerfFormattedData_PerfOS_Processor | Where-Object { $_.Name -eq '_Total' } | Select-Object -ExpandProperty PercentProcessorTime if ($i -lt 3) { Start-Sleep -Seconds 1 } } $AvgCpuUsage = [math]::Round(($CpuSamples | Measure-Object -Average).Average, 2) $TotalVisibleMemMB = $OSInfo.TotalVisibleMemorySize / 1KB $FreeMemMB = $OSInfo.FreePhysicalMemory / 1KB $UsedMemMB = $TotalVisibleMemMB - $FreeMemMB $RamUsagePct = [math]::Round(($UsedMemMB / $TotalVisibleMemMB * 100), 2) $TimeStamp = (Get-Date).ToString("yyyy-MM-dd_HHmm") [PSCustomObject]@{ ComputerName = $Computer Status = "Connected" OS_Name = $OSInfo.Caption vCPUs = $SumCores Live_AvgCpu_Pct = "$AvgCpuUsage%" Physical_Memory = "$PhysicalMemory GB" Live_RamUsage_Pct= "$RamUsagePct%" DiskAllocated_GB = $TotalAllocatedGB DiskUsed_GB = $TotalUsedGB DiskPercentUsed = "$TotalDiskPercentUsed%" Time_Stamp = $TimeStamp } } catch { $TimeStamp = (Get-Date).ToString("yyyy-MM-dd_HHmm") [PSCustomObject]@{ ComputerName = $Computer Status = "Unable_to_Connect" OS_Name = $null vCPUs = $null Live_AvgCpu_Pct = $null Physical_Memory = $null Live_RamUsage_Pct= $null DiskAllocated_GB = $null DiskUsed_GB = $null DiskPercentUsed = $null Time_Stamp = $TimeStamp } } finally { if ($Session) { Remove-CimSession -CimSession $Session -ErrorAction SilentlyContinue } } } # Initialize properties $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $ThrottleLimit) $RunspacePool.Open() $Jobs = New-Object System.Collections.Generic.List[PSCustomObject] # Prepare an array to hold all results for the CSV file if requested if ($CSVPath) { $CSVResults = New-Object System.Collections.Generic.List[PSCustomObject] } } PROCESS { foreach ($Computer in $ComputerName) { $Computer = $Computer.Trim() $PowerShell = [PowerShell]::Create().AddScript($ScriptBlock).AddArgument($Computer) $PowerShell.RunspacePool = $RunspacePool $Jobs.Add([PSCustomObject]@{ Instance = $PowerShell Handle = $PowerShell.BeginInvoke() }) } } END { while ($Jobs.Count -gt 0) { $FinishedJobs = @($Jobs | Where-Object { $_.Handle.IsCompleted }) foreach ($Job in $FinishedJobs) { $Result = $Job.Instance.EndInvoke($Job.Handle) # Always pass the results live to the console/pipeline Write-Output $Result # Collect the data for CSV writing if requested if ($CSVPath) { $CSVResults.Add($Result) } $Job.Instance.Dispose() [void]$Jobs.Remove($Job) } if ($Jobs.Count -gt 0) { Start-Sleep -Milliseconds 200 } } # Export to CSV if a path was specified if ($CSVPath -and $CSVResults.Count -gt 0) { $CSVResults | Export-Csv -Path $CSVPath -NoTypeInformation } if ($RunspacePool) { $RunspacePool.Close() $RunspacePool.Dispose() } } } <# Get-ServerMetrics -ComputerName (Get-Content "servers.txt") | Export-Csv -Path "C:\Temp\ServerMetrics_$(Get-Date -Format "yyyyMMdd_HHmmss").csv" -NoTypeInformation #> |