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

Tuesday, July 31, 2012

File Search using WMI CIM_DataFile with VBScript

I looked around, but didn't find a script example that did exactly what I wanted, but I ran across several good alternatives. One thing I found was that if I don't specify the drive letter, it takes WAAAAAAAYYYYY longer to execute. Just a tip. In any case, I hope this helps someone out there...

'****************************************************************
' Filename..: fileSearch.vbs
' Author....: ScriptZilla / SkatterBrainz / Dave
' Date......: 07/30/2012
' Purpose...: search for files using WMI/CIM_DataFile
'****************************************************************
time1 = Timer

'----------------------------------------------------------------
' comment: search parameters
'----------------------------------------------------------------

strFileExt  = "syn"
strFileName = "*"
strDriveLtr = "c:"
strComputer = "."

'----------------------------------------------------------------
' function: 
'----------------------------------------------------------------

Function StringDate(dv)
 Dim xdy, xdm, xdd, xdh, xdn, tmp
 ' example: 20120729195837.171181-240
 xdy = Mid(dv,1,4) ' year
 xdm = Mid(dv,5,2) ' month
 xdd = Mid(dv,7,2) ' day
 xdh = Mid(dv,9,2) ' hour
 xdn = Mid(dv,11,2) ' minute
 tmp = xdm & "/" & xdd & "/" & xdy & " " & xdh & ":" & xdn
 StringDate = FormatDateTime(tmp, vbShortDate) & " " & _
  FormatDateTime(tmp, vbLongTime)
End Function

'----------------------------------------------------------------
' comment: main script code begins
'----------------------------------------------------------------

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

If strFileName = "*" Then
 query = "Select * from CIM_DataFile Where Drive='" & strDriveLtr & "'" & _
  " AND Extension='" & strFileExt & "'"
Else
 query = "Select * from CIM_DataFile Where Drive='" & strDriveLtr & "'" & _
  " AND FileName = '" & strFileName & "'" & _
  " AND Extension='" & strFileExt & "'"
End If

wscript.echo "info: search criteria = " & strFileName & "." & strFileExt & " on " & strDriveLtr
Set colFiles = objWMIService.ExecQuery(query)

wscript.echo "info: beginning search..."

counter = 0
For Each objFile in colFiles
 counter = counter + 1
    wscript.echo objFile.Drive & objFile.Path & _
     objFile.FileName & "." & objFile.Extension & _
     vbTab & StringDate(objFile.CreationDate) & _
     vbTab & StringDate(objFile.LastModified) & _
     vbTab & objFile.FileSize
Next

wscript.echo "info: " & counter & " matching files found"
wscript.echo "info: " & Timer - time1 & " seconds"

Thursday, October 20, 2011

Query Installed Apps a Different Way

For whatever reason, in some environments, a WMI query of Win32_Product is God-awful slow.  I've seen this on Windows 7 and Windows 7 SP1 clients, as well as on Windows Server 2008 and 2008 R2.  The symptom can be seen from WIM script, WBEM, and using WMIC from a command console with very similar results:  The query hangs for 20-25 seconds and then begins executing in spurts.  Other Win32 classes work fine, from what I've seen, it's just Win32_Product for some reason.  One workaround is to dump a registry output file, and scrub it to make a "clean" output file.  You can port this to PowerShell or KiXtart if you want (or whatever you prefer, I really don't care as long as you're happy and that makes me happy so we're all happy. yay!)

'****************************************************************
' Filename..: installedApps.vbs
' Author....: David M. Stein aka Scriptzilla aka dipshit
' Date......: 10/20/2011
' Purpose...: save query of installed applications to local file
'****************************************************************

Const strInputFile  = "c:\regoutput.txt"
Const strOutputFile = "c:\installedApps.txt"

Const ForReading = 1
Const ForWriting = 2
Const adVarChar = 200

cmd = "reg query hklm\software\microsoft\windows\currentversion\uninstall /s >" & strInputFile

