Showing posts with label wmi. Show all posts
Showing posts with label wmi. Show all posts

Tuesday, March 18, 2008

Log events to the local application log

This script uses the LogEvent method to write an event to the local application log. In the below, the value of strResults would have been previously set.

Set WshShell = WScript.CreateObject("WScript.Shell")
if strResults = "0" then
WshShell.LogEvent 0, "Condition 0 happened."
else
WshShell.LogEvent 1, "Condition 1 happened."
end if

Monday, May 14, 2007

AD-COIT v2.52 Released - Adds CSV output and more inventory options

I posted an update today to my AD-COIT script over on SourceForge.

With the latest release, version 2.52 adds CSV output and local admin group enumeration. CSV output, together with improving readability, makes it easier to manipulate your data using a spreadsheet app. You may notice a few bugs in the output, but all-in-all I think it was worth the time to update the release.

The most recent changes were driven by internal needs – as well as your emails and comments – so keep them coming! Mainly we needed to find and fix local admin groups, as well as just make it easier to work with our data.

As always, your input is encouraged. Let me know if you have anything you’d like to see added!

Monday, January 15, 2007

AD-COIT v2.52, Inventory Tool Released on Sourceforge

Last updated: 5/14/2007

AD-COIT (Active Directory – Computer Object Inventory Tool) is a script that I’ve put together to automate the hardware/software information gathering and inventory process, with a focus on simplicity and portability. While the target audience for AD-COIT is small-to-midsized Active Directory environments – specifically for the SBS community - you can leverage it in much larger environments for information gathering and asset tracking. The highlights of what gets logged include: workstation hardware information, operating system and configuration information, installed software, enumeration of local admin groups, and more (see below).

Useful Links:

When you go to run the script ("cscript scriptname.vbs"), the output is both echoed to the screen and written to the .CSV file. During the previous release (2.3), I had a few people ask how to tell if the script was working. Basically, if you see text being written to your command-prompt window, and you’ve configured a valid path for the CSV output (c:\scripts by default), then just let it run. You can always open a read-only copy of the output while it’s working. When it’s finished, use Excel (or something similar) to view/sort the output.

What if I need something specific, will you customize the script for me?
Sure thing. For instance, if you want the results output to a spreadsheet (as of 2.52), or have a different antivirus package you want to check – or… whatever the case may be, just let me know and we can discuss your objectives, and hopefully work out a solution.

Does it do “X”, “Y”, and/or “Z”?
Maybe… if it doesn’t yet, send me an email or post a comment and I’ll consider adding the functionality in a future release.

Does it output to .CSV?
Yes… as of v2.52. Thanks to everyone who emailed me with this suggestion! If you havn't updated recently, go grab the latest copy!

What gets included in the inventory?
The full list includes: Individual system information organized by computer name, including… operating system, service pack level, installation date, manufacturer name, BIOS name, service tag, processor information, domain role, current user, model, RAM, daylight savings status, time zone, Symantec Antivirus definition date, free space on the local drives, list of installed applications, enumeration of the local admin group, as well as a summary of the FSMO-role holders, non-responsive systems, and systems which logged errors.

Why did you write the script?
It started out to help me troubleshoot some daylight savings time problems for a new client, and then just evolved from there… adding functionality where appropriate.

