How to use VBS, WMI, and Twitter to track your server temperature.
With the record temperatures in Seattle this week, I finally got around to doing something kind of silly but useful. I really just wanted something simple to notify me when my server was getting too hot, warning levels, while not good, are manageable. Critical levels, I end dealing with another way. Dell says my 2900 should warn me at 42c and critically warn me at 47c. Personally I’m much happier when it’s hovering around 34c.
But like I said, I just wanted a quick way to be notified if my server is getting to hot. Twitter has the benefit of texting me directly for stuff I choose so I figured it’d be an easy way of being notified. With the help of a few searches and some hacking and slashing of code I’ve got a nice little way of keeping tabs on my server through Twitter now. Technically since it’s using WMI, keeping track of just about anything is possible. There’s a load of data available if you check out MSDN. In my case, Dell exposes quite a bit of data against my PowerEdge 2900. In most cases this script and this sort of idea will work with just about any system out there running Vista, 7, or Server 2008. Straight out of the box no less.
First things first, I wanted to make sure I could pull the right data. In this sample, we use some simple VBS to query the WMI service and create a query to pull the current reading and status from the temperature sensor. In my first version, I omitted the if statements to make things simpler but later to make it work with the Twitter portion of the script I needed to write the WMI values to a variable. I did this a second time to pull the fan speeds as well since the first test with the temp worked well.
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2\dell")
Set colItems = objWMIService.ExecQuery("Select CurrentReading, Status from CIM_TemperatureSensor")
For Each objItem in colItems
if typename(objItem.Status) <> "Null" then
if objItem.Status(0) <> "" Then
sStatus = objItem.Status(0) ' write to variable
Wscript.Echo "Status: " & sStatus ' print out the info
end if
end if
if typename(objItem.CurrentReading) <> "Null" then
if objItem.CurrentReading(0) <> "" Then
sTemp = objItem.CurrentReading(0) ' write to variable
Wscript.Echo "Temp: " & sTemp / 10 & "c" ' print out the info
end if
end if
Next
Set colItems = objWMIService.ExecQuery("Select CurrentReading from CIM_Tachometer") ' switching context
For Each objItem in colItems
if typename(objItem.CurrentReading) <> "Null" then
if objItem.CurrentReading(0) <> "" Then
sFan = sFan + objItem.CurrentReading(0) ' increase the sum of fan speeds
sCount = sCount + 1 ' increase the count of fans
end if
end if
Next
Wscript.Echo "RPM: " & Cstr(Round(sFan / sCount)) ' take the sum total of fan speeds and average it out
So this first VBScript really just comes in handy for making sure you’re gathering the right data and writing it to a variable then printing it out to the command line fine. Perfect little test bed really.
Next, we’ll want to make sure we can write to Twitter just fine. To do this I used this sample VBScript:
if not wscript.arguments.count > 1 then
wscript.echo "Not enough options provided"
wscript.quit
end if
sUrl = "http://twitter.com/statuses/update.xml"
sUsername = wscript.arguments(0)
sPassword = wscript.arguments(1)
sMessage = wscript.arguments(2)
wscript.echo sUsername & ", " & sPassword & ", " & sMessage
sMessage = "status=" & sMessage
HTTPPost sUrl, sMessage, sUsername, sPassword
Function HTTPPost(sUrl, sRequest, sUsername, sPassword)
set oHTTP = CreateObject("Microsoft.XMLHTTP")
oHTTP.open "POST", sUrl,false,sUsername,sPassword
oHTTP.send sMessage
HTTPPost = oHTTP.responseText
WScript.Echo HTTPPost
End Function
The usage is pretty simple, from the command line you run the script, twitter.vbs you pass it your username, password, and the message you want posted. If it updates Twitter you know that bit works. I honestly borrowed this code from some random find on the web, I wish I could remember which result it was but I don’t (if you recognize it please give me a link for proper credit). But honestly there’s a bunch of samples out there, Twitter does a good job of helping people with their API.
Now finally, I took the two samples above, then combined them into the code that now reads the info through WMI and posts to Twitter:
Dim strUsername, strPassword, strMessage, sStatus, sTemp, sFan, sCount ' declare variables
On Error Resume Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2\dell") 'specify wmiService
Set colItems = objWMIService.ExecQuery("Select CurrentReading, Status from CIM_TemperatureSensor")
For Each objItem in colItems
if typename(objItem.Status) <> "Null" then
if objItem.Status(0) <> "" Then
sStatus = objItem.Status(0) ' write to variable
end if
end if
if typename(objItem.CurrentReading) <> "Null" then
if objItem.CurrentReading(0) <> "" then
sTemp = objItem.CurrentReading(0) ' write to variable
end if
end if
Next
Set colItems = objWMIService.ExecQuery("Select CurrentReading from CIM_Tachometer") ' switching context
For Each objItem in colItems
if typename(objItem.CurrentReading) <> "Null" then
if objItem.CurrentReading(0) <> "" Then
sFan = sFan + objItem.CurrentReading(0)
sCount = sCount + 1 ' take the sum total of fan speeds and average it out
end if
end if
Next
strUsername = "corego" ' Twitter username
strPassword = " " ' Twitter password, remove for testing
strMessage = "automated message from @corego's server: the status is " & CStr(sStatus) & ", the ambient temp is " & CStr(sTemp / 10) & "c, and average fan speed across " & sCount & " fans is " & CStr(Round(sFan / sCount)) & "RPM" 'mesage that's posted to Twitter.
' strMessage is where the big ass string is put together.
' Use CStr to ensure the values from WMI are in a string format, divide the temp by 10 since it needs it.
' Take the average fan speed across the number of fans and round them to make it pretty.
' Calling the function and store the result in a variable.
Dim strTwitterXMLResponse
strTwitterXMLResponse = SendToTwitter(strMessage, strUsername, strPassword)
' Post back the result with a messagebox so you know something happend.
' MsgBox strMessage, VbOkOnly, "TWITTER STATUS UPDATE"
' The MsgBox is disabled for live, enabled for testing, uncomment this and comment your password for testing.
Function SendToTwitter(strMessage, strUsername, strPassword) ' actual send function
' This is the function which does all the work.
' It uses XMLHTTP to post your message to Twitter.
Dim objHTTP
Set objHTTP = CreateObject("Microsoft.XMLHTTP")
objHTTP.open "POST", "http://twitter.com/statuses/update.xml", false, strUsername, strPassword
objHTTP.send "status=" & strMessage
' The function stores the Twitter response to the result of the function so you can use this later
SendToTwitter = objHTTP.responseText
Set objHTTP = nothing 'Release the object
End Function
And that’s pretty much that. You could run this as a scheduled task to update regularly. You could maybe add some refresher code to leave it running all the time and only update when the temperature changes. Options are pretty much open. You could also modify this to spit out some HTML for your WordPress blog, something I might do at some point.
In the end, I used Dell’s Open Manage stuff to use the built in alerting. I’ve set it up to basically run this VBS any time the system is in the Warning or Critical levels I mentioned previously. If the temp hits 42c it’ll kick off the alert and Twitter will get updated along with the SMS sent to my iPhone. Another future idea is to write a very simple iPhone friendly web page that’ll let me manage the server. Maybe cycle IIS, restart, shutdown, etc. For now this is good enough.
I was going to create an account just for the server on Twitter but that seems excessive. I don’t like managing multiple accounts and this should only alert when it really needs to. But there you go. Enjoy.
Oh and one last thing, I’ve tested this against only a single machine, so YMMV, I’m also not a Dev, you can probably perfect the code, make it simpler, cleaner, whatever. Feel free to provide constructive feedback.



