Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

A PowerShell Network Monitor

Posted on May 12, 2020October 12, 2021

I hope you've been trying your hand at the scripting challenges being posted on the Iron Scripter website. The challenges are designed for individuals to do on their own to build up their PowerShell scripting skills. A few weeks ago, a challenge was posted to create a network monitoring tool using PowerShell and the Write-Progress cmdlet. I thought I'd share my notes on the challenge and some of the code I came up with.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Intermediate Challenge

The first step was to identify the necessary performance counters for Get-Counter.

$counters = "\Network interface(*ethernet*)\Bytes sent/sec",
"\Network interface(*ethernet*)\Bytes received/sec",
"\Network interface(*ethernet*)\Bytes total/sec"

With these, I could use Get-Counter to retrieve the data.


Get-Counter -Counter $counters -MaxSamples 10 -SampleInterval 1 -ov d | 
Select-object -ExpandProperty CounterSamples | Select-Object -Property Timestamp,
@{Name="Computername";Expression = {[regex]::Match($_.path, "(?<=\\\\)\w+").Value.toUpper() }},
@{Name = "Counter"; Expression = { ($_.path -split "\\")[-1]}},
@{Name = "Network"; Expression = {$_.instancename}},
@{Name = "Count"; Expression = {$_.cookedValue}}

I'm parsing out values from the counter sample property.

netperf-1

If I wanted to take this a step further I could define the output as a custom object and create a format ps1xml file to clean up the display.

Advanced

The advanced challenge was to create a visual tool using Write-Progress. The cmdlet lets you have multiple progress bars in the same window. You can reference them by an ID number. This meant I had to divide up the counters.

Get-Counter -Counter $counters -MaxSamples 30 -SampleInterval 1  |
ForEach-Object {
    $network = $_.countersamples[0].InstanceName
    $computername = [regex]::Match($_.CounterSamples[0].path, "(?<=\\\\)\w+").Value.toUpper()
    $time = $_.timestamp
    $total = $_.countersamples.where( {$_.path -match "total"})
    $totalKbps = $total.cookedValue*0.008
    if ($totalKbps -gt 100) {
        $totalPct = 100
    }
    else {
        $totalPct = $totalKbps
    }
    $sent = $_.countersamples.where( {$_.path -match "sent"})
    $sentKbps = $sent.cookedValue*0.008
    if ($sentKbps -gt 100) {
        $sentPct = 100
    }
    else {
        $sentPct = $sentKbps
    }
    $rcvd = $_.countersamples.where( {$_.path -match "received"})
    $rcvdKbps = $rcvd.cookedValue*0.008
    if ($rcvdKbps -gt 100) {
        $rcvdPct = 100
    }
    else {
        $rcvdPct = $rcvdKbps
    }
    Write-Progress -Activity "[$time] $computername : $network" -status "Total Kbps $totalKbps" -id 1 -PercentComplete $totalpct
    Write-Progress -Activity " " -status "Send Kbps $sentKbps" -id 2 -PercentComplete $sentpct
    Write-Progress -Activity " " -status "Received Kbs $rcvdKbps" -id 3 -PercentComplete $rcvdpct

}

Another bonus element was to format the data as Kbps.  As far as I know, if I multiply the byte value by 0.008 I will get what I want. I also had to take into account the length of the progress bar since it obviously can't go above 100. Thus the display is relative and not a true graph.

In testing this, I found that Write-Progress in Windows PowerShell seems to have a display bug that doesn't produce exactly what I have in mind. But it works just fine in PowerShell 7.

netperf-2

Get-NetworkPerformance

I put all of this together into a PowerShell function.