Did you know something - fill-in-the-blank - doesn’t work right?
I probably am not aware of it. If you find something doesn’t work the way you expect, or is simply broken, please let me know, and I’ll take a look (yes, I do know that FSMO roles aren't written to the CSV file).


Monday, December 04, 2006

WMI: AD-COIT 2.3 Sample Output

As discussed in my last post, here is some sample output from the AD-COIT script. As you can see, it’s pretty basic. But with some minor changes, you could fairly easily make it do something else useful... such as just outputting workstation names with out-of-date definition files. Or just find the workstations that don't belong to a particular time-zone, or machines that are low on disk-space. Or you could schedule it to run and do check-ups on your network weekly.

If you give it a try, be sure and post comments, or shoot me an email. Certainly, if you have any suggestions or recommendations for improvement, I'm interested in your feedback.

-------------------------------------------------------------
Computer Name: DOMWS01
-------------------------------------------------------------
Operating System: Microsoft Windows XP Professional
Service Pack: Service Pack 2

Install Date: 1/5/2006 11:05:36 AM
Manufacturer: Dell Computer Corporation
BIOS Name: Default System BIOS
Service Tag: ABCD111
Processor type: Intel(R) Pentium(R) 4 CPU 1.70GHz
Domain Role: Member workstation
Current User: DOMAIN\username
Model: OptiPlex GX240
RAM: 267399168
Daylight Savings in effect: False
Time Zone: -5
Symantec Antivirus Definition Date: 11/29/2006 Rev. 017


C:, 23783 MB Free, Local Fixed Disk
Workstation Application List:
-----------------------------
WebFldrs XP (v.9.50.5318)
Fujitsu COBOL Free Run-time (v.6.1)
Adobe Acrobat and Reader 6.0.3 Update (v.6.0.3)
Adobe Acrobat and Reader 6.0.4 Update (v.6.0.4)
Adobe Acrobat and Reader 6.0.5 Update (v.6.0.5)
Adobe Acrobat 6.0.1 Professional (v.006.000.001)
Java 2 Runtime Environment, SE v1.4.2_06 (v.1.4.2_06)
J2SE Runtime Environment 5.0 Update 6 (v.1.5.0.60)
J2SE Runtime Environment 5.0 Update 9 (v.1.5.0.90)
Microsoft Office Professional Edition 2003 (v.11.0.7969.0)
Microsoft Office Project Professional 2003 (v.11.0.7969.0)
Symantec AntiVirus Client (v.8.1.0.825)
Windows Genuine Advantage v1.3.0254.0 (v.1.3.0254.0)
Microsoft Virtual PC 2004 (v.5.3.582)
Microsoft .NET Framework 1.1 (v.1.1.4322)

-------------------------------------------------------------



WMI: AD-COIT v2.3 (Computer Object Intentory Tool)

Updated: 1/15/07, For the latest release information go here.

Updated: 1/9/07, Instead of struggling with the extra characters and formatting issues associated with posting long scripts to blogger (see the comments below), I created a project for AD-COIT over on Sourceforge. From there, you can download the entire working script. While I plan to post information and updates to the blog, you’ll be able to find the latest release there. I'll leave the code posted below - so that you can review the logic and skim though it easily. However, if you want a copy of it...

Download the latest version of AD-COIT.


12/4/06, It's been a while since I've posted an update to my AD Workstation Inventory script, so the other day when I was using it to troubleshoot antivirus-definition updates on a few clients, I figured now would be as good of time as any to post my changes (and to do a name-change to "AD-COIT" for "Active Directory Computer Object Inventory Tool").

In any case, refer here for basic usage and instructions - as they've not really changed since my last update. You should be able to just copy and paste the below code snippet into notepad and save it with a .VBS extension. Let me know if you have any trouble doing so.

Otherwise, if you're interested in the logic or how I came up with the functions, you can check out my WMI category. If you're interested in the output, I'll post that in a follow-up.


' AD Computer Object Inventory Tool v2.3, by wmi.wmi@gmail.com
'------------------------------
' Usage: "cscript scriptname.vbs >inventoryreport.txt"

'=== Begin Script Configuration ===
strLdapPath = "'LDAP://DC=domain,DC=local'" 'Set to relflect your LDAP path
'=== End Script Configuration ===

Dim rootDSE
Dim DistinguishedName
Dim objShell,objDef,objDate,objVer,objRev,objOutFile,objFSO,objNDate,objToday, strRole
Const MegabyteConversion = 1048576
Const Warning_Threshold = 1000
Set objShell = CreateObject("WScript.Shell")


wscript.echo strLdapPath
dsqueryFSMOroles

'Set rootDSE = GetObject("LDAP://rootDSE")
'strLdapPath = "'LDAP://" & rootDSE.Get("defaultNamingContext")'"
'wscript.echo strLdapPath

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.CommandText = _
"Select Name, Location from " & strLdapPath & " Where objectCategory='computer'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
strComputer = objRecordSet.Fields("Name").Value
'Set objShell = CreateObject("WScript.Shell")
strCommand = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
Set objExecObject = objShell.Exec(strCommand)
strText=""
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadAll()
If Instr(strText, "Reply") > 0 Then
Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2")
If Err.Number > 0 then
strErrorSystems = strComputer & ", " & strErrorSystems
else
BuildHeader
OperatingSystem
BiosQuery
ProcQuery(strComputer)
DayLightSavingsEffect(strComputer)
SavDate(strComputer)
Diskspace
ListInstalledApplications
BuildFooter
end if
Err.Clear 'flushes error code from previous loop
Else
UnavailableSystems = strComputer & ", " & UnavailableSystems

End If
Loop
objRecordSet.MoveNext
Loop
Wscript.Echo "The following systems were unavailable: " & UnavailableSystems
Wscript.Echo " "
Wscript.Echo "The following systems were on, but returned an error: " & strErrorSystems


Function ListInstalledApplications
Set colItemsProduct = objWMIService.ExecQuery("Select * from Win32_Product")
Wscript.echo "Workstation Application List:"
Wscript.Echo "-----------------------------"
For Each objItemProduct in colItemsProduct
Wscript.echo objItemProduct.Description & " (v." & objItemProduct.Version & ")"
'Wscript.echo "Location: " & objItem.InstallLocation & ", "
Next

End Function

Function dsqueryFSMOroles
Dim objShell, ArrFSMOCmds(4)
Set objShell = CreateObject("WScript.Shell")

Cmd1 = "cmd /c"
Cmd2 = "dsquery server -hasfsmo "
ArrFSMOCmds(0) = "schema"
ArrFSMOCmds(1) = "rid"
ArrFSMOCmds(2) = "name"
ArrFSMOCmds(3) = "infr"
ArrFSMOCmds(4) = "PDC"

For Each ArrFSMOCmds in ArrFSMOCmds
Set objExec = objShell.Exec(Cmd1 & Cmd2 & ArrFSMOCmds)
strExecResults = LCase(objExec.StdOut.ReadAll)
Wscript.Echo ArrFSMOCmds & ": " & strExecResults
Next

End Function


Function BuildHeader
Wscript.Echo "-------------------------------------------------------------"
Wscript.Echo "Computer Name: " & strComputer
Wscript.Echo "-------------------------------------------------------------"
End Function
Function OperatingSystem
Set colItems = objWMIService.ExecQuery ("Select * From Win32_OperatingSystem")
For Each objItem in ColItems
strOs = objItem.Caption
strServPack = objItem.CSDVersion
strInstallDate = objItem.InstallDate
Next
Wscript.Echo "Operating System: " & strOs
Wscript.Echo "Service Pack: " & strServPack
Wscript.Echo "Install Date: " & WMIDateStringToDate(strInstallDate)
End Function
Function BiosQuery
Set colItems2 = objWMIService.ExecQuery("Select * from Win32_BIOS",,48)
For Each objItem in colItems2
strDellTag = objItem.SerialNumber
strManu = objItem.Manufacturer
strBiosName = objitem.Name
Next
WScript.Echo "Manufacturer: " & strManu
Wscript.Echo "BIOS Name: " & strBiosName
Wscript.Echo "Service Tag: " & strDellTag
End Function
Function WMIDateStringToDate(dtmDate)
WScript.Echo dtm:
WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) & "/" & _
Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _
& " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2))
End Function
Function ProcQuery(shost)
Set colItems4 = objWMIService.ExecQuery("SELECT * FROM Win32_Processor", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem in colitems4
strProcessor = objItem.Name
Next
Wscript.Echo "Processor type: " & strProcessor
End Function
Function DayLightSavingsEffect(shost)
Set colItems3 = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)

