DEV Community

mibii
mibii

Posted on

Building Your Own PowerShell Security Auditor!

From Novice to Cyber Helper: Building Your Own PowerShell Security Auditor!

Hey fellow coding enthusiasts!

We all started our programming journey somewhere, and one of the best ways to learn is by building something practical that solves a real (even if small) problem. Today, I want to share the experience of developing a simple yet useful tool in PowerShell: a local system security auditor. This project perfectly demonstrates how you can combine system commands, process manipulation, and even create a graphical user interface (GUI) – all using PowerShell!
We'll go from an idea to an interactive application that not only highlights suspicious activity but also offers to take action.

Let's dive in!

Step 1: The Idea and First Drafts – What Do We Want to Check?
Initially, the task was simple: write a script to quickly assess certain security aspects of a local system. The key areas we decided to focus on were:
Network Activity: Which ports is our system listening on? Are there any non-standard ones or processes with suspiciously high PIDs (Process Identifiers)?
Process Integrity: Are all running processes digitally signed? Unsigned binaries can be a sign of trouble.
The first thought for network analysis was the good old netstat -ano. For checking signatures, the built-in Windows mechanism Get-AuthenticodeSignature.

Initial (simplified) idea

$netstatOutput = netstat -ano | findstr LISTENING

... some text parsing here ...

$processes = Get-Process
foreach ($proc in $processes) {
# ... signature check ...
}

This is a starting point. But we want to do it cooler and more "PowerShell-idiomatically"!
Step 2: The PowerShell Way – Objects Instead of Plain Text
Parsing the text output of netstat is a thankless and fragile task. PowerShell loves objects! And for network connections, there's a wonderful cmdlet: Get-NetTCPConnection.

✅ Key Insight: Instead of parsing strings, Get-NetTCPConnection -State Listen immediately gives us objects with convenient properties like LocalPort and OwningProcess (that very PID). This makes the code cleaner and more reliable.

A more "correct" approach

$listeningConnections = Get-NetTCPConnection -State Listen
foreach ($conn in $listeningConnections) {
$pid = $conn.OwningProcess
$port = $conn.LocalPort
# ... further analysis ...
}

Additionally, we decided it would be useful to see not just the PID for each listening port, but also the path to the process's executable. This is done using Get-Process -Id $pid | Select-Object Path, ProcessName.

Step 3: Graphical User Interface – Making It Pretty and Understandable

Outputting results to the console is fine, but a popup window with a report looks much more professional and user-friendly. This is where the magic of the .NET Framework, accessible directly from PowerShell, comes in!
✅ Key Insight: Add-Type -AssemblyName System.Windows.Forms opens up the entire world of Windows Forms to us. We can create forms, text boxes, buttons – everything needed for a simple GUI.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing # For sizes, colors, etc.

function Show-ResultPopup {
    param ($text)
    $popup = New-Object Windows.Forms.Form
    $popup.Text = "System Audit Result"
    # ... configure sizes, controls (TextBox) ...
    $popup.ShowDialog() # Show the window modally
    $popup.Dispose()    # IMPORTANT: Release resources!
}
Enter fullscreen mode Exit fullscreen mode

Don't forget .Dispose() for forms! This releases the resources used by GUI elements when they are no longer needed.

Step 4: Signature Check – Trust, but Verify

For checking the digital signatures of executable files, Get-AuthenticodeSignature -FilePath $path is our best friend. If the Status property of the result is not Valid, it's a reason for concern (or, as we found out, sometimes a peculiarity of UWP apps).

$signature = Get-AuthenticodeSignature -FilePath "C:\Path\To\File.exe"
if ($signature.Status -ne [System.Management.Automation.SignatureStatus]::Valid) {
    # Suspicious!
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Interactivity – Giving the User a Choice!

Simply showing a list of "suspicious" unsigned processes is half the battle. What if we gave the user the option to try and "kill" (terminate) them right there?
✅ Key Insight: Here we combine System.Windows.Forms.MessageBox to request confirmation from the user and Stop-Process to terminate the process.
Request Admin Rights: Terminating processes often requires administrator privileges. The script should check for this and, if possible, offer to restart with elevated rights.
Confirmation Dialog: For each "problematic" process, display a MessageBox with details (name, PID, path) and the question: "Terminate?".

$userChoice = [System.Windows.Forms.MessageBox]::Show($ownerForm, "Terminate process X?", "Confirmation", [System.Windows.Forms.MessageBoxButtons]::YesNo)
if ($userChoice -eq [System.Windows.Forms.DialogResult]::Yes) {
    Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue
    # Log the result
}
Enter fullscreen mode Exit fullscreen mode

Note the -Force for Stop-Process and error handling (at least -ErrorAction SilentlyContinue or a full try-catch).

Step 6: A Beginner's Headache – Encodings! 😵

During development, especially when we added non-English messages (Cyrillic in our original case) to MessageBox, we ran into a problem: instead of proper characters, we saw "mojibake" (Ð”Ð»Ñ etc.).
✅ Key Insight (and a common beginner mistake): This is an encoding issue with the .ps1 file. PowerShell expects a certain encoding (often UTF-8 with BOM), but the file might be saved in another (e.g., ANSI).
Solution: Always save your .ps1 files containing non-ASCII characters in UTF-8 with BOM (Byte Order Mark) encoding. Most code editors (VS Code, PowerShell ISE, Notepad++) allow you to do this.

What Did We End Up With?

We created a small but functional PowerShell script that:
Analyzes network listeners.
Checks the digital signatures of running processes.
Displays results in a user-friendly GUI.
Interactively offers the user to terminate processes with invalid signatures.

Considers the need for administrator privileges.

Lessons and Takeaways for Beginners:

Use PowerShell's Native Tools: Cmdlets that work with objects (Get-NetTCPConnection, Get-Process) are preferable to parsing text from external utilities.
Don't Be Afraid of .NET: PowerShell integrates beautifully with .NET, opening up vast possibilities (e.g., for GUI creation).
Handle Errors: try-catch blocks and proper use of -ErrorAction will make your script more robust.
Manage Resources: For GUI objects, don't forget Dispose().
Encodings – Your Friend (or Foe): Remember UTF-8 with BOM for files with international characters.
Iterative Development: Start small and gradually add functionality. Our script also went through several stages of improvement!

This project is an excellent example of how you can combine system administration, a bit of programming, and user interface creation with a powerful tool like PowerShell.
I hope this experience inspires you to create your own useful utilities! Experiment, learn, and share your successes.
Happy coding! 💻✨

Top comments (0)