On Error Resume Next

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

wscript.echo "info: executing shell command to create temp file..."

objShell.Run "cmd /c " & cmd, 7, True

wscript.echo "info: getting temp file for input..."

If objFSO.FileExists(strInputFile) Then
 wscript.echo "info: reading temp file..."
 Set objFile = objFSO.OpenTextFile(strInputFile, ForReading)
 Set objFile2 = objFSO.CreateTextFile(strOutputFile, True)

 Set rs = CreateObject("ADODB.RecordSet")

 rs.CursorLocation = adUseClient
 rs.Fields.Append "productname", adVarChar, 255
 rs.Open

 Do Until objFile.AtEndOfStream
     strLine = objFile.Readline
     If Left(strLine, 25) = "    DisplayName    REG_SZ" Then
      strOutput = Trim(Mid(strLine, 30))
   rs.AddNew
   rs.Fields("productname").value = strOutput
   rs.Update
     End If
 Loop
 
 rs.Sort = "productname"
 
 Do Until rs.EOF
     objFile2.WriteLine(rs.Fields("productname").value)
  rs.MoveNext
 Loop
 rs.CLose
 Set rs = Nothing
 
 objFile.Close
 objFile2.Close
 wscript.echo "info: finished scrubbing input to new output file"
Else
 wscript.echo "fail: temp file not found"
End If

Set objFSO = Nothing
Set objShell = Nothing
'----------------------------------------------------------------

wscript.echo "info: processing complete!"

Wednesday, October 27, 2010

A WMI Search-Filter Thingy Script Thingy

I worked on this for a couple of hours. It could use a lot more work and embellishment (such as specifying the namespaces in the data file, etc.), but here goes. It reads a text file to scan the local computer for matching WMI class properties (currently only within the CIMv2 namespace). I hope it helps someone. Enjoy!
'****************************************************************
' Filename..: wmi_rule.vbs
' Author....: Scriptzilla / skatterbrainz.blogspot.com
' Date......: 10/27/2010
' Purpose...: evaluate wmi class property value matches using data file
'****************************************************************

scriptPath = Replace(wscript.ScriptFullName, "\" & wscript.ScriptName, "")

ruleFile = scriptPath & "\wmi_rules.txt"
Const ForReading = 1
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
Set objFile = objFSO.OpenTextFile(ruleFile, ForReading)
If err.Number = 0 Then
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)
If strLine <> "" And Left(strLine,1) <> "'" And Left(strLine,1) <> ";" Then
arrRule = Split(strLine, ",")
For each item in arrRule
arrPair = Split(item, "=")
Select Case arrPair(0)
Case "Class": wmi_class = arrPair(1)
Case "Property": wmi_prop = arrPair(1)
Case "Value": wmi_val = arrPair(1)
Case "MatchType": wmi_match = arrPair(1)
End Select
Next

If WMIRule(wmi_class, wmi_prop, wmi_val, wmi_match) = True Then
wscript.echo "class....... " & wmi_class
wscript.echo "property.... " & wmi_prop
wscript.echo "value....... " & wmi_val
wscript.echo "matchtype... " & wmi_match
wscript.echo "result ----> TRUE"
wscript.echo
Else
wscript.echo "class....... " & wmi_class
wscript.echo "property.... " & wmi_prop
wscript.echo "value....... " & wmi_val
wscript.echo "matchtype... " & wmi_match
wscript.echo "result ----> FALSE"
wscript.echo
End If
End If
Loop
objFile.Close
Else
wscript.echo "fail: unable to open rule file for input"
End If
Set objFSO = Nothing

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

Function WMIRule(w_class, w_prop, w_val, w_match)
Dim objClass, objProp, strName, strValue, retval
Dim objWMIService, wmiQuery, colItems, objItem

strComputer = "."
Set objWMIService = objWMI(strComputer, "classes")