For Each objItem in colitems3
strDomainRole = objItem.DomainRole
strUserName = objItem.Username
strModel = objItem.Model
strRAM = objItem.TotalPhysicalMemory
strTimeZone = (objItem.CurrentTimeZone / 60)
strDayLightSavings = objItem.DaylightInEffect
Next

Select Case strDomainRole
Case 0
strRole = "Standalone workstation"
Case 1
strRole = "Member workstation"
Case 2
strRole = "Standalone server"
Case 3
strRole = "Member server"
Case 4
strRole = "Backup domain controller"
Case 5
strRole = "PDC Emulator"
End Select
Wscript.Echo "Domain Role: " & strRole
Wscript.Echo "Current User: " & strUsername
Wscript.Echo "Model: " & strModel
Wscript.Echo "RAM: " & strRAM
Wscript.Echo "Daylight Savings in effect: " & strDayLIghtSavings
Wscript.Echo "Time Zone: " & strTimeZone
strUsername = ""
End Function
Function SavDate(shost)
strCmdRun = "cmd /c"
strRegQ = "reg query "
strRegKey = "\HKLM\SOFTWARE\Symantec\SharedDefs\"
strCmdSw = " /v "
strRegKey2 = "DEFWATCH_10"
Set objExec = objShell.Exec(strCmdRun & strRegQ & "\\" & shost & strRegKey & strCmdSw & strRegKey2)
strExecResults = LCase(objExec.StdOut.ReadAll)
objVer = Right(strExecResults,16)
objRev = Right(objVer,7)
objDate = Left(objVer,8)
objYear = Left(objDate,4)
objMonth = Mid(objDate,5,2)
objDay = Right(objDate,2)
objNDate = CDATE(objMonth &"/"& objDay &"/"& objYear)
Wscript.Echo "Symantec Antivirus Definition Date: " & objNDate &" Rev. "& objRev & " "
End Function
Function DiskSpace
Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
If colLogicalDisk.Count = 0 Then
Wscript.Echo "No drives exist on this computer."
Else
For Each objLogicalDisk in colLogicalDisk
FreeMegaBytes = objLogicalDisk.Freespace / MegabyteConversion

'If objLogicalDisk.DriveType = 3 Then
If FreeMegaBytes <> 0 Then
FreeMegaBytes_String = Int(FreeMegaBytes) & " MB Free"
Wscript.Echo objLogicalDisk.DeviceID & ", " & FreeMegaBytes_String &amp;amp;amp; ", " & objLogicalDisk.Description
End if
Next
End if
End Function
Function BuildFooter
Wscript.Echo "-------------------------------------------------------------"
End Function


Friday, September 22, 2006

Patching: Mitigating against MSIE VML Exploit

SANS ISC has raised the InfoCon level to yellow today, after news that the Microsoft Internet Explorer VML exploit is becoming more widespread. SANS, Microsoft, and others are recommending to unregister the VGX.DLL to mitigate against the risk until a patch is available. Obviously, unregistering this DLL will disable the rendering of VML by your web browser, and other applications. So use this as appropriate for your environment.

The command looks like this: "regsvr32 /u "%ProgramFiles%\Common Files\Microsoft Shared\VGX\vgx.dll"

I rolled this into a GPO applied computer startup script that I'm using internally.


Set objShell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")

strUnregCommand = "regsvr32 -u -s ""%CommonProgramFiles%\Microsoft Shared\VGX\vgx.dll"
strComputer = objshell.ExpandEnvironmentStrings("%COMPUTERNAME%")

Set objExec = objShell.Exec(strUnregCommand)
strExecResults = LCase(objExec.StdOut.ReadAll)

Tuesday, March 21, 2006

WMI: Retrieving a list of installed printers

This script will retrieve a list of printers installed on a given system. By connecting to the Win32_Printer class - , it builds a collection of everything in the class, and then loops through the collection echoing the strings that we’re interested in (name, location, default).

If you follow the link to the Win32_Printer class, you’ll see that there’s a number of methods we can use to do some work. You could use this snippet as part of a more complex script that helps with some of the preparation work for a print server migration.

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

Set colInstalledPrinters = objWMIService.ExecQuery _
("Select * from Win32_Printer")

