PowerShell and dbatools

Tested in October 2026 with dbatools 2.9.0 on PowerShell 7.4 against SQL Server 2022 test instances. Get-DbaDiskSpace (which needs PowerShell on Windows) and Sync-DbaAvailabilityGroup have since been tested on Windows against a real availability group.

dbatools is a free, community-built PowerShell module with several hundred commands for SQL Server administration. It is most useful for checking many servers at once and for repeatable migrations. Run it from an admin workstation or jump server, not from the SQL Servers themselves.

Installing

Install-Module dbatools -Scope CurrentUser
Import-Module dbatools

If the servers have no internet access, download it on another machine with Save-Module dbatools -Path C:\Temp and copy the folder across. dbatools 2.0 and later encrypt connections by default; if your servers use certificates that are not trusted, agree the right setting with the security team rather than turning checks off.

Daily read-only checks

$servers = 'SQL01', 'SQL02', 'SQL03'

# Databases without a full backup in the last 24 hours
Get-DbaLastBackup -SqlInstance $servers |
    Where-Object { -not $_.LastFullBackup -or [datetime]$_.LastFullBackup -lt (Get-Date).AddDays(-1) } |
    Select-Object SqlInstance, Database, LastFullBackup, LastLogBackup | Format-Table -AutoSize

# Disks under 15% free (needs PowerShell on Windows: it uses WMI/CIM)
Get-DbaDiskSpace -ComputerName $servers | Where-Object PercentFree -lt 15 | Format-Table -AutoSize

# Agent jobs that did not succeed in the last day
Get-DbaAgentJobHistory -SqlInstance $servers -StartDate (Get-Date).AddDays(-1) -ExcludeJobSteps |
    Where-Object Status -ne 'Succeeded' | Format-Table -AutoSize

# Error log entries mentioning errors in the last 24 hours
Get-DbaErrorLog -SqlInstance $servers -After (Get-Date).AddHours(-24) |
    Where-Object Text -match '^Error:|\bfailed\b' | Format-Table -AutoSize

# Build level and whether it is the latest
Test-DbaBuild -SqlInstance $servers -Latest | Format-Table -AutoSize

Useful one-off commands

# Restore the latest backups to a test server and run CHECKDB on them
Test-DbaLastBackup -SqlInstance SQL01 -Destination SQLTEST01 -Database YourDB

# Top waits
Get-DbaWaitStatistic -SqlInstance SQL01 -Threshold 95

# Run the same query everywhere
Invoke-DbaQuery -SqlInstance $servers -Query 'SELECT @@SERVERNAME AS server_name, @@VERSION AS version;'

Test-DbaLastBackup is the easiest way to prove backups restore. It drops the test copy afterwards. The backups must be on a network share (\\server\share) that the test server can read; with local backup paths it reports “Restore not located on shared location”.

Commands that make changes (need approval on production)

# Copy a login with its SID and password
Copy-DbaLogin -Source SQL01 -Destination SQL02 -Login 'DOMAIN\someuser'

# Sync logins, jobs and other server objects across an Availability Group (not yet tested)
Sync-DbaAvailabilityGroup -Primary SQL01 -AvailabilityGroup AG1

Most commands that change things accept -WhatIf, which shows what would happen without doing it. Use it first.

Good practice

  • Wrap regular checks in a script that writes to a log file (Start-Transcript) or a table, and schedule it on the admin server.
  • Pin the dbatools version on shared servers and update deliberately; commands occasionally change between releases.

From my SQL Server DBA handbook.