Comparing WMI DateTime to String in Query - vbscript

I'm trying to query Win32_NTLogEvent for entries past the previous time that I ran the query. I've tried using a string variable so that I can change it every time I run the script. But I am getting a null returned for the generated collection. I've looked up what I can about WMI DateTimes and using them in comparisons. Although I have found some seemingly conflicting information (namely some sources using human readable to compare directly with UTC and others not). I've tried a UTC string and a human readable string. But neither seem to work. I'm thinking it is because I need to compare a datetime to a datetime as opposed to a string to a string. Although many sources seem to say that a string to a string would work in this case. But, even if I am right, I'm not sure how to convert the time for every object in Win32_NTLogEvent while inside the query.
Here is the relevant part of my script. The UTC that is commented out is just there because I don't want to retype the date if I have to go back to UTC:
strTimeMin = "01/01/1970/0:00:00"
'19700101000000.000000-480
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'Querying Event Logs
Set colLoggedEvents = objWMIService.ExecQuery _
("SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'system' AND "_
& "Type = 'Error' AND TimeGenerated > " & strTimeMin & "")
Thanks for any help!

UTC strings should work fine. However, since they're strings you need to put them between single quotes in your WMI query:
computer = "..."
minTime = "20140801000000.000000-000"
Set wmi = GetObject("winmgmts:\\" & computer & "\root\cimv2")
qry = "SELECT * FROM Win32_NTLogEvent " & _
"WHERE LogFile = 'System' AND Type = 'Error' " & _
"AND TimeGenerated > '" & minTime & "'"
For Each evt In wmi.ExecQuery(qry)
...
Next

Related

Select from Object with multiple attributes "Invalid query" Error

I have a Server with multiple Sessions on it, which all have to have a process running.
My Program should start up that process as soon as it stopped and the Session is online.
I checked for the process, and if I didn't find it I just started it. The problem is, I see the same process over all Sessions. How can I just get the processes of my Session and not the whole Server's?
This was my try, but it throws me an Error:
option explicit
DIM strComputer
DIM strProcessName
DIM WshShell
DIM strWMIQuery
DIM strSessionID
Set wshShell = CreateObject("WScript.Shell")
strSessionID= wshShell.ExpandEnvironmentStrings("%SESSIONID%")
strComputer = "."
strProcessName = "FortiSwitch-Replacer.exe"
strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "' AND SessionId like '" & strSessionID & "'"
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
if objWMIService.ExecQuery(strWMIQuery).Count > 0 then
'Dont do anything
else
'start process
end if
The Error is at the "ExecQuery()" Part (line 18) saying "Invalid query"
Lankymart found out the Answer:
The SessionId needs to be an Integer while mine was a String. By Changing the Value into an Integer the program would've worked.
What I want to add:
The ExpandEnvironmentStrings don't offer the SessionId. Right now I've used a small script from an Answer of this Question: Is it possible to run Powershell code from VBScript?
It Runs the simple Powershell command to get the SessionId in VBS.
If anyone else has some different Ideas on how to get the SessionId another way I'm interested to learn and see them :)

Is there a script to check existing printer name and rename it?

As mentioned in title, I have to change the client side printer name and unified the name of them.
For example there are lots of workstation who has installed same printer with different named. So, is there any script that i can use to change the name by checking the existing name ?
(e.g. : HP_printer_4300_ABC, HP_4300_ABC and 4300_printer_ABC to change to ABC )
You can query and change your printers' names using WMI
Here's a simple script that I just coded which should do what you want
strComputer = "." ' Local computer
strOldNameContains = "_ABC" ' The target printers to rename contains this string
strNewName = "ABC" ' New name for the printer
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPrinters = objWMIService.ExecQuery ("Select * From Win32_Printer ")
For Each objPrinter in colPrinters
' Uncomment this for debugging
'msgbox objPrinter.Name
if instr(objPrinter.Name,strOldNameContains)>0 then
msgbox "Changing printer name from '" & objPrinter.Name & "' to '" & strNewName & "'"
objPrinter.RenamePrinter(strNewName)
end if
Next
Adapt the strings on top if needed, and remove the msgbox when you are ready

Query to Select All Non-Essential Temporary Files