For Each objPrinter in colInstalledPrinters
Wscript.Echo "Name: " & objPrinter.Name
Wscript.Echo "Location: " & objPrinter.Location
Wscript.Echo "Default: " & objPrinter.Default
Next

WMI: TechNet Script Center Community Submitted Scripts Feed

If you’ve been reading my blog for a while, you’ve probably seen my links to Microsoft's TechNet Script Center . If you’re not familiar with the Script Center yet, it’s an excellent resource for system administration scripting, and really worth checking out. Even for if you don’t have much of a programming or scripting background, you can use some of their code snippets to start building some really useful tools.

Even more exciting, is that they recently started adding Community-Submitted scripts. So anybody with a useful tool that they’ve built, can submit it to the Community site. They also added an RSS feed for the recently added scripts that gets updated every Monday. So just load up your favorite feed reader, and point it at the Community submitted scripts feed .

And while you're at it, subscribe to my feed too!

Tuesday, February 28, 2006

WMI: Checking Symantec Antivirus version information and definition dates

Back when I posted the Symantec Antivirus definition date script, I thought it would also be useful to also know the client version information. Useful – but not absolutely necessary for the task at hand. At the time, I recall poking through the registry trying to find a version stamp somewhere, but never really getting exactly what I want.

After posting the script to get a list of installed applications, I recalled my original post, and saw just how easy it was to filter the version information out of the installed applications, and combine the two scripts to print version and definition date information together. So by adding the If-Then statement inside the For Next loop, we get exactly what we need.


strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Product")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("Wscript.Shell")
strCmdRun = "cmd /c"
strRegQ = "reg query "
strRegKey = "\HKLM\SOFTWARE\Symantec\SharedDefs\"
strCmdSw = " /v "
strRegKey2 = "DEFWATCH_10"
Dim objShell,objDef,objDate,objVer,objRev,objOutFile,objFSO,objNDate

Set objExec = objShell.Exec(strCmdRun & strRegQ & "\\" & strcomputer & strRegKey & strCmdSw & strRegKey2)

strExecResults = LCase(objExec.StdOut.ReadAll)
objVer = Right(strExecResults,16)
objRev = Right(objVer,7)
objDate = Left(objVer,8)
objYear = Left(objDate,4)
objMonth = Mid(objDate,5,2)
objDay = Right(objDate,2)
objNDate = CDATE(objMonth &"/"&amp; objDay &"/"& objYear)


For Each objItem in colItems
If objItem.Description = "Symantec AntiVirus" Then
wscript.echo objItem.Description & " (v." & objItem.Version & ")"
End if
Next

wscript.echo vbCrLf &"Symantec AntiVirus definition date: " & objNDate &amp;" Rev. "& objRev

Monday, February 27, 2006

WMI: Get a list of installed applications

Have you ever needed to get a list of applications that are installed on a workstation? I can think of a number of situations where this might be useful… Maybe you’re trying to get an application count as part of a Software Asset Management (SAM) project, or maybe because you’ve been tasked with determining the popularity of something inside your organization, say RSS Bandit (keep in mind that this list only includes applications installed by the Windows Installer).

Personally, I’ll be adding this as a function to my inventory script - because right now, I need this list for an audit I'll be conducting at a customer site.

Let’s just quickly review how this works…

First we declare a string (strComputer), and assign a value to it (ComputerName). Next, we connect to the \root\cimv2 namespace, query the “Win32_Product” class, and get a collection of items (colItems). Finally, we loop though the collection and echo the objItem.Descriptions and objItem.Versions.


strComputer = "computerName"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Product")

For Each objItem in colItems
wscript.echo objItem.Description & " (v." & objItem.Version & ")"
Next


Friday, February 24, 2006

WMI: Using WMI to detect machines running under Microsoft Virtual Server 2005

There’s probably quite a few situations where it would be useful to be able to programmatically detect if a particular OS is running under Virtual Server/Virtual PC or not. In my case, I was working at a new customer site; the sysadmin responsible for the site was out of town/unreachable, there was no documentation, and the only thing I had to go on was that the OS I needed to look at was running under Virtual Server.

So in working on my inventory script, I remembered seeing that in the output, some of the machines on my network had a model type of “Virtual Machine”. When I originally saw this, I didn’t give too much thought to it, but now, being in a situation where it would come in handy, I was immediately reminded of how useful this is.

After skimming through the script for a bit, I found what I needed and saw how/why the detection was working. Specifically the Win32_ComputerSystem class, which the WMI SDK says “represents a computer operating system in a Windows environment.” Contains a string called “Model”, which is a “Product name that a manufacturer gives to a computer.” Apparently, when the machine is working under Virtual Server 2005 or Virtual PC, the reported model type is “Virtual Machine”.

Okay, so great. This was really convenient, and helped me to solve my problem. So posted below you’ll see some code to do the detection. Also, after I did this I realized that Ben, over at the “Virtual PC Guy’s WebLogalready posted a similar script. His works a bit differently, which I’ll explain… He uses the Win32_BaseBoard class – which we know “represents a baseboard, which is also known as a motherboard or system board". And we can see he is looking at objItem.Manufacturer – a string that, again according to the SDK, represents the “Name of the organization responsible for producing the physical element.” Which is just to say, that he’s getting “Microsoft Corporation” from it, and he knows that any motherboards called “Microsoft Corporation”, are going to be Virtual Machines.

So his script actually looks pretty similar to mine. The only notable different is that he’s talking to a different class. But it’s neat, and useful... and there’s always more than one way to skin a cat! Have fun.

