A VBScript ‘Wake on LAN’ Project

Note: WordPress does weird things to punctuation, so don’t copy and paste the scripts in this post. For your convenience I’ve packaged the three scripts as plain text VBS files in a ZIP file, which you can download here: VBScript Wake On Lan ZIP File

I was working at home one weekend recently, performing some scheduled server maintenance. We have mostly HP servers where I work, and they have this nice feature built into them called Remote Insight. It’s a card that’s plugged into the motherboard of the server. This card has an ethernet port on it. You can connect to the RI card over this ethernet port and use it as a sort of virtual KVM. It’s a fantastic feature, letting you control a server remotely, shutting down or restarting if you need to, and, since it’s essentially attached to the console, you can even get into the BIOS should the need arise.

That is, when it works.

The RI cards are pretty reliable, but every once in a while they’ll disconnect you and make you wait a 30 minute timout period before it resets the connection. Not a big deal if you’re in the building, but a much bigger problem if you’re offsite, as I was this particular weekend.

Anyway, I had to shut down a server briefly, and that server’s RI card decided that right then would be a good time to drop its connection. I had to drive in to work on a Sunday just so I could press the power button on the server. I was good and annoyed, let me tell you.

The next work day, I decided to give myself a backup method of turning on a server. My tool of choice? A wonderful piece of technology called Wake on LAN. I use a tiny application called WOL.EXE for this. Open a command prompt, type “wol 112233445566? (that last part being a MAC address) and WOL.EXE sends out what’s called the magic packet to wake up the computer (or server) with the correct MAC address. This would have suited my needs perfectly, if only I’d had the MAC address of the server in question.

Hmm, I feel some scripting coming on.

Let’s not limit this to servers. Let’s cover all the computers in an entire domain, ok? Ok.

The first thing to do is gather all the computer names from your Active Directory domain. I found the perfect script over at Microsoft’s Script Center Repository. Their website doesn’t support direct hyperlinking, so I can’t link to the script. I’ll just give it to you here:

On Error Resume Next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject(“ADODB.Connection”)
Set objCommand = CreateObject(“ADODB.Command”)
objConnection.Provider = “ADsDSOObject”
objConnection.Open “Active Directory Provider”
Set objCommand.ActiveConnection = objConnection

objCommand.Properties(“Page Size”) = 1000
objCommand.Properties(“Searchscope”) = ADS_SCOPE_SUBTREE

objCommand.CommandText = _
“SELECT Name FROM ‘LDAP://dc=fabrikam,dc=com’ WHERE objectCategory=’computer’”
Set objRecordSet = objCommand.Execute

objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Wscript.Echo objRecordSet.Fields(“Name”).Value
objRecordSet.MoveNext
Loop

Quick side note: The script references an example AD domain as ‘LDAP://dc=fabrikam,dc=com’. The AD domain where I work is actually a subdomain of our public domain name, so I have to add to the DC path above. Like so: ‘LDAP://dc=subdomain,dc=fabrikam,dc=com’. Note how I added a third DC section. That’s how you can reference a subdomain name in an LDAP path.

The script as-is will output the information it gathers to the console, but I wanted to capture it in a text file. The easiest way to do this without modifying the script is to run the script from within Microsoft’s Scriptomatic tool, with Scriptomatic set to display the results in a text file. Boom, nice and easy. I use Scriptomatic a lot this way.

Paste the script into Scriptomatic, change the LDAP path in the script to your own AD domain, and click Run. After a second or two you’ll see a text file pop open with a list of all the computers and servers in your domain. Save this text file somewhere safe. I saved mine with the name workstations.txt.

Now we need to fetch all the MAC addresses of the computers listed in that text file we just saved. We’ll use another script to do that, using the text file we just saved as the input for the script.

Here’s the script:

‘– Let’s Dim our variables

Dim strComputer, objFSO

‘–Set some constants used for manipulating text files

Const ForReading = 1
Const ForAppending = 8