I am trying to write a script to delete unneeded temporary files. I am wanting to specifically target .tmp's, though. At least for now. So I am trying to write a WQL query to return a collection with which I can use a FOR EACH statement to delete all of the .tmp's in C:\Users\\AppData\Local\Temp. I've only recently started learning VBScript. But I have experience writing programs in C/C++ (mainly "math-y" programs).
Cscript seems to have no problem with the query itself. But when I try to use the Count method on the resulting collection, cscript returns an error: (17,1) Microsoft VBVScript runtime error: Object doesn't support this property or method: 'colTempFiles.Count'.
I've read up on WQL a little bit, thinking that maybe I'm not getting a collection returned for some reason. But I can't seem to find anything wrong with the query. I'm thinking that maybe I shouldn't be selecting from FileSystemObject. But I've read what I can find about it, and it seems to be the right thing to do (although there really isn't a lot of helpful info on MSDN).
Anyway, here's the script I currently have, without comments. The second line is something I am not currently using, but am going to try to use later, so that I can define a variable as the local computer's username and not have to point to the local Temp folder's path specifically. Any help would be greatly appreciated:
strComputer = "."
strUser="adam"
Set objFSO=CreateObject("Scripting.FileSystemObject")
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colTempFiles = objWMIService.ExecQuery _
("SELECT * FROM FileSystemObject WHERE Name = '*.tmp' AND "_
& "NOT Name LIKE 'Prf%' AND Path LIKE 'C:\Users\adam\AppData\Local\Temp\%'")
colTempFiles.Count
For Each objFile in colTempFiles
Wscript.Echo objFile.Name
'Set objF=objFSO.GetFile("objFile.Path")
'objF.Delete(True)
Next
I think you're confusing two different technologies. A FileSystemObject is a COM class that needs to be instantiated using CreateObject() in VBScript. For WQL, you need to use a WMI class in your query. Here is a core list of WMI classes. For your purposes, you'll want to use the CIM_DataFile class to work with files.
You can use either technology. The FileSystemObject is the preferred method if you're working with the local file system. If you need to work with files on a remote machine, use WMI and WQL.
Here's an example using a FileSystemObject:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\Users\adam\AppData\Local\Temp")
For Each objFile In objFolder.Files
If StrComp(objFSO.GetExtensionName(objFile.Path), "tmp", vbTextCompare) = 0 Then
objFile.Delete ' This is the Delete() method of the FSO's "File" class
End If
Next
And here's an example using WQL:
strComputer = "."
' Connect to the WMI service on the specified computer...
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
' Build our WQL query...
strQuery = "select * from CIM_DataFile "
strQuery = strQuery & "where Drive='C:' "
strQuery = strQuery & "and Path='\\Users\\adam\\AppData\\Local\\Temp\\' "
strQuery = strQuery & "and Name like '%.tmp'"
' Run the query...
Set colTempFiles = objWMIService.ExecQuery(strQuery)
' Delete each file...
For Each objFile In colTempFiles
objFile.Delete ' This is the Delete() method of the WMI "CIM_DataFile" class
Next

Does VBScript Support Introspection for Objects?

I am pulling results back from WMI using WQL via VBScript.
In examples, a For Each loop is used to iterate over the results, but in each example, it is assumed that the property names are known. Case in point:
Set colInstalledPrinters = objWMIService.ExecQuery ("Select * from Win32_Printer Where Default = True")
For Each objPrinter in colInstalledPrinters
Wscript.Echo objPrinter.Name
Next
Some of the WMI classes have a very long list of properties associated with them. As an additional complication, some properties cannot be expected to be present (according to various webpages I have read about WMI). Rather than researching each WMI class and hoping that the properties listed are present, I would like to obtain a list of the properties (or columns, if I am thinking in SQL/WQL) present for, say, an objPrinter or any other returned item.
Python is my usual language but I cannot install it on the target machines in this instance; I can perform remote querying of WMI via Python but I am trying to trigger on an local event, hence falling back to VBScript. Although I gather Powershell might be able to do this, I would rather not learn it just this instant.
So, does VBScript support that level of introspection which would allow me to enumerate a list of properties? Or is there something I can do involving a schema I can reference and examine in-script?
Use the .Properties_ collection of the item:
Option Explicit
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
Dim objWMIService
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Dim colItems
Set colItems = objWMIService.ExecQuery( _
"SELECT * FROM Win32_Printer" _
, "WQL" _
, wbemFlagReturnImmediately + wbemFlagForwardOnly _
)
Dim objItem
For Each objItem In colItems
Dim oProp
For Each oProp In objItem.Properties_
WScript.Echo oProp.Name, TypeName( oProp.Value ), ToString( oProp.Value )
Next
WScript.Echo
Next
Function ToString( vX )
ToString = "!! work to do !!"
On Error Resume Next
ToString = CStr( vX )
On Error GoTo 0
End Function
Output:
...
MimeTypesSupported Null !! work to do !!
Name String Auto HP LaserJet 5 on WINXP2
NaturalLanguagesSupported Null !! work to do !!
Network Boolean False
PaperSizesSupported Variant() !! work to do !!
...
Obviously, the ToString() function needs further work.

Quoting in VBscript

I am using vbscript to query an "at" job that is executing a specific command and I believe I have the quoting wrong. I have confirmed the script works as intended when I query something that does not contain spaces or quotes; however when I query for something that contains spaces and quotes I do not get the desired results. The exact value I want to find is:
cmd /c "C:\Test Folder\Folder1\Blah.cmd"
Here is the code I am using:
strComputer = "."
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\"_
& strComputer & "\root\cimv2")
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='cmd /c ""C:\Test Folder\Folder1\Blah.cmd""' ")
For Each objJob in colRandJob
WScript.Echo "Found AT Job with ID " + CStr(objJob.JobID)
Next
I have tried a few different things and cant seem to find the right way. Can someone help me out and let me know the proper way to do this?
Update
I was able to resolve the issue by doing the following (I am only including the relevant lines) I have not tested this without the double back slash's in the path, but I believe it is required along with the new quoting I have used:
'Assign the string I'm looking for to a variable
set targetCmd = "cmd /c "C:\\Test Folder\\Folder1\\Blah.cmd""
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='" & targetCmd & "' ")
Backslash (\) is an escape character in WMI. So, WMI queries must use double backslashes \\ in place of each single backslash:
Set colRandJob = objWMIService.ExecQuery _
("Select * from Win32_ScheduledJob WHERE Command='cmd /c ""C:\\Test Folder\\Folder1\\Blah.cmd""' ")
Use """" to produce a string containing only " and also use & to concatenate your string first.
mystring = "cmd /c " & """"C:\Test Folder\Folder1\Blah.cmd"""
(not tested )

Resources