strComputer = "computername"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)

For Each objItem in colItems
strModel = objItem.Model
If strModel = "Virtual Machine" Then
wscript.echo "This is a virtual machine!"
else
wscript.echo "This is NOT a Virtual Machine"
End if
Next

Saturday, February 18, 2006

WMI: Scripting DSQUERY to report FSMO roles using an Array

So while Friday's effort got the job done, Saturday's effort is a more compact and efficient way of doing the same thing using a 1-dimensional array. Instead of building each command separately, and then building the output, you can do all of that effort with one for-next loop. Granted, the display of the output could be improved a bit, but this will do nicely as a function in my inventory script. One thing you'll need to keep in mind is that when working with an array, you need to start counting at 0, such that "ArrFSMOCmds(4)" has 5 values (0,1,2,3,4).

Dim objShell, ArrFSMOCmds(4)
Set objShell = CreateObject("WScript.Shell")

Cmd1 = "cmd /c"
Cmd2 = "dsquery server -hasfsmo "
ArrFSMOCmds(0) = "schema"
ArrFSMOCmds(1) = "rid"
ArrFSMOCmds(2) = "name"
ArrFSMOCmds(3) = "infr"
ArrFSMOCmds(4) = "PDC"

For Each ArrFSMOCmds in ArrFSMOCmds
Set objExec = objShell.Exec(Cmd1 & Cmd2 & ArrFSMOCmds)
strExecResults = LCase(objExec.StdOut.ReadAll)
Wscript.Echo ArrFSMOCmds & ": " & strExecResults
Next

Friday, February 17, 2006

WMI: Scripting DSQUERY to report FSMO roles

This script executes a series of "dsquery" commands to determine which servers house the FSMO roles on your network. This will later be incorporated as a function into my inventory script.

Dim objShell
Set objShell = CreateObject("WScript.Shell")

strCmdRun = "cmd /c"
strQuery = "dsquery server -hasfsmo "
strQuerySchema = "schema"
strQueryRID = "rid"
strQueryName = "name"
strQueryInfr = "infr"
strQueryPDC = "PDC"

Set objExec = objShell.Exec(strCmdRun & strQuery & strQuerySchema)
strExecResultsSchema = LCase(objExec.StdOut.ReadAll)

Set objExec = objShell.Exec(strCmdRun & strQuery & strQueryRID)
strExecResultsRID = LCase(objExec.StdOut.ReadAll)

Set objExec = objShell.Exec(strCmdRun & strQuery & strQueryName)
strExecResultsName = LCase(objExec.StdOut.ReadAll)

Set objExec = objShell.Exec(strCmdRun & strQuery & strQueryInfr)
strExecResultsInfr = LCase(objExec.StdOut.ReadAll)

Set objExec = objShell.Exec(strCmdRun & strQuery & strQueryPDC)
strExecResultsInfr = LCase(objExec.StdOut.ReadAll)

Wscript.Echo "FSMO Roles: "
Wscript.Echo "-----------"
Wscript.Echo "Schema Master: " & strExecResultsSchema
Wscript.Echo " "
Wscript.Echo "RID Master: " & strExecResultsRID
Wscript.Echo " "
Wscript.Echo "Domain Naming Master: " & strExecResultsName
Wscript.Echo " "
Wscript.Echo "Infrastructure Role: " & strExecResultsInfr
Wscript.Echo " "
Wscript.Echo "PDC Emulator: " & strExecResultsInfr

Thursday, December 08, 2005

WMI: Changes to Workstation Inventory

Joe pointed out that in the workstation inventory script that I recently posted, it’s considerably more efficient to use objectCategory=’computer’ than objectClass. I made the recommended change, and sure enough, it worked, and worked more quickly. Thanks joe!

If you want to follow along, consider the following change…


"Select Name, Location from " & strLdapPath & " Where objectClass='computer'"

to

"Select Name, Location from " & strLdapPath & " Where objectCategory='computer'"


After I’ve completed some more work on the script, I’ll post the new version in it’s entirety, incorporating this update.

Tuesday, December 06, 2005

WMI: Active Directory Workstation inventory, version 2

I cleaned the original Active Directory workstation inventory script that I mentioned in last week’s post. Basically, I broke the logic out into functions, adding the free disk space check, and the Symantec antivirus definition date check, and made it a bit more readable and usable than the original script.

So how should you go about using this?


Well, first thing you’ll want to do is modify your LDAP path (search for the strLdapPath string) to make this work on your network. I have this commented, and it should be relatively self-explanatory.

The next thing you’ll want to do is consider if you should run the script. If you’ve got a larger environment (say hundreds or thousands of workstations) then it’s going to take quite a while to run. But on a small to mid-sized network, this shouldn’t be too bad.

What do I type to make this work?

So you copy and paste the below code into a text editor, and save it with a .VBS extension. Then, you make sure you’re either logged in as a domain admin, or that you’re executing this script under the context of a domain admin account, you then modify the LDAP path, drop to the command line, and use the following command:

“cscript scriptname.vbs >inventoryreport.txt”

This is going to iterate though all of the computer objects in active directory, ping them to determine if they’re on, and then do some work. Which after hitting all of the objects will leave you with a text file that contains all of your workstation names, their operating system versions, service pack levels, installation dates, computer manufacturer, bios revisions, service tags, processor types, currently logged-on user, model number, amount of ram, daylight savings zone, Symantec antivirus definition dates, and the amount of available free disk space.

