Skip to content

Instantly share code, notes, and snippets.

@thedavecarroll
Last active May 13, 2020 05:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedavecarroll/a62355d2a1c72e86f16fd991e75291c6 to your computer and use it in GitHub Desktop.
Save thedavecarroll/a62355d2a1c72e86f16fd991e75291c6 to your computer and use it in GitHub Desktop.
IronScripter Challenge - April 27, 2020 - Building a Network Usage PowerShell Monitor
function Get-NetworkUsage {
[CmdletBinding(DefaultParameterSetName='Default')]
param(
[string]$ComputerName = $env:COMPUTERNAME,
[int]$WarnSentBytes = 10000,
[Parameter(ParameterSetName='Default')]
[int]$MaxSamples = 5,
[Parameter(ParameterSetName='Default')]
[int]$SampleInterval = 1,
[Parameter(ParameterSetName='Default')]
[string]$Outfile,
[Parameter(ParameterSetName='Default')]
[ValidateSet('JSON','CSV','TXT')]
[string]$Format = 'JSON',
[Parameter(ParameterSetName='Default')]
[switch]$Quiet,
[Parameter(ParameterSetName='Continuous')]
[switch]$Continuous
)
if ($ComputerName -ne $env:COMPUTERNAME) {
$Credential = Get-Credential -Message "Enter Credentials for $ComputerName"
try {
$Session = New-PSSession -ComputerName $ComputerName -Credential $Credential -ErrorAction Stop
if ($Session) {
$InvokeCommandSplat = @{
Session = $Session
ErrorAction = 'Stop'
}
} else {
'Unable to create PSSession on {0}' -f $ComputerName | Write-Error -ErrorAction Stop
}
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
} else {
$InvokeCommandSplat = @{
ErrorAction = 'Stop'
}
}
# prompt the user to select the adapter
try {
$NetAdapter = Invoke-Command @InvokeCommandSplat -ScriptBlock { Get-NetAdapter } | Out-GridView -Title 'Select Network Interface' -OutputMode Single
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
if ($null -eq $NetAdapter) {
'No adapter selected' | Write-Warning
return
}
# get the network interface counters
try {
$NetworkInterfacePaths = Invoke-Command @InvokeCommandSplat -Scriptblock { Get-Counter -ListSet 'Network Interface' }
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
# set ComputerName variable from counter data
$CounterComputerName = $NetworkInterfacePaths.MachineName -eq '.' ? $env:COMPUTERNAME.ToUpper() : $NetworkInterfacePaths.MachineName.ToUpper()
# get specific counter paths for the interface and Bytes Sent/Received/Total
$NetworkInterfaceCounters = $NetworkInterfacePaths.PathsWithInstances | Where-Object {
$_ -match $NetAdapter.InterfaceDescription -and $_ -match 'Bytes Sent|Bytes Received|Bytes Total'
}
if ($PSBoundParameters.ContainsKey('Continuous')) {
$GetCounterSplat = @{
Counter = $NetworkInterfaceCounters
Continuous = $true
}
} else {
$GetCounterSplat = @{
Counter = $NetworkInterfaceCounters
MaxSamples = $MaxSamples
SampleInterval = $SampleInterval
}
}
# prepare a generic list to collect the usage data
$NetworkUsage = [System.Collections.Generic.List[object]]::new()
# get the original background color
$OriginalBackground = $Host.PrivateData.ProgressBackgroundColor
$Activity = 'Network Usage'
try {
Invoke-Command @InvokeCommandSplat -ScriptBlock {param($GetCounterSplat) Get-Counter @GetCounterSplat } -ArgumentList $GetCounterSplat | ForEach-Object {
$SentBytes = $_.CounterSamples.Where{$_.Path -match 'sent'}[0].CookedValue
$ReceivedBytes = $_.CounterSamples.Where{$_.Path -match 'received'}[0].CookedValue
$TotalBytes = $_.CounterSamples.Where{$_.Path -match 'total'}[0].CookedValue
if ($NetworkUsage.Count -gt 1) {
if (!$Warned) {
$MaxSentBytes = ($NetworkUsage | Measure-Object -Property SentBytes -Maximum).Maximum
if ($SentBytes -gt $MaxSentBytes + $WarnSentBytes ) {
$Host.PrivateData.ProgressBackgroundColor = 'Red'
$Activity = 'Network Usage - Warning - SentBytes Exceeded'
$Warned = $true
}
}
}
if (!$Quiet) { Write-Progress -Activity $Activity -Id 1 -Status ('[{0}] {1} : {2} ({3})' -f $_.Timestamp,$ComputerName,$NetAdapter.Name,$NetAdapter.InterfaceDescription) }
if ($TotalBytes -ne 0) {
$SentPercent = $SentBytes -ne 0 ? $SentBytes/$TotalBytes * 100 : 0
$ReceivedPercent = $ReceivedBytes -ne 0 ? $ReceivedBytes/$TotalBytes * 100 : 0
} else {
$SentPercent = 0
$ReceivedPercent = 0
}
$TotalBytesStatus = 'Total Kbps {0:n2}' -f ($TotalBytes / 1KB)
$SentBytesStatus = 'Sent Kbps {0:n2}' -f ($SentBytes / 1KB)
$ReceivedBytesStatus = 'Received Kbps {0:n2}' -f ($ReceivedBytes / 1KB)
if (!$Quiet) { Write-Progress -Id 2 -ParentId 1 -Activity ' ' -Status $TotalBytesStatus -PercentComplete 100 }
if (!$Quiet) { Write-Progress -Id 3 -ParentId 1 -Activity ' ' -Status $SentBytesStatus -PercentComplete $SentPercent }
if (!$Quiet) { Write-Progress -Id 4 -ParentId 1 -Activity ' ' -Status $ReceivedBytesStatus -PercentComplete $ReceivedPercent }
$UsageData = [PSCustomObject]@{
ComputerName = $CounterComputerName
Timestamp = $_.Timestamp
AdapterName = $NetAdapter.Name
AdapterDescription = $NetAdapter.InterfaceDescription
SentBytes = $SentBytes
ReceivedBytes = $ReceivedBytes
TotalBytes = $TotalBytes
}
$NetworkUsage.Add($UsageData)
}
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
# reset background color
$Host.PrivateData.ProgressBackgroundColor = $OriginalBackground
# display all the data at once
# note - this "breaks" the value of the pipeline but it's the only way I could provide saving output to a file
$NetworkUsage
# save data to a file in format specified by user
if ($PSBoundParameters.ContainsKey('Outfile')) {
try {
switch ($Format) {
'JSON' { $NetworkUsage | ConvertTo-Json | Out-File -Path $Outfile }
'CSV' { $NetworkUsage | ConvertTo-Csv -NoTypeInformation | Out-File -Path $Outfile }
'TXT' { $NetworkUsage | Format-List | Out-String | Out-File -Path $Outfile }
}
}
catch {
$PSCmdlet.ThrowTerminatingError($_)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment