Monday, October 18, 2010

VBScript: List Type, Slot and Capacity of Installed RAM.

This is just a quick script that I've found useful when I need to know what kind of RAM is installed on a PC (DRAM, SDRAM, etc.), where it is (which slot) and in what capacity (the ever-important GB's). This can be helpful in determining if a user's PC meets the minimum requirements for a particular install, or when determining if a user's PC could benefit from an upgrade. Also useful for general inventory purposes as, unlike many of the methods that display memory, this one will tell you how many chips and of what denomination the user has.


'-----------------Memory Checker------------------------------------------
Dim objIE, objDoc, popDebug
popDebug = True
strComputer = "."
memType = array("Unknown","Other","DRAM","Synchronous DRAM","Cache DRAM","EDO","EDRAM","VRAM","SRAM","RAM","ROM","Flash","EEPROM","FEPROM","EPROM","CDRAM","3DRAM","SDRAM","SGRAM","RDRAM","DDR","DDR-2")


Set ObjWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set ColItems = ObjWMI.ExecQuery("Select * from Win32_PhysicalMemory")

For Each Item in ColItems
pop("Memory Type: " & memType(Item.MemoryType))
pop("Slot: " & Item.DeviceLocator)
pop("Capacity: " & (Item.Capacity / 1048576) / 1024 & " GB")
pop("")
Next

function pop(strText)
if popDebug = True then
if Not IsObject(objIE) then
Set objIE = wscript.CreateObject("InternetExplorer.Application")
objIE.Navigate "about:blank"
objIE.Visible = 1
objIE.ToolBar = False
objIE.Width = 400
objIE.Height = 500
Set objDoc = objIE.Document
objDoc.Open
'objDoc.Writeln "<HEAD><TITLE>Immediate Window - Debugger</TITLE></HEAD>"
end if
objDoc.Writeln strText & "<br/>"
end if
end function

'-----------------Memory Checker------------------------------------------

Enjoy,

Wednesday, October 6, 2010

VBScript: Sending an e-mail via a script.

Over the years I've occasionally found it necessary to employ scripts in a fashion that makes monitoring their progress difficult or nearly impossible, given that I suffer from the human fallibility known as "needing to sleep". So to counteract this weakness and sustain the illusion that I'm some kind of omniscient IT-Deity I long ago looked into developing a way to have scripts communicate with me using that most ubiquitous of channels; e-mail.

No great trick, I know. There are tons of examples out there that will show you how to send an e-mail via script and this one isn't too dissimilar to the rest. The difference here would be in the way that I typically employ this trick, which is not something I've personally seen posted anywhere else; as part of error handling.

Granted I would suggest using this sparingly lest you be inundated with  little pops and pings from your scripts, but including something like this in those mission-critical scripts that have to run at all hours of the day or night can help you rest a little easier; or not, depending on the results. As a bonus the same function can be used to send an e-mail at any time throughout the script, so "start and stop" notifications can be configured just as easily if need be.

This particular sub is configured to work with Gmail as the sending account, primarily because it's free and easily accessible. If you're not able to use a web-accessible service you can pretty easily modify this to run off of your company's exchange system (or what have you).

The example below is straight forward; I purposely generate an error by making an illegal assignment to kick off the error checking routine and send an e-mail notification. I also stop the script from executing further, to keep the damage to a minimum (hopefully).


On Error Resume Next
Set Now = "This Value" 'Throw an error to be caught

if Err.Number <> 0 Then
msgSubject = Err.Description & " : " & Err.Number
msgText = Err.Description & vbCrlf
msgText = msgText & Err.Number & vbCrlf
msgText = msgText & Err.Source & vbCrlf
msgText = msgText & "If you get this e-mail, we're good to go!"
Call sendError("colonelhammer@yahoo.com", msgSubject, msgText)
Wscript.Quit
End if
msgbox "If you see this, I'm in trouble"



sub sendError(toField, subjectLine, msgBody)
Set objMsg = CreateObject("CDO.Message")

'Build your e-mail.

objMsg.From = "YourAddress@gmail.com" '<----Generally needs to match the address you're sending from!
objMsg.To = toField
objMsg.Subject = subjectLine
objMsg.TextBody = msgBody

'------------Back-end Configuration information for the remote SMTP server----------

objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

'SMTP Server, name or by IP address.
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"

'Type of authentication
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1

'Your UserID on the SMTP server
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusername") = "YourAddress@gmail.com@gmail.com"

'Your password on the SMTP server
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "YourPaswordHere"

'Server port (typically 25)
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

'Use SSL for the connection (False or True)
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = True

'Connection Timeout in seconds
objMsg.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60

objMsg.Configuration.Fields.Update

'------------Back-end Configuration information for the remote SMTP server----------

objMsg.Send

End Sub




Enjoy,

Sunday, October 3, 2010