Why is it just sitting here doing nothing?

It’s probably doing work. If you’d rather see the results echoed to the screen, then just get rid of the redirection, using the following command line “cscript scriptname.vbs”.

How is this useful?

Well, if you’re an administrator on a small to midsized network, this is a really handy inventory tool that can be used quickly and with very limited editing on your internal and/or customer networks. As a result, it’s cost effective, and you can audit or spot-check your clients. Secondly, if you take a look at a recent post of Susan Bradley, you’ll see this automates a bit of what new SBS net-admins need to for health-check and monitoring type of functions.

I plan to follow-up this post with some more specifics as to how I’m using on the SMB side of the business, and also start thinking about ways I can improve this (think Exchange database sizes) or to make it scale well for larger environments.


'AD Workstation Inventory version 2
'by Nick, wmi.wmi@gmail.com, http://addicted-to-it.blogspot.com
Dim objShell,objDef,objDate,objVer,objRev,objOutFile,objFSO,objNDate,objToday
Const MegabyteConversion = 1048576
Const Warning_Threshold = 1000

'=================================================
'Set the LDAP path to your Active Directory
'=================================================
strLdapPath = "'LDAP://DC=domain,DC=local'"
wscript.echo strLdapPath
'=================================================

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.CommandText = _
"Select Name, Location from " & strLdapPath & " Where objectClass='computer'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst

Do Until objRecordSet.EOF

strComputer = objRecordSet.Fields("Name").Value

Set objShell = CreateObject("WScript.Shell")
strCommand = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
Set objExecObject = objShell.Exec(strCommand)

'clears echo replies left in strText from the previous loop
strText=""


Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadAll()
If Instr(strText, "Reply") > 0 Then


Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2")

'=================================================
'The following functions produce the reports
'=================================================

If Err.Number > 0 then
strErrorSystems = strComputer & ", " & strErrorSystems
else
BuildHeader
OperatingSystem
BiosQuery
ProcQuery(strComputer)
DayLightSavingsEffect(strComputer)
SavDate(strComputer)
Diskspace
BuildFooter

end if


'flushes error code from the previous loop
Err.Clear


Else
'
UnavailableSystems = strComputer & ", " & UnavailableSystems

End If
Loop


objRecordSet.MoveNext
Loop

Wscript.Echo "The following systems were unavailable: " & UnavailableSystems
Wscript.Echo " "
Wscript.Echo "The following systems were on, but returned an error: " & strErrorSystems

Function BuildHeader
Wscript.Echo "-------------------------------------------------------------"
Wscript.Echo "Computer Name: " & strComputer
Wscript.Echo "-------------------------------------------------------------"
End Function

Function OperatingSystem
Set colItems = objWMIService.ExecQuery ("Select * From Win32_OperatingSystem")
For Each objItem in ColItems
strOs = objItem.Caption
strServPack = objItem.CSDVersion
strInstallDate = objItem.InstallDate
Next
Wscript.Echo "Operating System: " & strOs
Wscript.Echo "Service Pack: " & strServPack
Wscript.Echo "Install Date: " & WMIDateStringToDate(strInstallDate)

End Function



Function BiosQuery
Set colItems2 = objWMIService.ExecQuery("Select * from Win32_BIOS",,48)
For Each objItem in colItems2
strDellTag = objItem.SerialNumber
strManu = objItem.Manufacturer
strBiosName = objitem.Name
Next
WScript.Echo "Manufacturer: " & strManu
Wscript.Echo "BIOS Name: " & strBiosName
Wscript.Echo "Dell Service Tag: " & strDellTag
End Function

Function WMIDateStringToDate(dtmDate)
WScript.Echo dtm:
WMIDateStringToDate = CDate(Mid(dtmDate, 5, 2) &amp;amp;amp;amp;amp; "/" & _
Mid(dtmDate, 7, 2) & "/" & Left(dtmDate, 4) _
& " " & Mid (dtmDate, 9, 2) & ":" & Mid(dtmDate, 11, 2) & ":" & Mid(dtmDate,13, 2))
End Function


