Print binary data WScript - vbscript

I am using the last example on this page in WMI to print out some Windows System Log information:
http://msdn.microsoft.com/en-us/library/aa394593(VS.85).aspx
I would also like to print out the binary data as well, but I am not sure how to do that in WScript. Here is my modified code:
' test.vbs
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colLoggedEvents = objWMIService.ExecQuery _
("Select * from Win32_NTLogEvent " _
& "Where Logfile = 'System' and SourceName = 'MySource'")
For Each objEvent in colLoggedEvents
Wscript.Echo "Category: " & objEvent.Category & VBNewLine _
& "Event Code: " & objEvent.EventCode & VBNewLine _
& "Message: " & objEvent.Message & VBNewLine _
& "Time Written: " & objEvent.TimeWritten & VBNewLine _
& "Event Type: " & objEvent.Type & VBNewLine _
& "Binary Data: " & objEvent.Data
Next
I get this error message from Windows Script Host when running test.vbs:
Error: Type mismatch, Code: 800A000D, Source: Microsoft VBScript runtime error
Any idea how to print the data out as a hex character string?

.Data is an array of integer values (little endian encoded wide characters from the looks of it). You'd need to ChrW() each pair of numbers and concatenate them to a string before you could print the data. A function like this might work:
Function ToStr(arr)
ToStr = ""
For i = 0 To UBound(arr) Step 2
ToStr = ToStr & ChrW(arr(i) + arr(i+1)*256)
Next
End Function

Related

Is there a way to organize WriteLine output into columns in a text file?

Is there any way to separate the WriteLine data output in a text file into columns (ex: Date | Location | Size)?
I've yet to see any information regarding this anywhere online, unsure if possible since the data being written isn't static. Would I need an entirely different function in order to have the script handle the formatting of the text file?
Option Explicit
Dim sDirectoryPath,Search_Days,r_nr,iDaysOld,CmdArg_Object,lastModDate
Dim oFSO,oFolder,oFileCollection,oFile,oTF,Inp, SubFolder,fullpath
Set CmdArg_Object = Wscript.Arguments
Select Case (CmdArg_Object.Count)
Case 3
sDirectoryPath = CmdArg_Object.item(0)
Search_Days = CmdArg_Object.item(1)
r_nr = CmdArg_Object.item(2)
Case Else
WScript.Echo "SearchFiles.vbs requires 3 parameters:" & _
vbCrLf & "1) Folder Path" & _
vbCrLf & "2) # Days to Search" & _
vbCrLf & "3) Recursive option (r/nr)"
WScript.Quit
End Select
Set oFSO = CreateObject("Scripting.FileSystemObject")
iDaysOld=Date+(-1*Search_Days)
Inp = InputBox("Please Enter Desired Location of Log File:")
If Inp= "" Then
Set oTF = oFSO.CreateTextFile("C:\output.txt")
Else
Set oTF = oFSO.CreateTextFile(oFSO.BuildPath(Inp, "output.txt"))
End If
Set oFolder = oFSO.GetFolder(sDirectoryPath)
Set oFileCollection = oFolder.Files
WScript.Echo Now & " - Beginning " & Search_Days & " day search of " & sDirectoryPath
If r_nr = "r" Then
oTF.WriteLine ("Search Parameters-") & _
vbCrLf & "DirectoryPath: " & sDirectoryPath & _
vbCrLf & "Older than: " & Search_Days &" Days " & _
vbCrLf & "Recursive/Non-Recursive: " & r_nr & _
vbCrLf & "------------------ "
TraverseFolders oFSO.GetFolder(sDirectoryPath)
Function TraverseFolders (FolderName)
For Each SubFolder In FolderName.SubFolders
For Each oFile In SubFolder.Files
lastModDate = oFile.DateLastModified
If (lastModDate <= iDaysOld) Then
oTF.WriteLine (oFile.DateLastModified) & " " & oFile.Path
End If
Next
TraverseFolders(Subfolder)
Next
End Function
Else
oTF.WriteLine ("Search Parameters:") & _
vbCrLf & "DirectoryPath: " & sDirectoryPath & _
vbCrLf & "Older than: " & Search_Days &" Days " & _
vbCrLf & "Recursive/Non-Recursive: " & r_nr & _
vbCrLf & "------------------------- "
For Each oFile In oFileCollection
lastModDate = oFile.DateLastModified
If (lastModDate <= iDaysOld) Then
oTF.WriteLine (oFile.DateLastModified) & " " & oFile.Path
End If
Next
End If
If Inp = "" Then
WScript.Echo "Now - Finished! Results Placed in: C:\output.txt"
Else
WScript.Echo "Now - Finished! Results Placed in: " & Inp
End If
You could use a delimiter-separated output format, e.g. like this:
Delim = vbTab
oTF.WriteLine "DateLastModified" & Delim & "Size" & Delim & "Path"
...
For Each oFile in oFileCollection
oTF.WriteLine oFile.DateLastModified & Delim & oFile.Size & Delim & oFile.Path
Next
Using tabs and a carefully chosen order of fields has the advantage that editors will display the content in (mostly) proper columns and you can import it as CSV in other programs.
If you're aiming for a fixed-width format you need to pad the data yourself e.g. with custom padding functions, e.g.
Function LPad(s, l)
n = 0
If l > Len(s) Then n = l - Len(s)
LPad = String(n, " ") & s
End Function
Using a StringBuilder object would also be an option, as described in this answer to another question.