I've become quite fond of VBScript over the years despite it's many quirks and limitations, most of which are counter balanced by the fact that all you need to create something on the fly is Notepad and a good memory, but there are still a few "features" I've always missed.

I personally started my path to programming with VB6, so one of those oft-missed features is the Immediate Window; a wonderful little tool that lets you keep track of the current values of variables and expressions while your program is running. Kind of a behind-the-curtain view of what's going on. The best part about the Immediate Window was that it let the program execute uninterrupted but could give you a kind of history of what transpired, if you took the time to set it up correctly.

With VBScript, on the other hand, the most commonly used method is to throw values into a MsgBox for debugging and then either delete the line, or comment it out when you're done. While this quick and dirty approach is fine and functional for simple or short scripts, when you start to work on scripts with hundreds or thousands of lines it leaves quite a bit to be desired. Not only can the large number of Msgbox pops annoy you to death with having to click "ok" dozens of times, the effort involved to turn your debugging "on" or "off" can be downright enervating. If you've ever found yourself clicking "ok" for ten minutes straight you know where I'm coming from.

So, after dealing with this for a couple of years and just accepting it as simply par for the course, I found myself with a need to write a script for an asp site that pulled a DB query and then presented the results in a table on a web page, and the lights came on. Why not use the same principle to make a reasonable facsimile of an Immediate Window? To my chagrin I found that others had come to the same conclusion long ago (hey, I'm a dabbler) but what I found wasn't exactly what I was looking for, so I wrote my own variant.

The main benefits to using this process are:
1) all of your debug information is pushed to a single screen for easy tracking
2) Your script is not interrupted by the process so test runs complete more quickly
3) You can build your debugging routine and leave it all in place within the script, turning it on or off with only a single change.

The example below includes the function, the necessary variable declarations and some usage samples. Key points: you have to declare the objIE, objDoc and popDebug variables in the main part of the script (globally) for this to work properly. Set the value of popDebug to true to turn debugging on, and false to turn it off.

'-----------------Sample Script-----------------------------------
Dim objIE, objDoc, popDebug
popDebug = True

pop("This")
pop("That")
pop("other things")

function pop(strText)
if popDebug = True then
if Not IsObject(objIE) then
Set objIE = wscript.CreateObject("InternetExplorer.Application")
objIE.Navigate "about:blank"
objIE.Visible = 1
objIE.ToolBar = False
objIE.Width = 400
objIE.Height = 500
Set objDoc = objIE.Document
objDoc.Open
'objDoc.Writeln "<HEAD><TITLE>Immediate Window - Debugger</TITLE></HEAD>"
end if
objDoc.Writeln strText & "<br/>"
end if
end function
'-----------------Sample Script-----------------------------------


Enjoy,

Saturday, October 2, 2010

VBScript: Working with System / Environmental Variables

System / Environmental Variables can be useful creatures to deal with at times, especially if you have an IT Department that actually takes the time to define custom variables specific to your environment. For most of us that's not the case, but even the "out of the box" variables can be a quick source of useful data.

There are a couple of ways to work with System Variables, the method of which depends greatly on your personal preference and whether or not you already know that a particular variable exists. If you know it's name and know it's there, then you can get the value with just a few lines of code. For a System Variable with a name of COMPUTERNAME you'd use the following.

Set wS = WScript.CreateObject( "WScript.Shell" )
strComputerName = wS.ExpandEnvironmentStrings( "%COMPUTERNAME%" )

strComputerName will contain the current value of the variable.

A quick, easy way to tell if the System Variable exists on the machine? Use the same method above and then check the value of strComputerName. If the variable is not defined on the system the value will be the name passed to wS.ExpandEnvironmentStrings(), % signs and all!

Of course I've also occasionally wanted to know what system variables are actually available for use on a machine, without playing hide-and-seek in the dark with the above method. If you're interested in generating a list of all of the available variables then use something like the following.

'----------------------------------------------------------------------

'---Optional---
Set Worker = New Logger
'---Optional---

strComputer = "."
Set objWMI = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colI = objWMI.ExecQuery("Select * from Win32_Environment")

For Each objI in colI
'Your code here, the example below outputs the list to a file
'---Optional---
Worker.logThis("Name: " & objI.Name & " : " & "Value: " & objI.VariableValue)
'---Optional---
Next

'---Optional---
Class Logger

Sub logThis(txtString)
Set objFSO = Createobject("Scripting.FileSystemObject")
objLogFile = Left(wscript.scriptname, Len(wscript.scriptname)-4) & "_Log.txt"
Set objfile1 = objFSO.OpenTextFile(objLogFile, 8, True)
objfile1.Write txtString
objfile1.Writeline
objfile1.close
end sub

end class
'---Optional---
'----------------------------------------------------------------------

For the full list of available attributes for a Win32_Environment object, search for "Win32_Environment" or go here
Win32_Environment on MSDN