Function Get-NetworkPerformance {
    [cmdletbinding(DefaultParameterSetName = "sample")]
    [alias("gnp")]
    Param(
        [Parameter(HelpMessage = "Specify a computer to connect to.")]
        [string]$Computername = $env:computername,
        [Parameter(HelpMessage = "Use the network description from Get-NetAdapter")]
        [string]$NetworkInterface = "*ethernet*",
        [Parameter(ParameterSetName = "continuous")]
        [switch]$Continuous,
        [Parameter(Mandatory, ParameterSetName = "sample")]
        [int64]$MaxSamples,
        [Parameter(Mandatory, ParameterSetName = "sample")]
        [Int32]$SampleInterval,
        [switch]$Passthru
    )

    Write-Verbose "Starting $($MyInvocation.MyCommand)"
    Write-Verbose "Detected parameter set $($pscmdlet.ParameterSetName)"
    Write-Verbose "Validating network interface"
    #updated 12 Oct 2021 to make sure only a single network adapter is selected 
    $c = (Get-NetAdapter -InterfaceDescription $NetworkInterface -CimSession $Computername | Where-Object { $_.status -eq 'up' }).count
    if ($c -gt 1) {
        Throw "You must specify a single network interface."
    }
    Write-Verbose "Verified a single network interface"
    #save the current progressbar setting
    $bg = $host.PrivateData.progressBackgroundColor

    #the networking counters
    $counters = "\Network interface($NetworkInterface)\Bytes sent/sec",
    "\Network interface($NetworkInterface)\Bytes received/sec",
    "\Network interface($NetworkInterface)\Bytes total/sec"

    $PSBoundParameters.Add("counter", $counters)

    if ($PSBoundParameters.ContainsKey("Passthru")) {
        [void]( $PSBoundParameters.Remove("passthru"))
    }

    if ($PSBoundParameters.ContainsKey("NetworkInterface")) {
        [void]( $PSBoundParameters.Remove("NetworkInterface"))
    }
    Write-Verbose "Passing these parameters to Get-Counter:`n $($PSBoundParameters | Out-String)"

    Try {
        Get-Counter @PSBoundParameters -OutVariable pass -ErrorAction Stop |
        ForEach-Object {
            $network = $_.countersamples[0].InstanceName
            $computername = [regex]::Match($_.CounterSamples[0].path, "(?<=\\\\)\w+").Value.toUpper()
            $time = $_.timestamp
            $total = $_.countersamples.where( { $_.path -match "total" })
            $totalKbps = $total.cookedValue * 0.008
            #adjust the progressbar color
            if ($totalKbps -ge 150) {
                $host.PrivateData.progressBackgroundColor = "Red"
            }
            else {
                $host.PrivateData.progressBackgroundColor = $bg
            }
            if ($totalKbps -gt 100) {
                $totalPct = 100
            }
            else {
                $totalPct = $totalKbps
            }
            $sent = $_.countersamples.where( { $_.path -match "sent" })
            $sentKbps = $sent.cookedValue * 0.008
            if ($sentKbps -gt 100) {
                $sentPct = 100
            }
            else {
                $sentPct = $sentKbps
            }
            $rcvd = $_.countersamples.where( { $_.path -match "received" })
            $rcvdKbps = $rcvd.cookedValue * 0.008
            if ($rcvdKbps -gt 100) {
                $rcvdPct = 100
            }
            else {
                $rcvdPct = $rcvdKbps
            }

            Write-Progress -Activity "[$time] $computername : $network" -Status "Total Kbps $totalKbps" -Id 1 -PercentComplete $totalpct
            Write-Progress -Activity " " -Status "Send Kbps $sentKbps" -Id 2 -PercentComplete $sentpct
            Write-Progress -Activity " " -Status "Received Kbs $rcvdKbps" -Id 3 -PercentComplete $rcvdpct
        }
    } #Try
    Catch {
        Write-Warning "Failed to get performance counters. $($_.Exception.message)"
    }

    if ($passthru -AND $pass) {
        Write-Verbose "Passing results to the pipeline"
        $pass
    }

    #restore the progressbar value
    $host.PrivateData.progressBackgroundColor = $bg
    Write-Verbose "Ending $($MyInvocation.MyCommand)"
}

The function offers flexibility and ease of use.

netperf-3The function has room for improvement. For one, there's no error handling. Get-Counter should really be in a Try/Catch block. This version doesn't handle alternate credentials for remote computers. Nor does it dynamically change the progress background color. I should be able to do that by dynamically changing the value of $host.PrivateData.ProgressBackgroundColor.

I even learned a few new things in solving this challenge, which is really the whole point. I hope you'll try your hand at the challenges. There are tests for every skill level. Good luck.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

5 thoughts on “A PowerShell Network Monitor”

  1. Pingback: ICYMI: PowerShell Week of 15-May-2020 | PowerShell.org
  2. Pingback: ICYMI: PowerShell Week of 15-May-2020 – 247 TECH
  3. Nothing497 says:
    May 17, 2020 at 7:15 am

    Nice function ! I would consider adding it in my PS Toolbox that I’m currently building 🙂
    I really appreciate the different techniques and new approaches in each post of the blog ! Thanks !

  4. Pingback: PowerShell Snippetrace 20-2020 | | PowerShell Usergroup Austria
  5. Pingback: Network Monitoring in Powershell – Curated SQL

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d