wmiQuery = "select * from " & w_class

Set colItems = objWMI(strComputer, wmiQuery)

For each objItem in colItems
For Each objProp In objItem.Properties_
strName = objProp.Name
If Ucase(strName) = Ucase(w_prop) Then
'wscript.echo vbTab & "property --> " & w_prop
If IsArray(objProp.Value) Then
strValue = Join(objProp.Value, ";")
Else
strValue = Trim(objProp.Value)
End If
End If
Next

If strValue <> "" And Not IsNull(strValue) Then
If w_match = "EQUAL" Then
If strValue = w_val Then
retval = True
End If
Else
If InStr(strValue, w_val) > 0 Then
retval = True
End If
End If
End If
Next
WMIRule = retval
End Function


Function objWMI(strComputer, strWQL)
'On Error Resume Next
Dim wmiNS, objWMIService, objSWbemLocator, objSWbemServices
Dim strUID, strPwd

wmiNS = "\root\cimv2"
strUID = ""
strPwd = ""

Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")

On Error Resume Next

Set objSWbemServices = objSWbemLocator.ConnectServer(strComputer, wmiNS, strUID, strPwd)

Select Case Err.Number
Case -2147024891:
wscript.echo "error: access denied!"
Exit Function
End Select

On Error GoTo 0

Select Case UCase(strWQL)
Case "CLASSES":
Set objWMI = objSWbemServices
Case Else:
Set objWMI = objSWbemServices.ExecQuery(strWQL)
End Select

Set objSWbemServices = Nothing
Set objSWbemLocator = Nothing
End Function

And here is the data "rules" file that spells out the class properties to search...

'------------------------------------------------------------------------------
' wmi_rules.txt
'------------------------------------------------------------------------------
' each row denotes a rule to be tested within root\cimv2 namespace (for now)
' each row contains the WMI: class, property, value, and matchtype
' class = win32 class name
' property = the name of a given class property
' value = the value you wish to test for
' matchtype = EQUAL or LIKE
'------------------------------------------------------------------------------
Class=win32_ComputerSystem,Property=Model,Value=dc7900,MatchType=LIKE
Class=win32_OperatingSystem,Property=Caption,Value=Microsoft Windows 7 Enterprise,MatchType=LIKE
Class=win32_OperatingSystem,Property=OSArchitecture,Value=64-bit,MatchType=EQUAL
Class=win32_Service,Property=Name,Value=VMAuthdService,MatchType=EQUAL

Thursday, March 18, 2010

Query Scheduled Tasks The Hard Way

Because the CIM/WMI model is still an unfinished work in progress, I’ve once again had to resort to making some ugly crap code to work around a giant hole in the model. In this case it’s the lack of a model counterpart to the Scheduled Tasks collection.  This is NOT the same as the Win32_ScheduledJobs or the AT command output.  I’m talking about SCHTASKS.exe and the Windows Scheduled Tasks utility.  Anyhow, the klunky workaround here is to ride the SCHTASKS command like a whipping boy and make it dump a text file, then turn around and do a crude (but effective) string parsing and crank it out in XML form.  Enjoy.
'****************************************************************
' Filename..: xml_scheduled_tasks.vbs
' Author....: David M. Stein
' Date......: 03/18/2010
' Purpose...: query Scheduled Tasks (not WMI/Jobs/AT) --> XML out
'****************************************************************

Const tempfile = "c:\temp\schtasks.txt"
Const computer = ""

Const ForReading = 1
Const ForWriting = 2

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

If computer <> "" Then
cmdstr = "cmd /c schtasks /query /s \\" & computer & " /v /fo list >" & tempfile
Else
cmdstr = "cmd /c schtasks /query /v /fo list >" & tempfile
End If

retval = objShell.Run(cmdstr, 1, True)

If objFSO.FileExists(tempfile) Then
Dim linecount, objFSO, objFile, ln, strLine