Trigger some vbs code on filename change

I would like to be able run some custom vb script code upon filename change (for instance to keep a list of newly created files or the ones which changed their name).
The vbs should be called on every filename change happening within a specified folder.
I know how to do that with a full directory scan but I would like to find a more efficient method, for instance by the mean of a sort of OS hook calling my code.
Any way to do that ?
Thank you,
A.
There are two simple WMI examples, tracing changes for *.txt files in C:\Test\ folder.
First one is for synchronous event processing:
Option Explicit
Dim oWMIService, oEvents, s
Set oWMIService = GetObject("WinMgmts:\\.\root\CIMv2")
Set oEvents = oWMIService.ExecNotificationQuery( _
"SELECT * FROM __InstanceOperationEvent " & _
"WITHIN 1 WHERE " & _
"TargetInstance ISA 'CIM_DataFile' AND " & _
"TargetInstance.Drive = 'C:' AND " & _
"TargetInstance.Extension = 'txt' AND " & _
"TargetInstance.Path = '\\Test\\'")
Do
With oEvents.NextEvent()
s = "Event: " & .Path_.Class & vbCrLf
With .TargetInstance
s = s & "Name: " & .Name & vbCrLf
s = s & "File Size: " & .FileSize & vbCrLf
s = s & "Creation Date: " & .CreationDate & vbCrLf
s = s & "Last Modified: " & .LastModified & vbCrLf
s = s & "Last Accessed: " & .LastAccessed & vbCrLf
End With
If .Path_.Class = "__InstanceModificationEvent" Then
With .PreviousInstance
s = s & "Previous" & vbCrLf
s = s & "File Size: " & .FileSize & vbCrLf
s = s & "Last Modified: " & .LastModified & vbCrLf
End With
End If
End With
WScript.Echo s
Loop
The second is for asynchronous event processing:
Option Explicit
Dim oWMIService, oSink
Set oWMIService = GetObject("WinMgmts:\\.\root\CIMv2")
Set oSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_")
oWMIService.ExecNotificationQueryAsync oSink, _
"SELECT * FROM __InstanceOperationEvent " & _
"WITHIN 1 WHERE " & _
"TargetInstance ISA 'CIM_DataFile' AND " & _
"TargetInstance.Drive = 'C:' AND " & _
"TargetInstance.Extension = 'txt' AND " & _
"TargetInstance.Path = '\\Test\\'"
Do
WScript.Sleep 1000
Loop
Sub Sink_OnObjectReady(oEvent, oContext)
Dim s
With oEvent
s = "Event: " & .Path_.Class & vbCrLf
With .TargetInstance
s = s & "Name: " & .Name & vbCrLf
s = s & "File Size: " & .FileSize & vbCrLf
s = s & "Creation Date: " & .CreationDate & vbCrLf
s = s & "Last Modified: " & .LastModified & vbCrLf
s = s & "Last Accessed: " & .LastAccessed & vbCrLf
End With
If .Path_.Class = "__InstanceModificationEvent" Then
With .PreviousInstance
s = s & "Previous" & vbCrLf
s = s & "File Size: " & .FileSize & vbCrLf
s = s & "Last Modified: " & .LastModified & vbCrLf
End With
End If
End With
WScript.Echo s
End Sub
More info on CIM_DataFile instance properties you can find by the link on MSDN.

How to Calculate Percentages of Free Space

I got a script which obtains disk space usage of servers. How to get the output in a table with free space percentage?
Below is the code:
strComputer = "Computer Name"
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root'\cimv2")
Set colDisks = objWMIService.ExecQuery _
("Select * from Win32_LogicalDisk where drivetype=" & HARD_DISK)
str = str & "SERVER 1 - " & strComputer & vbcrlf
str = str & vbcrlf
For Each objDiskC in colDisks
str = str & objDiskC.DeviceID & " " & FormatNumber(objDiskC.Size/1073741824,2) & " GB" & vbcrlf & vbtab & vbtab
str = str & objDiskC.DeviceID & " " & FormatNumber(objDiskC.FreeSpace/1073741824,2) & " GB" & vbcrlf
Next
str = str & vbcrlf
str = str & vbcrlf
'====================================================================
'Wscript.Echo str
'Send the email
SendMail "xxx#xxx.com", "xxx#xxx.com", "*** Free Disk Space Summary ***", str
'
Sounds like you just want to calculate the percentage of free-space.
The calculation for this is simply;
(objDiskC.FreeSpace / objDiskC.Size) * 100
Here have added an extra line to the For Next loop to denote the percentage.
For Each objDiskC in colDisks
str = str & objDiskC.DeviceID & " " & FormatNumber(objDiskC.Size/1073741824, 2) & " GB" & vbCrLf & vbTab & vbTab
str = str & objDiskC.DeviceID & " " & FormatNumber(objDiskC.FreeSpace/1073741824, 2) & " GB" & vbCrLf
'Added this line to your For loop.
str = str & objDiskC.DeviceID & " " & FormatNumber((objDiskC.FreeSpace / objDiskC.Size) * 100, 2) & "% Free" & vbCrLf
Next
I would suggest to use a HTML Table. You could also insert a CSS style snippet to the HTML Mail body which sets the margins / paddings inside the table.
For this small solution I would suggest to use string interpolation for creating table, tr, td and the style element. Then use the well known way to make the percentage value out of the absolute sizes.
Have a look at MDN - Table on how to use it.