Cheers,

Friday, October 1, 2010

VBScript: How to print a document after a delay

Have you ever worked in a crowded office with public and shared printers, but needed to print something personal or confidential? If you have then you've know that moment of gut-clenching, cold-sweating nausea that accompanies the old "hit print and run like hell to the printer" routine. I've had to do it in the past, and I've hated it.

So, here's a quick little script that can make life a little easier. When you run the script it will prompt you for a number of seconds to wait and the path to a Word Document (.doc) that you want to print. Just enter it in the format of "Seconds, FilePath" such as 30, C:/Temp/Test1.doc and hit enter. The script will then wait the number of seconds specified, open Word and print your document to your default printer, giving you plenty of time to walk over and stake your claim to privacy.


'-----------------------------------------------------------------
Input1 = InputBox("Seconds, FilePath",, "30, C:/Temp/Test1.doc")
findComma = Instr(Input1, ", ")-1
Seconds = left(Input1, findComma)
FilePath = right(Input1, Len(Input1)-(findComma +2))
call delayPrint(Seconds, FilePath)

function delayPrint(Seconds, FilePath)
WScript.Sleep Seconds * 1000
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Open(FilePath)
objDoc.PrintOut()
objWord.Quit
end function
'-----------------------------------------------------------------


Enjoy,

VBScript: How to stop a VBScript immediately, or terminate another running process.

Ok, we've all done it. You write a script, you think it's the bomb....you click run and realize...oops. Whatever the reason, you want to kill that little sucker and if you're unlucky enough to be running a script that moves the mouse and sends key strokes then scrambling to open taskmanager and find wscript.exe is more of a pain than it's worth.

With a little forward planning you can be prepared. Just make a copy of this script and keep a shortcut to it handy (I keep one in the quick launch bar for one-click-emergencies).

'-----------------------------------------------------------
Option Explicit
Dim objWMI, objProc, colProc
Dim strComputer, strProc
strComputer = "."
strProc = "'wscript.exe'"

Set objWMI = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")

Set colProc = objWMI.ExecQuery _
("Select * from Win32_Process Where Name = " & strProc )
For Each objProc in colProc
objProc.Terminate()
Next
'-----------------------------------------------------------

Of course this same script could be modified to terminate any running process easily enough. The only real caveat is that whatever value you pass to strProc would need to be encapsulated in single quotes, or you would need to change the ExecQuery string to include those automatically. Ah heck, here you go.

function killProc(strProc)
Dim objWMI, objProc, colProc, strComputer
strProc = "'" & strProc & "'"
strComputer = "."

Set objWMI = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")

Set colProc = objWMI.ExecQuery _
("Select * from Win32_Process Where Name = " & strProc )
For Each objProc in colProc
objProc.Terminate()
Next
end function


Enjoy,

VBScript: Easy output to a text file

When your script generates output a msgbox is seldom sufficient, especially if you want to maintain some kind of logfile or history.

Here are a couple of classes I wrote that make exporting output to a file simple and repeatable. These functions log text to a file one line at a time, with a return between each line. Not ideal for large output but sufficient for light to moderate logging needs.

'This version send output to a file in the same directory as then executing script,
'with a name the same as the script_Log.txt

Class Logger

Sub logThis(txtString)
Set objFSO = Createobject("Scripting.FileSystemObject")
objLogFile = Left(wscript.scriptname, Len(wscript.scriptname)-4) & "_Log.txt"
Set objfile1 = objFSO.OpenTextFile(objLogFile, 8, True)
objfile1.Write txtString
objfile1.Writeline
objfile1.close
end sub

end class


'Or if you need a little more flexibility as to where to put the file.

Class openLogger

Sub logThis(txtString, filePath)
Set objFSO = Createobject("Scripting.FileSystemObject")
Set objfile1 = objFSO.OpenTextFile(filePath, 8, True)
objfile1.Write txtString
objfile1.Writeline
objfile1.close
end sub

end class


To use one of these in a script, paste the class code somewhere at the bottom of the script and then define a variable as a member of that class in your main function and call the class sub.

Example, if you want to send the text "Computername: MZZ1005AH" to a text file you would do the following.

Set Worker = New Logger
Worker.logThis("Computername: MZZ1005AH")

Not flashy, but functional.

VBScript: Dynamically pull the current path of the script.

Sometimes you need to know where a script is living, without having to change a hard coded value when you deploy it. The following code is a cheap and easy way to find the current path where the script resides.

You can get the full script path, including the name of the script file by accessing the wscript object.

wscript.scriptfullname

Or to get the folder it's currently living in, minus the name:

function scriptPath()
Full_Path = wscript.scriptfullname
Name1 = wscript.scriptname
Path = Left(Full_Path, Len(Full_Path) - Len(Name1))
scriptPath = Path
end function