Monitoring Windows FreeSpace with Slackbot: The Code

In part one of Monitoring Windows Freespace with Slackbot, we got everything set up to use a Slackbot url for posting messages to your Slack team. Now, we are going to take that url and use it in a batch file to send notifications about freespace on your servers hard disks. The end result will be a windows batch script that runs periodically to check the amount of space on your server and send you, or a channel, a message telling you what disks are below a certain space threshold.

To get started, create a folder call Freespace Monitor somewhere on your windows machine. Copy the curl.exe file that we extracted in the last part into this folder. Then create a batch file called freespace.bat. Your folder should looks similar to this:

Now, using your favorite text editor, edit the freespace.bat file. First thing we’re going to do is turn off echo so that we don’t get an output of every single command that our script executes. At the top of the file add “@ECHO OFF”. Next, we need to get a list of the drives on the system. For this, we’ll use WMIC. WMIC is a command line interface for getting information from the Windows Management Instrumentation. So, we’re going to call wmic in a for loop, so that we can process the whole list of drives that returns from the command. Copy this into the file after @echo off

for /f "skip=1 delims=" %%x in ('wmic logicaldisk get caption') do call :process_drives %%x
goto :eof

This for loop runs the command and calls the :process_drives function, passing each line of the command output to the function. It skips the first line because it is just a header for the output. The goto :eof is there for when :process_drives returns. Since all of the code is in the same file, if we left that out, it would proceed into a part of the file that we don’t want it to execute. The output of the wmic command, if you ran it in the command line, would look something like this depending on what your drive letters are:

Screen Shot 2015-12-30 at 3.43.05 PM

Now, lets look at the process_drives function. Copy this into the bottom of the file.

:process_drives
if "%1" NEQ "" (
for /f "tokens=1,2 delims=-" %%a in ('fsutil fsinfo drivetype %1') do call :process_types %%a %%b
)
goto :eof

This function takes the passed in parameter and uses it to get the type for the drive that we’re processing.  The if statements checks that we actually got a drive letter from the calling function, then it uses a for loop to get the output for an fsutil command. This command outputs the drive letter, and its type.

Screen Shot 2015-12-30 at 4.14.57 PM

The for loop passes the drive letter and it’s type on to the process_types function where we’ll sort out which drives we want to get the free space on. Go ahead and put this in the file after the goto :eof of the process_drives function.

:process_types

if "%2" EQU "Fixed" (
call :send_freespace %1
)
goto :eof

 

This function is pretty simple, it takes the second parameter and checks that it equals “Fixed” because those are the types of drives we want to get the free space on. You may be asking, how does this work, when the second parameter contains “Fixed Drive”? It works because the space between Fixed and Drive makes them 2 separate parameters when the variable is substituted for the string in the function call. So, what the processor sees is :process_types c: Fixed Drive. So, the if statement only gets the Fixed part. Now that we have a fixed drive we can go about getting the free space for that drive.

The first thing we do is define the function and set some variables. Copy this to the bottom of the file.

:send_freespace
SET /a THRESHOLD=20
SET DRIVELETTER=%1
SET CHANNEL=@paul

SET CHANNELNEW=%CHANNEL:@=%
if %CHANNELNEW% NEQ %CHANNEL% SET CHANNEL=%%40%CHANNELNEW%

SET CHANNELNEW=%CHANNEL:#=%
if %CHANNELNEW% NEQ %CHANNEL% SET CHANNEL=%%23%CHANNELNEW%

SET MESSAGE="Disk space on %COMPUTERNAME% disk %DRIVELETTER% is less than %THRESHOLD%GB. Please log on and free up some space."

These are the variables that you can change to fit your needs. The threshold is the number of gigabytes that your drive would get below before you get a message. The drive letter is passed in by the calling function. The channel is the channel you would like your message to go to. All you have to do for this is put the channel or direct message name in this variable just like you see it in slack. So to post to general, you would put #general. For a direct message, you would put @user. The next few lines are there to url encode the # and @ symbols because you can’t send either of those through an http url. Basically what it does is replace the @ with nothing, then if they strings are different, it means that that symbol existed in the original. So, it puts the url encoding on the front of that channel or user name for the original symbol. The Message variable can be changed however you would like, and you can include whatever information you would like.

Next, the script changes into the directory that it is running from so that we can call cURL with a relative path. You want to copy this in below where the message variable is set.

cd /d %~dp0

The next block takes the drive letter and uses it to get the number of free bytes on that disk:

REM get Free space
fsutil volume diskfree %DRIVELETTER% | find "of free" > space.tmp

set /p SPACE=<space.tmp

del space.tmp

for /F "tokens=2 delims=:" %%a in ("%SPACE%") do (
SET SPACESTR=%%a
)

First, we run fsutil piped to a find to get the number of free bytes on the disk and push that result to a temporary file. Then we read that back into a variable, and parse it with a for loop. The output of the fsutil function should look like “Total # of free bytes        : 41866162176”. The for loop splits it on the : and then only takes the second token, the number. This number is saved into a string because unfortunately the command line is limited to 32 bit numbers, and for modern disk drives this number is usually bigger than that. Now we can turn that string into an integer, and reduce it to gigabytes. To do this we have to be clever. Add this code to your file.

echo wsh.echo cdbl(%SPACESTR%)/1024/1024/1024 > %temp%.\tmp.vbs

for /f "delims=." %%a in ('cscript //nologo %temp%.\tmp.vbs') do set diskspace=%%a

del %temp%.\tmp.vbs

set /a SPACENUM=%diskspace%

To get around that 32 bit integer limitation we have to use a little bit of VB. All this does is echo a double representation of our bytes divided by 1024, 3 times. This changes our bytes into gigabytes. Then we use our for loop again to run that vb and take the results into a variable. Finally we get to send our message.

 

SET URL="https://slackteam.slack.com/services/hooks/slackbot?token=TOKEN&channel=%CHANNEL%"

if %SPACENUM% LEQ %THRESHOLD% (
curl -k --data %MESSAGE% %URL% --verbose >> freespace.log 2>&1
)
goto :eof

All you do now is change the put your URL in the url variable, be sure &channel=%CHANNEL% is on the end, and it is surrounded in quotes. The freespace number we got from the vb code is checked against the threshold and if it is less, then we use cURL to post the message. The “k” flag allows cURL to make connections even if it thinks they are insecure.  You can remove “–verbose >> freespace.log 2>&1 ” if you don’t want to keep any logs.

Now you have to do is put this on your windows servers and use task scheduler to schedule the script to run as often as you would like to check your available space. Just make sure when you copy the .bat file, that you copy the cURL exe as well. If you have any trouble running it, try right clicking and clicking “Run as Administrator” because some of the command line functions may require administrator privileges. Also, I attached a copy of my freespace.bat file that you can compare with yours.

Freespace.batDownload

Thanks for reading, I hope this helps you keep tabs on how your servers are doing.

Leave a Reply