Here’s a simple “set it and forget it” script I keep in my toolbox. It checks Windows drive space on the SQL Server host and emails an HTML table when any drive falls below 10% free. It can run hourly as a SQL Agent job.
I didn’t originally write this. I combined notes from old scripts and kept the logic intact so you can copy and paste it.
What it does
- Enables
xp_cmdshelltemporarily and calls PowerShell to readWin32_Volume. - Loads capacity and free space into a temp table.
- If any volume is under 10% free, it sends a formatted email.
- Designed to run on the local server, no linked servers required.
Prerequisites
- Database Mail configured with a working profile.
- PowerShell available on the SQL Server host.
- The SQL Server service account must be able to query WMI on the local machine.
- You’re OK using
xp_cmdshell. If not, run it inside a locked-down environment or use an alternative.
How to use it
- Create or pick a utility database.
- Replace the placeholders for database name, DB Mail profile, and recipient.
- Run the script to test.
- Create a SQL Agent job to run it every hour (or whatever you prefer).
Copy-paste script (placeholders included)
USE [YourUtilityDB]
GO
/******
This uses powershell and Tsql
Puts data in a temp table and can be run hourly in a SQL Agent job to check space at the threshold you need. (Currently set at 10%)
Sends an email out when hits the threshold set
******/
sp_configure 'show advanced options', 1
go
Reconfigure with override
go
sp_configure 'xp_cmdshell', 1
go
Reconfigure with override
go
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Declare @svrName varchar(255)
Declare @sql varchar(400)
--by default it will take the current server name, we can the set the server name as well
SET @svrName = @@SERVERNAME
SET @sql = 'powershell.exe -c "Get-WmiObject -ComputerName ' + QUOTENAME(@svrName,'''') +
' -Class Win32_Volume -Filter ''DriveType = 3'' | select name,capacity,freespace | foreach{$_.name+''|''+$_.capacity/1048576+''%''+$_.freespace/1048576+''*''}"'
--creating a temporary table
CREATE TABLE #output
(line varchar(255))
--inserting disk name, total space and free space value in to temporary table
INSERT #output
EXEC xp_cmdshell @sql
CREATE Table ##DriveSpace
(ServerName sysname,
[PhysicalName] sysname,
[Capacity(GB)] nvarchar(20),
[Drive FreeSpace(GB)] nvarchar(20))
INSERT INTO ##DriveSpace
([ServerName]
,[PhysicalName]
,[Capacity(GB)]
,[Drive FreeSpace(GB)])
SELECT @@SERVERNAME
,rtrim(ltrim(SUBSTRING(line,1,CHARINDEX('|',line) -1))) as PhysicalName
,round(cast(rtrim(ltrim(SUBSTRING(line,CHARINDEX('|',line)+1,
(CHARINDEX('%',line) -1)-CHARINDEX('|',line)) )) as Float)/1024,0) as 'capacity(GB)'
,round(cast(rtrim(ltrim(SUBSTRING(line,CHARINDEX('%',line)+1,
(CHARINDEX('*',line) -1)-CHARINDEX('%',line)) )) as Float) /1024 ,0)as 'Drive freespace(GB)'
FROM #output
WHERE line like '[A-Z][:]%'
order by PhysicalName
DROP TABLE #output
SELECT * FROM ##DriveSpace
WHERE (Cast([Drive FreeSpace(GB)] as float)/Cast([Capacity(GB)] as float)) < .10
IF EXISTS ( SELECT * FROM ##DriveSpace WHERE (Cast([Drive FreeSpace(GB)] as float)/Cast([Capacity(GB)] as float)) < .10 )
BEGIN
DECLARE @tableHTML NVARCHAR(MAX);
SET @tableHTML = '
<body style="font-family:Sans-serif;">
<table style="width: 100%;border-collapse:collapse;border:1px solid;">
<tr style="background-color:#404040;color:#FFFFFF;">
<th>Drive Free Space under 10%</th>
</tr>
</table>
<table style="width: 100%;border-collapse:collapse;border:1px solid;">
<tr style="text-align:left;background-color:#CC0000;color:#FFFFFF;">
<td style="border: 1px solid black">ServerName</td>
<td style="border: 1px solid black">Drive</td>
<td style="border: 1px solid black">Capacity(GB)</td>
<td style="border: 1px solid black">Drive FreeSpace(GB)</td>
</tr>' +
CAST ( ( SELECT td = ServerName, '',
td = [PhysicalName], '',
td = [Capacity(GB)], '',
td = [Drive FreeSpace(GB)], ''
FROM ##DriveSpace
WHERE (Cast([Drive FreeSpace(GB)] as float)/Cast([Capacity(GB)] as float)) < .10
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;
SET @tableHTML = replace(replace(@tableHTML, '<', '<'), '>', '>')+ '</table>'
EXEC msdb.dbo.sp_send_dbmail
@profile_name = 'YourDatabaseMailProfile',
@recipients = 'ops@example.com',
@subject = 'Drive Free Space under 10%',
@body = @tableHTML,
@body_format = 'HTML' ;
END
DROP TABLE ##DriveSpace
go
sp_configure 'show advanced options', 0
go
Reconfigure with override
go
Notes and tweaks
- Threshold: it’s set at 10% in two places. If you want 15%, change
.10to.15in both theSELECTand theIF EXISTS. - Security:
xp_cmdshellis enabled here and left on as the original script does. If you prefer to turn it off after the run, add this as a separate step in your Agent job:
EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE WITH OVERRIDE;
- Agent job: create a job with one T-SQL step that runs the script and schedule it hourly.
- HTML styling: adjust colors and fonts in the HTML string if you want a different look.
Summary
This script checks Windows drive space from SQL Server using PowerShell/WMI and loads the results into a temp table. If any drive drops below 10% free, it emails a simple HTML report so you can act before things break.
- Runs on a schedule as a SQL Agent job.
- Uses
xp_cmdshellto call PowerShell. - Threshold is easy to change (look for
.10). - Requires Database Mail (profile name matches the one in the script).
If you’re not comfortable leaving xp_cmdshell enabled, run the monitor in one step and add a second job step to disable it after each run.
Discover more from SQLYARD
Subscribe to get the latest posts sent to your email.