‘– Let’s open the list of workstations we grabbed from Active Directory

Set objFSO = CreateObject(“Scripting.FileSystemObject”)
Set objFile = objFSO.OpenTextFile(“C:\scripts\Fetch MAC Addresses\workstations.txt”, ForReading)

‘– We want to loop through the text file line by line

‘– grabbing MAC addresses as we go —

Do Until objFile.AtEndOfStream
strComputer = objFile.ReadLine

‘– Let’s see if we can ping the workstation

Set WshShell = CreateObject(“WScript.Shell”)
PINGFlag = Not CBool(WshShell.run(“ping -n 2 -w 250 ” & strComputer,0,True))

‘– If we can ping the workstation, grab the MAC address and save it in a text file

If PINGFlag = True Then
wScript.Echo strComputer & ” pings”
Dim objShell,objExec
Set objShell=CreateObject(“wscript.shell”)
strCommand=”nbtstat -a ” & strComputer
Set objExec=objShell.Exec(strCommand)
Do While objExec.StdOut.AtEndOfStream True
strLine=objExec.StdOut.ReadLine
If InStr(strLine,”MAC Address”) Then
arrFields = Split(strLine, ” “)
strMAC1 = arrFields(7)
strMACAddress = Replace(strMAC1, “-”, “”)
strCompEntry = strComputer & “,” & strMACAddress
Set objFile2 = objFSO.OpenTextFile(“C:\scripts\Fetch MAC Addresses\MAC_Addresses.txt”, ForAppending)
objFile2.WriteLine strCompEntry
objFile2.close
End If
Loop
Else

‘–If we can’t ping the workstation, let’s log that so we

‘– can get the MAC address later

Set objFile3 = objFSO.OpenTextFile(“C:\scripts\Fetch MAC Addresses\cannot_ping.txt”, ForAppending)
objFile3.WriteLine strComputer
objFile3.close

End If

Loop

The script reads the first workstation name, sees if the workstation responds to ping, runs the nbtstat command against the workstation, grabs the MAC address by monitoring the stdout of the nbtstat command, then saves the workstation name and MAC address (sans hyphens) to a second text file. Also, if the workstation does not respond to ping, it saves that workstation name to a third text file. We can use this third text file at a later date as the input file of this same script so that, over time, we can gather all the MAC addresses in our domain.

There you have it, all the MAC addresses in your domain. For myself, I now have all the information I need to wake up any workstation or server on my domain, but let’s not stop here. Let’s make it easy to use the MAC addresses we just gathered.

Here’s a script that prompts you for a workstation name, searches for the MAC address in the second text file, then automatically sends the WOL packet to wake up the workstation.

‘– Let’s dim our variables
dim fname, objFSO, objFile

‘– This opens an input box into which we’ll enter our workstation name

fname=InputBox(“Which computer do you want to wake up?”)
fname = UCase(fname)

‘– Some tracking integers

i = 0
y = 0

Const ForReading = 1

‘– Open the text file of MAC addresses and read the
‘– entire thing into memory at once

Set objFSO = CreateObject(“Scripting.FileSystemObject”)
Set objFile = objFSO.OpenTextFile_
(“C:\scripts\Fetch MAC Addresses\Copy of MAC_Addresses.txt”, ForReading)
strFile = objFile.ReadAll
objFile.Close

strList = Replace(strFile, vbCrLf, “,”)
wScript.Echo strList

‘– Split the file into an array, using the comma delimiter

arrFields = Split(strList, “,”)

‘– When we find a match we’ll increment Y by 1, but
‘– we want the script to keep looping until otherwise

Do While y=0

‘– Whatever array field has the workstation name, the MAC address
‘– will be in the next field

strPC=arrFields(i)
strMAC=arrFields(i+1)

‘– Let’s see if we have a match between the workstation name taken
‘– from the text file and the input box

If strPC = fname Then

‘– If we do, let’s grab the MAC address and send the WOL signal

