Last active
May 13, 2020 05:17
-
-
Save thedavecarroll/a62355d2a1c72e86f16fd991e75291c6 to your computer and use it in GitHub Desktop.
IronScripter Challenge - April 27, 2020 - Building a Network Usage PowerShell Monitor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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