Function ProcQuery(shost)
Set colItems4 = objWMIService.ExecQuery("SELECT * FROM Win32_Processor", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem in colitems4
strProcessor = objItem.Name
Next
Wscript.Echo "Processor type: " & strProcessor

End Function



Function DayLightSavingsEffect(shost)
Set colItems3 = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
For Each objItem in colitems3
strUserName = objItem.Username
strModel = objItem.Model
strRAM = objItem.TotalPhysicalMemory
strTimeZone = (objItem.CurrentTimeZone / 60)
strDayLightSavings = objItem.DaylightInEffect
Next

Wscript.Echo "Current User: " & strUsername
Wscript.Echo "Model: " & strModel
Wscript.Echo "RAM: " & strRAM
Wscript.Echo "Daylight Savings in effect: " & strDayLIghtSavings
Wscript.Echo "Time Zone: " & strTimeZone
strUsername = ""
End Function



Function SavDate(shost)
strCmdRun = "cmd /c"
strRegQ = "reg query "
strRegKey = "\HKLM\SOFTWARE\Symantec\SharedDefs\"
strCmdSw = " /v "
strRegKey2 = "DEFWATCH_10"
Set objExec = objShell.Exec(strCmdRun & strRegQ & "\\" & shost & strRegKey & strCmdSw & strRegKey2)
strExecResults = LCase(objExec.StdOut.ReadAll)

objVer = Right(strExecResults,16)
objRev = Right(objVer,7)
objDate = Left(objVer,8)
objYear = Left(objDate,4)
objMonth = Mid(objDate,5,2)
objDay = Right(objDate,2)
objNDate = CDATE(objMonth &amp;amp;amp;amp;amp;"/"& objDay &"/"& objYear)
Wscript.Echo "Symantec Antivirus Definition Date: " &amp;amp;amp;amp;amp; objNDate &" Rev. "& objRev & " "

End Function



Function DiskSpace
Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
If colLogicalDisk.Count = 0 Then
Wscript.Echo "No drives exist on this computer."
Else
For Each objLogicalDisk in colLogicalDisk
FreeMegaBytes = objLogicalDisk.Freespace / MegabyteConversion

'If objLogicalDisk.DriveType = 3 Then
'If FreeMegaBytes <> 0 Then
FreeMegaBytes_String = Int(FreeMegaBytes) & " MB Free"
Wscript.Echo objLogicalDisk.DeviceID & ", " & FreeMegaBytes_String & ", " &

objLogicalDisk.Description
End if

'End If
'End If
Next
End if
End Function

Function BuildFooter
Wscript.Echo "-------------------------------------------------------------"
End Function

Wednesday, November 30, 2005

WMI: Free disk space check

I was going though some of my scripts, and came across one that I need to add to my computer inventory script as a function. What it does is report the amount of free disk space on the machine's partitions. As I go through and update the inventory script, breaking code out into functions, I plan to add this.


Const MegabyteConversion = 1048576
Set objWMIService = GetObject("winmgmts:")

'Set objLogicalDisk = objWMIService.Get("Win32_LogicalDisk.DeviceID='c:'")

Set colLogicalDisk = objWMIService.InstancesOf("Win32_LogicalDisk")
If colLogicalDisk.Count = 0 Then
Wscript.Echo "No drives exist on this computer."
Else
For Each objLogicalDisk in colLogicalDisk
FreeMegaBytes = objLogicalDisk.Freespace / MegabyteConversion
FreeMegaBytes_String = Int(FreeMegaBytes) & " MB Free"
Wscript.Echo objLogicalDisk.DeviceID & " " & FreeMegaBytes_String
Next
End If


Friday, November 25, 2005

WMI: Checking Symantec Antivirus definition dates on workstations via a WMI script

Have you ever wanted to be able to check Symantec antivirus definition dates on workstations via WMI, but weren’t sure exactly how to find the date? Well wonder no more, as you can find the date and revision in the following registry location.

HKLM\SOFTWARE\Symantec\SharedDefs\DEFWATCH_10
The value data is in a string that looks like this: “20051123.019” [YearMonthDay.Revision].

With that piece of information, you’re just a few steps from automating this effort.

So the first thing I did was start playing with the “reg query” command under Windows XP/2003. What’s nice about this is that it’s very easy to grab stuff out of remote registries using the tool; just specify the machine name like so:

“reg query \\workstationname\HKLM\SOFTWARE\Symantec\SharedDefs\ /v DEFWATCH_10"”

Go ahead and run this on your machine. Doing so will produce string that you can use (making sure to specify your workstation name where it says “workstationname”).

After you have this, you can load the results into a string, and then use your “Right/Left/Mid” functions to massage the date into something presentable. Just copy and paste the below code into a text file, and save it with a “.vbs” extension.

Oh, wait… you wanted to do this to multiple workstations? Or say, maybe every computer object in Active Directory?

Not a problem. With the code I have on this page, you can copy and paste it directly into my inventory script, and be off and running. Just make sure you put the “Wscript.Echo” line down in the reporting section of the original script.

Let me know what you think.


Set objShell = CreateObject("Wscript.Shell")

strCmdRun = "cmd /c"
strRegQ = "reg query "
strComputer = "workstationname"
strRegKey = "\HKLM\SOFTWARE\Symantec\SharedDefs\"
strCmdSw = " /v "
strRegKey2 = "DEFWATCH_10"

Dim objShell,objDef,objDate,objVer,objRev,objOutFile,objFSO,objNDate

Set objExec = objShell.Exec(strCmdRun & strRegQ & "\\" & strcomputer & strRegKey & strCmdSw & strRegKey2)

strExecResults = LCase(objExec.StdOut.ReadAll)

objVer = Right(strExecResults,16)
objRev = Right(objVer,7)
objDate = Left(objVer,8)
objYear = Left(objDate,4)
objMonth = Mid(objDate,5,2)
objDay = Right(objDate,2)
objNDate = CDATE(objMonth &"/"& objDay &"/"& objYear)

wscript.echo vbCrLf &"Symantec AntiVirus definition date: " & objNDate &" Rev. "& objRev

Tuesday, November 15, 2005

WMI: Killing processes

Need to kill a process using WMI? Maybe outlook.exe isn't shutting down properly... maybe it hangs in taskmanager... maybe you're tired of fighting it on your workstation, and don't have a few spare hours RIGHT NOW to re-image your system. If any of the above apply, check out the below script.


Option Explicit
Dim objWMIService, objProcess, colProcess
Dim strComputer, strProcessKill

strComputer = "."
strProcessKill = "'outlook.exe'"

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

Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strProcessKill )
For Each objProcess in colProcess
objProcess.Terminate()
Next