Dim objShell,objExec
Set objShell=CreateObject(“wscript.shell”)
strCommand=”C:\scripts\wol.exe ” & strMAC
Set objExec=objShell.Exec(strCommand)
‘– Let’s get a visual confirmation that we sent the WOL signal

wscript.echo “Wake on lan command sent to MAC address ” & strMAC

‘– Since we found a match, let’s increment Y
y=1
End If

‘– If we didn’t find a match, let’s look at the next workstation name
‘– which will always be two array segments away

i=i+2

‘– The loop will terminate here once Y=1, otherwise it’ll keep going

Loop

And there you have it. I hope you find this helpful.

  • Anonymous

    In the final script where it retrieves the MAC address based on your input,
    it seems to only work if all of the entries are on the same line.

    Otherwise it’s not accurate…  as the MAC retrieval script places the entries
    on multiple lines this will require some modification. Let me know if you
    can figure out how to do it.

  • http://www.google.com/profiles/jeff.harbert#about Jeff Harbert

    Sorry for the delay in replying, and thank you for your comment. Yes, you are correct. The final WOL script does require all the entries to be on a single line. The easiest way to handle this would be to do it in memory. Add these two lines after “objFile.close”:

    strList = Replace(strFile, vbCrLf, “,”)
    wScript.Echo strList

    This replaces the line feeds at the end of each line with a comma before the entire file is split into an array.

    I’ve updated the script in the post as well.

  • Billy Russell

    Great scripts.  I’m having a slight issue with the one that pings and pulls the MAC.  I get a script error on the line:

    Do While objExec.StdOut.AtEndOfStreamTrue

    It says the object doesn’t support this method.  If i remove True from the end it runs, but never stops running.  I’m no VBScript expert so any help would be appreciated.

  • http://www.google.com/profiles/jeff.harbert#about Jeff Harbert

    There should be a space before ‘True’:

    Do While objExec.StdOut.AtEndOfStream True

    I recently edited this post and WordPress sometimes drops spaces when copying and pasting. Sorry about that, and thanks for bringing this to my attention.

  • Billy Russell

    I’ve noticed that wordpress does all kinds of nasty things to scripts.  Changes formatting, punctuation, etc…  Thanks for the quick reply.  There are more errors, but most likely due to the copy from word press.  I’m going through it line by line.  Eventually it will work itself out or my boss will stop asking me to be a vb expert.

  • http://www.google.com/profiles/jeff.harbert#about Jeff Harbert

    Billy – I’ve packaged the three VBS (simply created in Notepad) scripts as a ZIP file and (I think) fixed all the WordPress-induced incorrect punctuation. Here’s the link to the ZIP file: http://dl.dropbox.com/u/569310/WakeOnLan.zip

    I’ll also add this ZIP file to the post. Do let me know how well the scripts in the ZIP file work for you.

  • Billy Russell

    Sorry for the delay, I was unable to reply here last week.  It is still giving an error in the same place.  I haven’t had time to troubleshoot it.  If I remove True from the end it does run, but it never does the mac address find, just checks for ping and writes all the failures to a txt file but not of the successs get logged.

  • http://twitter.com/ChrisKader ChrisKader

    I know this post is old but I was looking for a method to send WOL by using just vbScripting (No WOL exe). After looking at your script, I found the issue. Here is the fixed section (lines 35 to 46)

    DostrLine=objExec.StdOut.ReadLineIf InStr(strLine,”MAC Address”) ThenarrFields = Split(strLine, ” “)strMAC1 = arrFields(7)strMACAddress = Replace(strMAC1, “-”, “”)strCompEntry = strComputer & “,” & strMACAddressSet objFile2 = objFSO.OpenTextFile(“C:toolsdnsmac.txt”, ForAppending)objFile2.WriteLine strCompEntryobjFile2.closeEnd IfLoop While Not ObjExec.Stdout.atEndOfStreamElse

    Basically, remove everything from the Do and add the “While Not ObjExec.Stdout.atEndOfStream” after the loop on line 46.