linecount = 0
wscript.echo ""

Set objFile = objFSO.OpenTextFile(tempfile, ForReading)
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)

If Left(strLine, 9) = "HostName:" Then
hostname = Mid(strLine, 39)
wscript.echo vbTab & ""

ElseIf Left(strLine, 9) = "TaskName:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""
wscript.echo vbTab & vbTab & "" & hostname & ""

ElseIf Left(strLine, 15) = "Scheduled Type:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 9) = "Schedule:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Task To Run:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 8) = "Comment:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 12) = "Run As User:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Time:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 11) = "Start Date:" Then
wscript.echo vbTab & vbTab & "" & Mid(strLine, 39) & ""

ElseIf Left(strLine, 17) = "Power Management:" Then
wscript.echo vbTab & "
"

End If
linecount = linecount + 1

Loop
objFile.Close
Set objFSO = Nothing

wscript.echo "
"

Else
wscript.echo "fail: file not found"
End If

Saturday, November 14, 2009

Restarting a Remote Service (VBScript vs PowerShell)

This kind of goes along with my rants about PowerShell examples being pretty much reformatted VBScript WMI code examples, but regardless, PowerShell does provide a more abbreviated code environment.  The PowerShell code example was derived from a posting by Thomas Lee on the PowerShell blog on restarting a DNS service on a remote computer.  I had a VBScript example which does the same with the Spooler service, so I simply adapted Thomas’ code to support and apples-to-apples comparison.  As you can see, they are very similar.  In fact, the KiXtart version looks almost identical to both as well.

VBScript Example

strComputer = "server1" 
wscript.echo "Restarting Spooler Service on: ",strComputer

Set wmi = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set ret = wmi.ExecMethod("Win32_Service.Name='Spooler'", "StopService")
If ret.ReturnValue = 0 Then
wscript.echo "Spooler Service stopped"
Else
wscript.echo "Spooler Service not stopped"
End If

Set ret = wmi.ExecMethod("Win32_Service.Name='Spooler '", "StartService")
If ret.ReturnValue = 0 Then
wscript.echo "Spooler Service started"
Else
wscript.echo "Spooler Service not started"
End If


PowerShell Example



$strComputer = "server1" 
"Restarting Spooler Service on: $strComputer"

# get the service object
$svc = gwmi Win32_Service -computer $strComputer | where {$_.name -eq "Spooler"}

# stop the service
$ret = $svc.StopService()
if ($ret.ReturnValue -eq 0) {"Spooler Service stopped"}
else {"Spooler Service not stopped"}

# start the service
$ret = $svc.StartService()
if ($ret.ReturnValue -eq 0) {"Spooler Service started"}
else {"Spooler Service not started"}

Sunday, November 1, 2009

Am I a VMWare Guest Machine or Not?

VBScript Version
Function IsVmWareClient()
Dim objWMIService, colBIOS, objBIOS, retval
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colBIOS = objWMIService.ExecQuery("Select SerialNumber from Win32_BIOS")
For each objBIOS in colBIOS
If Left(objBIOS.SerialNumber, 6) = "VMware" Then
retval = True
Exit For
End If
Next
IsVmWareClient = retval
End Function

' test

If IsVmWareClient() Then
wscript.echo "yes - this is a vmware guest machine"
Else
wscript.echo "not a vmware guest machine"
End If

KiXtart Version

Function IsVmWareClient()
Dim $wmiService, $colBIOS, $objBIOS, $retval
$wmiService = GetObject("winmgmts:\\.\root\CIMV2")
$colBIOS = $wmiService.ExecQuery("select SerialNumber from Win32_BIOS")
For Each $objBIOS in $colBIOS
If Left($objBIOS.SerialNumber, 6) = "VMware"
$retval = 1
EndIf
Next
$IsVmWareClient = $retval
EndFunction

; test

If IsVmWareClient()
? "yes - this is a vmware guest machine"
Else
? "not a vmware guest machine"
EndIf

