Scripting as a network engineer
In the three years I’ve been working I’ve done a bit of automating and scripting to make my work life a bit easier. I like to automate the task I do (almost) everyday or the things that I would have to repeat more than ten times.
Since I work as a network engineer at a hospital, I don’t have all the permissions to download whatever programming language I would like. But I do have Powershell. So because of this, I started writing and learning a bit more Powershell. In my studies I’ve learned the basics of Powershell, but barely ever used it for anything useful.
This obviously changed once it was the only programming language available to me. Most of my quality of life improvements are added to my Powershell profile and I use the ps terminal in some way for nearly every task I do at work. This would make little me so happy because that is what I imagined working in IT would look like. Like the hacker man in every movie, only working from the terminal. (I do not only work from the terminal, I just need or use it very regularly)
Scripting and automating also keeps my job interesting for me and gets me excited when I automate something on a bigger scale. The small QoL scripts are also so much time and happiness saved for me!
These are some of the automations or scripts I am quite proud of:
MAC address formatting
I can trigger this mac from my powershell terminal with the alias mac. The script takes a few parameters:
| Parameter | Alias | Description |
|---|---|---|
| ToFormatMac | mac | The MAC address that needs to be formatted |
| PredeterminedType | t, type | Any predetermined type from the list below |
| BulkFile | f, csv | Filepath for bulk csv file |
| SingleType (switch) | s | Only show given type instead of list of all formats |
| NoPrint (switch) | np | Only returns the formatted mac, doesn’t copy to clipboard - only use when importing in other script |
| ReplacePrompt (switch) | rp | Replaces the previous console line, probably the prompt |
So to format a MAC address I would type mac AA-BB-CC-DD-EE-FF -t dhcp and it would copy the formatted MAC address to my clipboard and print out this output:
❯ mac AA-BB-CC-DD-EE-FF -t dhcp
ise : AA:BB:CC:DD:EE:FF
dhcp_c : aa-bb-cc-dd-ee-ff
dhcp_u : AABBCCDDEEFF
cisco : aabb.ccdd.eeff
windows : AA:BB:CC:DD:EE:FF
ccc : aa:bb:cc:dd:ee:ff
Formatted MAC (dhcp): aabbccddeeff
Depending on which parameters are selected the output differs. By default the cisco format is used (because I need this the most). The “types” are defined by a dictionary in the script which looks like this:
$types = @{
"cisco" = [PSCustomObject]@{
charsBetweenSpacers = 4
spacerChar = "."
lowerCase = $true
}
"windows" = [PSCustomObject]@{
charsBetweenSpacers = 2
spacerChar = ":"
lowerCase = $false
}
"dhcp" = [PSCustomObject]@{
charsBetweenSpacers = 12
spacerChar = ""
lowerCase = $true
}
"dhcp_c" = [PSCustomObject]@{
charsBetweenSpacers = 2
spacerChar = "-"
lowerCase = $true
}
"ise" = [PSCustomObject]@{
charsBetweenSpacers = 2
spacerChar = ":"
lowerCase = $false
}
"dhcp_u" = [PSCustomObject]@{
charsBetweenSpacers = 12
spacerChar = ""
lowerCase = $false
}
"ccc" = [PSCustomObject]@{
charsBetweenSpacers = 2
spacerChar = ":"
lowerCase = $true
}
}
I then format the given MAC address using the variables of the type with this function:
function fm {
param (
[Parameter()]
[string]$ToFormatMac,
[Parameter()]
$type
)
if ($type.lowerCase) {
$ToFormatMac = ($ToFormatMac.ToLower() -replace "[-:._ ]", "")
} else {
$ToFormatMac = ($ToFormatMac.ToUpper() -replace "[-:._ ]", "")
}
for ($i = $type.charsBetweenSpacers; $i -lt $ToFormatMac.Length; $i+=$type.charsBetweenSpacers+1)
{
$ToFormatMac = $ToFormatMac.Insert($i,$type.spacerChar)
}
return $ToFormatMac
}
A step I added recently was validating the MAC address. This checks if the given MAC has the right amount of characters and only hex characters. For this I use this function:
function validate_mac {
$ToFormatMac = ($ToFormatMac.ToLower() -replace "[-:._ ]", "")
# Check Lengte
if ($ToFormatMac.Length -gt 12) {
return @($false, "MAC has too many characters ($($ToFormatMac.Length) characters)")
} elseif ($ToFormatMac.Length -lt 12) {
return @($false, "MAC does not have enough characters ($($ToFormatMac.Length) characters)")
}
# Check character validity
if (-not ($ToFormatMac -match '[0-9a-f]{12}')) {
return @($false, "Invalid character(s) found")
}
return @($true, "")
}
Then there’s a bit of logic to make it all function. This script has gone through a lot of iterations, functionality that I added before has been removed or changed a lot. This (like the other scripts or automations) changes whenever I think I have a good idea to improve it.
Timed pings
Most of the time when I ping a device it is to check whether it is online or not. The few other times it is to check at what time they go offline and come back online. The default ping command does not have the functionality to show the time (and date) of every ping. Since I thought this would be useful I added the timed_pings.ps1 script to my Powershell profile. The output looks like this: (except the three dots, this is just to keep the output a bit shorter)
❯ tp 8.8.8.8 -t
Pinging 8.8.8.8 with 32 bytes of data:
✓ 29/06/2026 13:41:39: Reply from 8.8.8.8: time=13ms TTL=117
...
✓ 29/06/2026 13:41:55: Reply from 8.8.8.8: time=8ms TTL=117
✗ 29/06/2026 13:41:56: No reply from 8.8.8.8
...
✗ 29/06/2026 13:42:01: No reply from 8.8.8.8
✓ 29/06/2026 13:42:02: Reply from 8.8.8.8: time=7ms TTL=117
...
✓ 29/06/2026 13:42:06: Reply from 8.8.8.8: time=8ms TTL=117
Ctrl-C used, stopping ping
Ping statistics for 8.8.8.8:
Packets: Sent = 26, Received = 20, Lost = 6 (23.1 % loss)
Approximate round trip times in milli-seconds:
Minimum = 7ms, Maximum = 13ms, Average = 6.5ms
Status switches:
✗ 29/06/2026 13:41:56: Success → Failure
✓ 29/06/2026 13:42:02: Failure → Success
This script also is quite simple but very useful none the less. This one looks a bit more like pasta, not quite spaghetti but definitely some type of pasta.
It starts with a small but necessary block of code which makes sure the script can be stopped by Ctrl-C but after the user presses the Ctrl-C it can still output some stats.
[Console]::TreatControlCAsInput = $True
Start-Sleep -Seconds 0.5
$Host.UI.RawUI.FlushInputBuffer()
:Main_Loop while ($i -lt $Count) {
# Main pinging logic
...
# https://learn.microsoft.com/nl-nl/archive/blogs/dsheehan/powershell-taking-control-over-ctrl-c
# If a key was pressed during the loop execution, check to see if it was CTRL-C (aka "3"), and if so exit the script after clearing
# out any running jobs and setting CTRL-C back to normal.
If ($Host.UI.RawUI.KeyAvailable -and ($Key = $Host.UI.RawUI.ReadKey("AllowCtrlC,NoEcho,IncludeKeyUp"))) {
If ([Int]$Key.Character -eq 3) {
Spacer
Write-Host "Ctrl-C used, stopping ping" -ForegroundColor Yellow
$i = $Count
[Console]::TreatControlCAsInput = $False
}
# Flush the key buffer again for the next loop.
$Host.UI.RawUI.FlushInputBuffer()
}
}
[Console]::TreatControlCAsInput = $False # Just to be sure
# Output ping stats
The main logic is quite simple, the only reason it’s a bit chaotic is because I wanted to preserve most of the functionality of the default ping command. But at the base the logic is as follows: while we need to keep pinging, ping the host once, print out the datetime and result and wait one second, repeat.
In practice it looks like this:
:Main_Loop while ($i -lt $Count) {
# Ping the host
$pingResult = Test-Connection -ComputerName $ComputerName -TimeToLive $TTL -Count 1 -ErrorAction SilentlyContinue
$stats["total_count"]++
# Print the datetime and result
if ($pingResult.StatusCode -eq 0) {
if ($i -eq 0){ $stats["minimum_time"] = $pingResult.ResponseTime }
if ($previousStatus -ne $true) {
$previousStatus = $true
$stats["status_switches"] += @{
"type"= "success";
"time"= "$(Get-Date)"
}
}
$ch = @{"type"="check";"color"="Green"}
Write-Host "$($special_chars[$ch['type']]) " -ForegroundColor $ch["color"] -NoNewline
Write-Host "$(Get-Date -Format "dd/MM/yyyy HH:mm:ss")" -ForegroundColor DarkGray -NoNewline
Write-Host ": Reply from " -NoNewline
Write-Host "$($ComputerName)" -ForegroundColor Blue -NoNewline
if ($pingResult.Address -ne $pingResult.ProtocolAddress) { # If the dns name is given in the result
Write-Host " [$($pingResult.ProtocolAddress)]" -ForegroundColor DarkBlue -NoNewline
}
Write-Host ": time=$($pingResult.ResponseTime)ms TTL=$($pingResult.ResponseTimeToLive)"
$stats["total_time"] += $pingResult.ResponseTime
if ($pingResult.ResponseTime -lt $stats["minimum_time"]) { $stats["minimum_time"] = $pingResult.ResponseTime }
if ($pingResult.ResponseTime -gt $stats["maximum_time"]) { $stats["maximum_time"] = $pingResult.ResponseTime }
$stats["total_success"]++
} else {
if ($i -eq 0){ $previousStatus = $false }
if ($previousStatus -ne $false) {
$previousStatus = $false
$stats["status_switches"] += @{
"type"= "failure";
"time"= "$(Get-Date)"
}
}
$ch = @{"type"="cross";"color"="Red"}
Write-Host "$($special_chars[$ch['type']]) " -ForegroundColor $ch["color"] -NoNewline
Write-Host "$(Get-Date)" -ForegroundColor DarkGray -NoNewline
Write-Host ": No reply from " -NoNewLine
Write-Host "$($ComputerName)" -ForegroundColor Blue
$stats["total_failure"]++
}
# Wait one second
Start-Sleep -Seconds 1
if (!$t -or $i -eq 0) { $i++ }
# Catch Ctrl-C
...
# Repeat
}
This one I use regularly to check how long a device is offline whenever I do some task that involve restarting a network device. Most of the time I also let a regular ping run beside it, just because sometimes it misses a ping. After I stop the ping or the number of pings has been reached it returns a summary and lists the times when the device went from reachable to unreachable and the reverse as well. This makes it easy to see how long the device was offline.
Other
I won’t go over every single script I’ve written, the two above are the two I use the most. The other scripts are for automated actions that need to be done. For example, as far as I could find there is no function in the Cisco Catalyst 9800L Wireless controller to turn of the LED on access points at night and turn them back on during the day. As you can imagine, when a patient in the hospital has a bright blue light shining when they try to sleep, they are going to complain. So I wrote a script that uses Cisco Catalyst Center to turn the LED of every access point of at 18:00 and turns them back on at 07:00. This script is just a bunch of API calls but it does the job.
PS profile aliases
My PS profile is filled with aliases and functions which I don’t classify as scripts because there too small. Some examples below:
psk
Sometimes I need to generate a PSK. How my colleague told me to do that was to just google a random string generator and use that as the psk. I then need to remove some characters because they can’t be used in the PSK’s. I use this function for that, and added the ability to change the length of the PSK:
function psk {
param (
[Parameter()]
[Alias('Count', 'cc', 'c')]
[int]$CharCount = 20
)
#$pwd = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count $CharCount | ForEach-Object {[char]$_})
$pwd = ""; do { $pwd = $pwd + ((0x30..0x39) + (0x41..0x5A) + (0x61..0x7A) | Get-Random | % {[char]$_}) } until ($pwd.length -eq $CharCount)
Write-Host "`r`npsk=" -ForegroundColor Blue -NoNewLine
Write-Host "$($pwd)`r`n" -ForegroundColor Red
}
COM port
Every time I need to use the console port of a switch or firewall, I was struggling to find the COM port on which it was connected on my laptop. Every time I had to open the device manager and look which one was connected. But then I googled if it was possible to see active COM ports in the terminal, it turns out it is (ofcourse). It’s even a single Powershell line, but I kept forgetting so I put it in a function and gave it an alias:
function COM-port {
Write-Host ([System.IO.Ports.SerialPort]::GetPortNames())
}
# alias in PS profile:
com
Some ping aliases
These are some aliases I always added to my bash profile on linux, but translated to Powershell, these are all quite clear on what they do.
function p4 { Ping -4 $args }
function pt { Ping -t $args }
function pt4 { Ping -t -4 $args }
# naar lib/profile_functions.ps1
function pc {
Spacer
Write-Host "Pinging from clipboard: '$(Get-Clipboard)'" -ForegroundColor Yellow
Ping $args $(Get-Clipboard)
}
function tracerd { tracert -d $args }
Kiekeboe script
This one is a script that I got from my colleague and I use this to keep my screen on while doing patchings or installing a new switch in a rack. After I got the script and changed it a bit to also track if I lost my connection during the time it was running, I found out it’s also a option in powertoys called Powertoys Awake
# Modified Kiekeboe Script for WiFi Troubleshooting
$icons = @{
"check"= "$([char]0x2713)"; # ✓
"cross"= "$([char]0x2717)"; # ✗
}
function checkWifiStatus(){
param (
[Parameter()]
[Alias("prev")]
[string]$PreviousStatus
)
$HostToPing = "8.8.8.8"
$Now = Get-Date -Format "hh:mm:ss"
$pingResult = Test-Connection -ComputerName $HostToPing -Count 1 -ErrorAction SilentlyContinue
if ($pingResult.StatusCode -ne 0) {
# Ping was unsuccessful (StatusCode 0 means success)
if ($PreviousStatus -eq $true){
Write-Host "$($icons['cross']) Connection Failed at $($Now) $($icons['cross'])" -ForegroundColor "Red"
}
return $false
}
if ($pingResult.StatusCode -eq 0) {
# Ping was successful (StatusCode 0 means success)
if ($PreviousStatus -eq $false){
Write-Host "$($icons['check']) Connection Re-established at $($Now) $($icons['check'])" -ForegroundColor "Green"
}
return $true
}
}
Clear-Host
Write-Host "Kiekeboe... (Modified)"
Write-Host " "
Write-Host "Started at $(Get-Date -Format 'hh:mm:ss')" -ForegroundColor Blue
Write-Host " "
$WShell = New-Object -com "Wscript.Shell"
$previousStatus = $true
$sleepTime = 60
$checks = 3
while ($true)
{
# Keep laptop on
$WShell.sendkeys("{SCROLLLOCK}")
Start-Sleep -Milliseconds 100
$WShell.sendkeys("{SCROLLLOCK}")
for ($i = 0; $i -lt $checks; $i++) {
# Check wifi connectie
$previousStatus = checkWifiStatus $previousStatus
Start-Sleep -Seconds ($sleepTime/$checks)
}
}
All the other stuff, I won’t bother you with. I just wanted to share some of my own fun stuff so that will be it for this post!
Bye!