Use Registry value to start a batch

I'd like to check at fixed time intervals (days) if a specific registry key exceeds a certain value.
If yes, then run a batchfile.
Is this possible (maybe with RegScanner ?) / how ?
thx
This is from the sample code in Help on RegistryValueChangeEvent in WMI
Set wmiServices = GetObject("winmgmts:root/default")
Set wmiSink = WScript.CreateObject( _
"WbemScripting.SWbemSink", "SINK_")
wmiServices.ExecNotificationQueryAsync wmiSink, _
"SELECT * FROM RegistryValueChangeEvent " _
& "WHERE Hive='HKEY_LOCAL_MACHINE' AND " _
& "KeyPath='SOFTWARE\\Microsoft\\WBEM\\sCRIPTING' " _
& "AND ValueName='Default Namespace'"
WScript.Echo "Listening for Registry Value" _
& " Change Events..." & vbCrLf
While(True)
WScript.Sleep 1000
Wend
Sub SINK_OnObjectReady(wmiObject, wmiAsyncContext)
WScript.Echo "Received Registry " _
& "Change Event" & vbCrLf & _
wmiObject.GetObjectText_()
End Sub

VBScript - Don't know why my arguments are not used the same way as variables

I have written a VBScript to enumerate events from the event log on a particular day.
The first query select from the NT event log events between todays date and yesterdays date,
Set colEvents = objWMIService.ExecQuery _
("Select * from Win32_NTLogEvent Where TimeWritten >= '" _
& dtmStartDate & "' and TimeWritten < '" & dtmEndDate & "'")
Then from the query above i want to extract event id's from a log file.
For Each objEvent in colEvents
If objEvent.Eventcode = EventNu And (objEvent.LogFile = EventLog) Then
I have placed the following into the script and it works, however I want to use arguments instead via command line (i.e. EventLogCheck.vbs EventNumber LogFile )but if i use the arguments secion of the script no items are returned. This is driving me nuts. The full script below uses variables, i have commented out the arguments section, but you can uncomment them and play around with it. What am i doing wrong? Thanks for any help!
Const CONVERT_TO_LOCAL_TIME = True
Dim EventLog
EventNu = 18
EventLog = "System"
'Input from the command line
'If Wscript.Arguments.Count <= 1 Then
' Wscript.Echo "Usage: EventLogCheck.vbs EventNumber LogFile"
' Wscript.Quit
'End If
'EventNu = WScript.Arguments.Item(0)
'EventLog = WScript.Arguments.Item(1)
'For Each Computer In Wscript.Arguments
Set dtmStartDate = CreateObject("WbemScripting.SWbemDateTime")
Set dtmEndDate = CreateObject("WbemScripting.SWbemDateTime")
'DateToCheck = CDate("5/18/2009")
DateToCheck = date
dtmStartDate.SetVarDate DateToCheck, CONVERT_TO_LOCAL_TIME
dtmEndDate.SetVarDate DateToCheck + 1, CONVERT_TO_LOCAL_TIME
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colEvents = objWMIService.ExecQuery _
("Select * from Win32_NTLogEvent Where TimeWritten >= '" _
& dtmStartDate & "' and TimeWritten < '" & dtmEndDate & "'")
For Each objEvent in colEvents
If objEvent.Eventcode = EventNu And (objEvent.LogFile = EventLog) Then
'Wscript.Echo "Category: " & objEvent.Category
Wscript.Echo "Computer Name: " & objEvent.ComputerName
Wscript.Echo "Event Code: " & objEvent.EventCode
Wscript.Echo "Message: " & objEvent.Message
' Wscript.Echo "Record Number: " & objEvent.RecordNumber
' Wscript.Echo "Source Name: " & objEvent.SourceName
Wscript.Echo "Time Written: " & objEvent.TimeWritten
Wscript.Echo "Event Type: " & objEvent.Type
' Wscript.Echo "User: " & objEvent.User
Wscript.Echo objEvent.LogFile
End if
Next
'Next
WScript.Echo EventNu
WScript.Echo EventLog
The arguments passed are treated as being of type string. However, EventNu should be an integer. You therefore have to convert the arguments to the correct type using CInt and CStr:
EventNu = CInt(WScript.Arguments.Item(0))
EventLog = CStr(WScript.Arguments.Item(1))

Resources