Sunday, October 11, 2009

Reboot Computers by Operating System

What if you wanted to reboot every computer in your Active Directory domain that has a specific version of Windows installed?  One example is requesting every Windows 7 Ultimate computer to reboot (see below).  Just replace the “YOUR-DOMAIN” with your actual NetBIOS domain name and change the operating system string to whatever you prefer.  Remember to test in an isolated environment.

Set objDomain = GetObject("WinNT://YOUR-DOMAIN")

For each objX in objDomain
If Lcase(objX.Class) = "computer" Then
n = objX.Name
wscript.echo n
End If
Next

Sub Reboot(strComputer)
Dim objWMIService, colOS, objShare, objRetval, cap
On Error Resume Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
If err.Number <> 0 Then
wscript.echo "unavailable: " & strComputer
Else
Set colOS = objWMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem",,48)
For each objItem in colOS
cap = objItem.Caption
If cap = "Microsoft Windows 7 Ultimate" Then
Set objShare = objWMIService.Get("Win32_OperatingSystem.ReplaceKeyProperty=ReplacePropertyValue")
Set objRetval = objWMIService.ExecMethod("Win32_OperatingSystem.ReplaceKeyProperty=ReplacePropertyValue", "Reboot")
End If
Next
End If
End Sub

Saturday, October 3, 2009

VBScript - Get Remote Asset Tag (Serial Number)

Function AssetNumber(strComputer)
    Dim objWmi, objWmiCS, obj, retval
    On Error Resume Next
    Set objWmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
        strComputer & "\root\cimv2")
    If err.Number <> 0 Then
        wscript.echo "error: " & err.Number & " / " & err.Description
        err.Clear
        Set objWMI = Nothing
        retval = "*** unavailable ***"
    Else
        Set objWmiCS = objWmi.ExecQuery("select * from Win32_ComputerSystemProduct")
        For Each obj in objWmiCS
            retval = obj.IdentifyingNumber
        Next
        Set objWmiCS = Nothing
        Set objWMI = Nothing
    End If
    AssetNumber = retval
End Function

wscript.echo AssetNumber("holland")

Tuesday, September 22, 2009

Windows Defrag From a Script to a Script and Back Again

Sometimes you just have to unscrew your brain, take it out, set it down on the toilet lid and say “what the hell”.  Let’s just say, let’s… that we want to run the DEFRAG command using the /A option to just analyze a volume and somehow we’d like to be able to programmatically (that’s a big word) capture that output and automate something with that mess.  Let’s just say.

The command line might look like defrag c: /a /v >defrag.txt.  But we’d like to be able to schedule this to run at a certain after-hours time and maybe do something like send an email if the results meet some weird crack-infested condition we dreamed up while eating shrimp cocktail and downing four or five cold ones.

The output of this command might look like this…

Microsoft Disk Defragmenter
Copyright (c) 2007 Microsoft Corp.

Invoking analysis on (C:)...

The operation completed successfully.

Post Defragmentation Report:

Volume Information:
Volume size = 74.40 GB
Cluster size = 4 KB
Used space = 24.78 GB
Free space = 49.61 GB

Fragmentation:
Total fragmented space = 2%
Average fragments per file = 1.08

Movable files and folders = 75092
Unmovable files and folders = 45

Files:
Fragmented files = 2197
Total file fragments = 4809

Folders:
Total folders = 15288
Fragmented folders = 14
Total folder fragments = 43

Free space:
Free space count = 1805
Average free space size = 28.14 MB
Largest free space size = 30.62 GB

Master File Table (MFT):
MFT size = 76.50 MB
MFT record count = 78335
MFT usage = 100%
Total MFT fragments = 2

Note: File fragments larger than 64MB are not included in the fragmentation statistics.

You do not need to defragment this volume.


