PowerShell Strikes Back: A New Script6 min read

This is it. The final chapter of PowerShell Strikes Back.

Over the past four weeks, you’ve built a real foundation. You know that single quotes are literal and double quotes expand variables. You know how to store and use data in variables – strings, integers, booleans, and hashtables. You know how to loop over a collection and do something useful to each item, including handling errors when a server doesn’t cooperate.

Now we put it all together. No new concepts this week, just everything you’ve learned working as a single, practical script that solves a real DBA problem. Think of it as your Jedi trials. The training is done. Time to use the Force.

The script we’re building: a multi-server SQL Server environment health check that loops over a list of instances, checks SQL Server and SQL Agent service status, queries for databases not in the FULL recovery model, and writes a clean timestamped report to a log file. Something you could actually schedule and use.


The Script: Environment Health Check

Let’s walk through it section by section, then see it all together at the end.

Section 1: Configuration Variables

Everything that might change between environments lives at the top as variables. This is the habit from Week 2, no hardcoded values buried in the middle of the script.


Notice $logFile uses double quotes so PowerShell expands $logPath and the Get-Date subexpression to build a timestamped filename automatically. Week 1 and Week 2 in action on line one.

Section 2: Helper Function for Writing Output

Instead of calling Write-Host and writing to the log file separately every time, we build one small function that does both at once. Write it once, use it everywhere.

Section 3: The Main Loop

Here’s where Week 3 takes over. We loop over every server in $servers, check services, run a SQL query, and evaluate the results. The try/catch keeps a single bad server from stopping the whole check.


The Complete Script

Here it is in one block, ready to copy into VS Code or PowerShell ISE:


Sample Output


Three servers checked. A warning surfaced on HRSystem. SQL Agent is stopped on PROD-02, worth investigating. DR-01 was unreachable, but the script kept going and reported it cleanly. Everything is logged to a timestamped file ready to review or email.


Where to Take This Next

This script is a foundation, not a ceiling. Here are a few natural next steps if you want to keep building on it:

  • Add it to a SQL Agent job – run it on a schedule using sqlcmd or a CmdExec step calling PowerShell
  • Add an email alert – use Send-MailMessage or PowerShell’s Send-MgMail to email the log when warnings are found
  • Pull the server list from SQL – instead of a hardcoded array, query a central management server or a config table for the list of instances
  • Add more checks – last backup date, disk space, AG health, job failure counts. The loop structure supports it all

The Series Is Complete – But the Journey Isn’t

Four weeks. Four fundamentals. One complete script. You came in as someone who had dabbled in PowerShell but never really owned it. You’re leaving with quotes, variables, loops, error handling, functions, logging, and a working multi-server health check that you built up from scratch.

The Emperor of manual, repetitive DBA work has been defeated. The rebellion wins.

If you’ve been following along, drop a comment below and let me know if you get the script running in your environment. Did you extend it with additional checks? I’d genuinely love to hear what you built.

And if you missed any weeks, the full series is below. Start at Week 1 and work through in order; each post builds on the last.

Until next time. May the Force be with your scripts.


PowerShell Strikes Back — The Complete Series:
Week 1: Single vs Double Quotes (May 4)
Week 2: Variables (May 11)
Week 3: For Each Loop (May 18)
Week 4: Putting It All Together (May 26) — You are here

0 Replies to “PowerShell Strikes Back: A New Script6 min read”

Leave a Reply

Your email address will not be published. Required fields are marked *