WSCript.Echo "Outlook cleanup process complete, please reopen Outlook."
WScript.Quit

Wednesday, September 07, 2005

WMI: Step 2, Gathering a computer inventory of available systems from Active Directory

As I started to add features to my previous script, I realized that it got a little buggy when more than a couple of machines were going to be queried. And it was pretty obvious that it lacked any error handling. So with these things in mind, I decided to start over.

Being able to find service tags is convenient and all, but what I really wanted to do was get a quick inventory of the workstations connected to my LAN, gathering a wish-list of such items as: machine names with logged-on users, manufacturer names, model numbers, service tags, processor speeds, ram quantities, time zone settings, and daylight savings information.

Most importantly, I wanted this to be reasonably portable. I didn’t want to have to jump though hoops to get this to work at a different customer site… no creating a text file with all of the machine names in it, or having to export computer names to a CSV file … basically I wanted to minimize the amount of prep work needed, so that someone could “hit-the-ground-running” with the least amount of effort. Oh, and let’s not forget adding a little error handling…

I had an existing script that did some work against objects in an OU, so I could have probably used that as a starting point. But in order to really meet the error handling requirements, I decided to use a ping test against computer objects in active directory to determine if a machine was powered-up or not. The Microsoft Script Center has a scriptomatic) that I’ll need to meet my objectives. Then I added my for-next loops which actually load the items that I’m interested in, into string variables (e.g. strOS, strManu, etc), doing work where appropriate to make the output readable. Finally, I use wscript.echo commands to echo the reported data to the screen. Also, at the beginning of my main do-loop you’ll notice the If-Then statement that basically says…"If I get a ping response do this, else do this”… it’s that other else that does my error handling. So if a machine isn’t on, I add each machine to a string that will get echo’d at the end.

Check it out. And if you have any questions, comments, etc... post them in the comment section!

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.CommandText = _
"Select Name, Location from 'LDAP://DC=domainname,DC=local' " _
& "Where objectClass='computer'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst

Do Until objRecordSet.EOF
strComputer = objRecordSet.Fields("Name").Value

Set objShell = CreateObject("WScript.Shell")
strCommand = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
Set objExecObject = objShell.Exec(strCommand)

'clears echo replies left in strText from the previous loop
strText=""
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadAll()
If Instr(strText, "Reply") > 0 Then
Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery _
("Select * From Win32_OperatingSystem")
Set colItems2 = objWMIService.ExecQuery("Select * from Win32_BIOS",,48)
' Wscript.Echo Err.Description
Set colItems3 = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
Set colItems4 = objWMIService.ExecQuery("SELECT * FROM Win32_Processor", "WQL", _
wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objItem in ColItems
strOS = objItem.Caption
Next

For Each objItem in colItems2
strDellTag = objItem.SerialNumber
strManu = objItem.Manufacturer
Next

For Each objItem in colitems3
strUserName = objItem.Username
strModel = objItem.Model
strRAM = objItem.TotalPhysicalMemory
strTimeZone = (objItem.CurrentTimeZone / 60)
strDayLightSavings = objItem.DaylightInEffect
Next

For Each objItem in colitems4
strProcessor = objItem.Name
Next
If Err.Number > 0 then
strErrorSystems = strComputer & ", " & strErrorSystems
else
Wscript.Echo "Computer Name: " & strComputer
Wscript.Echo "Operating System: " & strOS
Wscript.Echo "Current User: " & strUserName
WScript.Echo "Manufacturer: " & strManu
Wscript.Echo "Model: " & strModel
Wscript.Echo "Dell Service Tag: " & strDellTag
Wscript.Echo "Processor type: " & strProcessor
Wscript.Echo "RAM: " & strRAM
Wscript.Echo "Time Zone: " & strTimeZone
Wscript.Echo "Daylight Savings in effect: " & strDayLIghtSavings
Wscript.Echo " "
end if
'flushes error code from the previous loop
Err.Clear
Else
UnavailableSystems = strComputer & ", " & UnavailableSystems
End If
Loop
objRecordSet.MoveNext
Loop
Wscript.Echo "The following systems were unavailable: " & UnavailableSystems
Wscript.Echo " "
Wscript.Echo "The following systems were on, but returned an error: " & strErrorSystems

Wednesday, August 24, 2005

WMI: Getting started with WMI

Wondering how I figured out how to retrieve the Dell express service tag information? It’s actually pretty easy. First, grab a copy of Microsoft’s “ScriptomaticV2.hta” tool; download it, and bring up the interface. On opening, it automatically loads the “root\CIMV2” namespace, which contains all of the WMI classes that you’re going to want to query.

Next, I opened the WMI Class drop down box and poked around a bit… working under the assumption that any Dell-specific information is going to be hidden inside the “Win32_BIOS” class. Next, I ran the automatic script that Scriptomatic generated, and skimmed the output looking for a 7-digit express service tag number. Sure enough, “objItem.SerialNumber” pulls out the information I wanted.

Finally, I grabbed a copy of another script I had written to take command-line arguments, replacing what I had been using to some other work, with a Wscript.echo command for objItem.SerialNumber.

Between having a few scripts on hand that already do some useful stuff, and tools like Scriptomatic, you can really build some powerful little scripts that can have an immediate impact, without hours and hours worth of effort. Granted, this is a pretty basic script, but I can’t tell you how often it comes in handy.