So, how can we do this automation gyration prognostication?  Easy.  Using VBScript, FileSystemObject, the Shell object and some coffee, duct tape and a slice of cold pizza, we might arrive at this…



Const inputFile = "c:\windows\temp\defrag.txt"
Const cmd = "cmd /c defrag c: /a /v"
Const ForReading = 1
Const ForWriting = 2

Dim objFSO, objFile, strLine, objShell, parse
Dim label, data

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

wscript.echo "info: running defrag analysis on c: drive..."
objShell.Run cmd & " >" & inputFile, 1, True
wscript.echo "info: defrag completed"

wscript.echo "info: checking if input file was created..."

If objFSO.FileExists(inputFile) Then
wscript.echo "info: file was found, opening for input..."
Set objFile = objFSO.OpenTextFile(inputFile, ForReading)
Do Until objFile.AtEndOfStream
strLine = Trim(objFile.Readline)
If InStr(1, strLine, "=") <> 0 Then
strLine = Replace(strLine, vbTab, "")
parse = Split(strLine, "=")
label = Trim(parse(0))
data = Trim(parse(1))
wscript.echo label & vbTab & data
End If
Loop
objFile.Close
Else
wscript.echo "fail: input file not found"
End If

Set objFSO = Nothing
Set objShell = Nothing

wscript.echo "info: processing complete"


The output might look like this…



info: running defrag analysis on c: drive...
info: defrag completed
info: checking if input file was created...
info: file was found, opening for input...
Volume size 74.40 GB
Cluster size 4 KB
Used space 24.78 GB
Free space 49.61 GB
Total fragmented space 2%
Average fragments per file 1.08
Movable files and folders 75096
Unmovable files and folders 43
Fragmented files 2197
Total file fragments 4810
Total folders 15288
Fragmented folders 14
Total folder fragments 43
Free space count 1802
Average free space size 28.19 MB
Largest free space size 30.62 GB
MFT size 76.50 MB
MFT record count 78335
MFT usage 100%
Total MFT fragments 2
info: processing complete


Now you can insert some code to send email using CDOsys (or whatever you prefer) or send some info to a database table.  Then wrap all that up with a tuna sandwich, some fries and a cold drink and you’re off.  Sure, you can do a lot of this with WMI directly and that works too.  But sometimes there are command console utilities that do things WMI doesn’t do as easily (or simply), so you have options like this (capture the output and then parse back into your script to process further).



Options: You can modify this easily to output XML, INI or just about any text format you desire.  You can also pipe it into another script, or pump it into a database.  You can also wrap it into an email and send it.  Or, because you can capture each line and check the “label” string value, you can check for “Total fragmented space” and if it’s greater than some percentage value, fire an email alert.  The take away here is that you can do just about anything you want.

Saturday, July 11, 2009

KiXtart: Get Asset Number

WMI query for asset number (e.g. Dell Asset, HP Serial number, etc.)


Function AssetNumber()
Dim $objWmi, $objWmiCS, $obj, $retval, $pc
$pc = @wksta
$objWmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\$pc\root\cimv2")
$objWmiCS = $objWmi.ExecQuery("select * from Win32_ComputerSystemProduct")
For Each $obj in $objWmiCS
$retval = $obj.IdentifyingNumber
Next
$AssetNumber = Trim($retval)
EndFunction

Tuesday, July 7, 2009

KiXtart: Enumerate Local Shares


Break ON

$strComputer = "."
$tab = Chr(9)

$objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\$strComputer\root\cimv2")
$colShares = $objWMIService.ExecQuery("Select * from Win32_Share")
$numshares = $colShares.Count

? "shares found: $numshares"

For each $objShare in $colShares
$n = $objShare.Name
If Right($n,1) = "$$"
$shareType = "HIDDEN"
Else
$shareType = "OPEN"
EndIf
? $objShare.Name + $tab + $shareType + $tab +
$objShare.Path + $tab + $objShare.Caption + $tab +
$objShare.Type
Next