Creation of object methods includes two steps:
-
Writing the methods code.
-
Adding information about methods to the description file.
On this step we will write the script code for the WMI
object methods. On the next step we will add information about the methods to the description.xml file. For a summary on the methods, review the step 1.
Most of the WMI
object methods that we are going to create will query WMI for various information using the SWbemServices.ExecQuery
method. The rest of this topic provides the full code of the methods as well as the explanation of what this code does. You need to add this code to the wmiCode unit.
ConnectToComputer
This method connects to WMI on a computer using the specified user account. It is actually a wrapper over the ConnectToComputerInternal
routine that we have created earlier, with added reporting to the playback indicator and the test log.
The code below also contains the helper GetComputerDisplayName
function that is used to obtain the computer name for use in the indicator and log messages. This method simply returns the computer name stored in theComputerName
variable, except when the local computer is specified by the dot string (".") -- in this case the method transforms it into the actual computer name.
VBScript
Const UMSG_ComputerConnected = "A connection to the ""%s"" computer has been established successfully."
Const UMSG_UnableToConnect = "Unable to connect to the ""%s"" computer."
Const USMG_WaitingForConnection = "Connecting to the ""%s"" computer..."
Sub ConnectToComputer(Computer, User, Password)
ComputerName = Computer
' Attempt to connect to WMI on the specified computer
On Error Resume Next
Indicator.PushText(aqString.Format(USMG_WaitingForConnection, GetComputerDisplayName))
ConnectToComputerInternal User, Password
Indicator.PopText
' Check if connection was successful
If Err.Number = 0 Then
Log.Message(aqString.Format(UMSG_ComputerConnected, GetComputerDisplayName))
Else
Log.Error(aqString.Format(UMSG_UnableToConnect, GetComputerDisplayName))
End If
End Sub
Function GetComputerDisplayName
If ComputerName = CLocalComputer Then
GetComputerDisplayName = Sys.HostName
Else
GetComputerDisplayName = ComputerName
End If
End Function
WaitForComputer
This method waits until the connection to WMI on the specified remote computer is established. Like ConnectToComputer
, this method is also a wrapper over the ConnectToComputerInternal
routine. The method calls the ConnectToComputerInternal
routine multiple times until the remote WMI connection is successfully established or the timeout period elapses. The method also reports its actions and results to the playback indicator and the test log.
VBScript
Const UMSG_ConnectionTimeout = "Failed to connect to the ""%s"" computer during the timeout period."
Sub WaitForComputer(Computer, User, Password, Timeout)
ComputerName = Computer
' Convert the timeout value from milliseconds to seconds (round to larger)
Dim TimeoutSeconds
TimeoutSeconds = Timeout \ 1000
If Timeout Mod 1000 <> 0 Then
TimeoutSeconds = TimeoutSeconds + 1
End If
' Perform multiple attempts to connect to the specified computer during the timeout period
On Error Resume Next
Indicator.PushText(aqString.Format(USMG_WaitingForConnection, GetComputerDisplayName))
Dim StartTime
StartTime = Now
Do
Err.Clear
ConnectToComputerInternal User, Password
Loop While (Err.Number <> 0) And (DateDiff("s", StartTime, Now) < TimeoutSeconds)
Indicator.PopText
' Check if connection succeeded
If Err.Number = 0 Then
Log.Message(aqString.Format(UMSG_ComputerConnected, GetComputerDisplayName))
Else
Log.Error(aqString.Format(UMSG_ConnectionTimeout, GetComputerDisplayName))
End If
End Sub
RestartComputer
This method uses the Reboot
method of the Win32_OperatingSystem
WMI class to shut down and then restart the computer:
VBScript
Sub RestartComputer
Dim OSColl, OSItem
Set OSColl = WMIService.ExecQuery("SELECT * FROM Win32_OperatingSystem")
For Each OSItem In OSColl
OSItem.Reboot
Next
End Sub
GetEnvironmentVariable
This method queries the Win32_Environment
class instance corresponding to the environment variable with the specified name and retrieves the variable value. The Flags_RtnImmedFwdOnly
flag value is used to improve the performance of the WMI queries.
VBScript
Const Flags_RtnImmedFwdOnly = &H30 ' The iFlags value for the SWbemServices.ExecQuery method
Function GetEnvironmentVariable(Name)
Dim EnvVarColl, EnvVarItem
' Search for an environment variable with the specified name
Set EnvVarColl = WMIService.ExecQuery _
("SELECT * FROM Win32_Environment WHERE Name='" & Name & "'", , Flags_RtnImmedFwdOnly)
' Get the variable's value
For Each EnvVarItem In EnvVarColl
GetEnvironmentVariable = EnvVarItem.VariableValue
Exit For
Next
End Function
PostEnvironmentVariableInfo
This method queries the Win32_Environment
WMI class to retrieve all environment variables defined on the computer and then posts the obtained information to the test log:
VBScript
Sub PostEnvironmentVariableInfo
Dim EnvVarColl, EnvVarItem
Log.AppendFolder("Environment Variables")
' Obtain all environment variables
Set EnvVarColl = WMIService.ExecQuery("SELECT * FROM Win32_Environment", , Flags_RtnImmedFwdOnly)
' Log the variables' properties
For Each EnvVarItem In EnvVarColl
Log.AppendFolder EnvVarItem.Name
Log.Message "Value: " & EnvVarItem.VariableValue
Log.Message "User name: " & EnvVarItem.UserName
Log.Message "Description: " & EnvVarItem.Description
Log.Message "System variable: " & EnvVarItem.SystemVariable
Log.PopLogFolder
Next
Log.PopLogFolder
End Sub
PostProcessorInfo
This method queries the Win32_Processor
WMI class to obtain information about the computer’s CPUs and then posts this information to the test log:
VBScript
Sub PostProcessorInfo
Dim ObjectsList, CurrentObject, ID
Log.AppendFolder "Processors"
' Obtain all the processors
Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_Processor", , Flags_RtnImmedFwdOnly)
' Log the processors' properties
ID = 1
For Each CurrentObject In ObjectsList
Log.AppendFolder "Processor #" & ID
Log.Message "Manufacturer: " & CurrentObject.Manufacturer
Log.Message "Description: " & CurrentObject.Description
Log.Message "Frequency: " & CurrentObject.CurrentClockSpeed
Log.PopLogFolder
ID = ID + 1
Next
Log.PopLogFolder
End Sub
PostDrivesInfo
This method queries the Win32_LogicalDisk
WMI class to retrieve information about the computer’s hard drives and then posts the obtained information to the test log:
VBScript
Sub PostDrivesInfo
Dim ObjectsList, CurrentObject
Log.AppendFolder "Logical Disks"
' Obtain all the fixed hard drives
Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE MediaType=12", , Flags_RtnImmedFwdOnly)
' Log the hard drives' properties
For Each CurrentObject In ObjectsList
Log.AppendFolder CurrentObject.Name
Log.Message "Label: " & CurrentObject.VolumeName
Log.Message "Size (MB): " & CurrentObject.Size / 1024^2
Log.Message "Free space (MB): " & CurrentObject.FreeSpace / 1024^2
Log.PopLogFolder
Next
Log.PopLogFolder
End Sub
PostInstalledAppsInfo
This method queries the Win32_Product
WMI class to retrieve information about software installed on the computer and then posts the obtained information to the test log:
VBScript
Sub PostInstalledAppsInfo
Dim ObjectsList, CurrentObject
Log.AppendFolder "Installed Applications"
' Obtain all the installed products
Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_Product", , Flags_RtnImmedFwdOnly)
' Log the products' properties
For Each CurrentObject In ObjectsList
Log.AppendFolder CurrentObject.Caption
Log.Message "Vendor: " & CurrentObject.Vendor
Log.Message "Version: " & CurrentObject.Version
Log.Message "Description: " & CurrentObject.Description
Log.Message "Location: " & CurrentObject.InstallLocation
Log.PopLogFolder
Next
Log.PopLogFolder
End Sub
PostEventsInfo
This method queries the Win32_NTLogEvent
WMI class to retrieve records from the system event log and then posts the latest records to the test log. The number of the latest events to report is specified by the MaxEventCount
variable:
VBScript
Sub PostEventsInfo
Dim ObjectsList, CurrentObject, Count
Log.AppendFolder("System Events")
' Retrieve entries from the system event log
Set ObjectsList = WMIService.ExecQuery("SELECT * FROM Win32_NTLogEvent WHERE LogFile='System'", , Flags_RtnImmedFwdOnly)
' Log the latest MaxEventCount events
Count = 1
For Each CurrentObject in ObjectsList
Log.AppendFolder(CurrentObject.SourceName)
Log.Message "User: " & CurrentObject.User
Log.Message "Category: " & CurrentObject.CategoryString
Select Case CurrentObject.EventType
Case 1
Log.Error "Message", CurrentObject.Message
Case 2
Log.Warning "Message", CurrentObject.Message
Case 3
Log.Message "Message", CurrentObject.Message
End Select
Log.PopLogFolder
Count = Count + 1
If Count > MaxEventCount Then
Exit For
End If
Next
Log.PopLogFolder
End Sub
CreateProcess
This method uses the Create
method of the Win32_Process
WMI class to launch a process specified by its command line and returns the process ID. If the method fails to create the specified process, it posts an error message to the test log:
VBScript
Const UMSG_ProcessWasCreated = "The ""%s"" process has been created successfully."
Const UMSG_UnableToCreateProcess = "Unable to create the ""%s"" process."
Const UMSG_ErrorWhileCreatingProcess = "An error occurred while creating the ""%s"" process. The error code is %u."
Function CreateProcess(CommandLine)
Dim Process, InParams, OutParams
Set Process = WMIService.Get("Win32_Process")
' Specify the command line to execute
Set InParams = Process.Methods_("Create").InParameters.SpawnInstance_
InParams.CommandLine = CommandLine
' Launch the process and get its ID
Set OutParams = WMIService.ExecMethod("Win32_Process", "Create", InParams)
CreateProcess = OutParams.ProcessId
' Check if the process was launched successfully
If OutParams.ReturnValue = 0 Then
Log.Message(aqString.Format(UMSG_ProcessWasCreated, CommandLine))
ElseIf IsNull(OutParams.ReturnValue) Then
Log.Error(aqString.Format(UMSG_UnableToCreate, CommandLine))
Else
Log.Error(aqString.Format(UMSG_ErrorWhileCreatingProcess, CommandLine, OutParams.ReturnValue))
End If
End Function
ProcessExists
This method checks to see if the specified process is running on the computer by querying the Win32_Process
class instance corresponding to the specified process name.
VBScript
Function ProcessExists(ProcessName)
ProcessExists = False
Dim ProcessColl, ProcessItem
' Search for a process with the specified name
Set ProcessColl = WMIService.ExecQuery _
("SELECT * FROM Win32_Process WHERE Name='" & ProcessName & "'", , Flags_RtnImmedFwdOnly)
' Check if the found object is valid
For Each ProcessItem In ProcessColl
ProcessExists = Not IsNull(ProcessItem.ProcessId)
Exit For
Next
End Function
WaitForProcessExit
This method waits until the specified process is stopped. For this, it monitors the __InstanceDeletionEvent
WMI event triggered by the Win32_Process
class instance corresponding to the specified process. This event occurs when a WMI class instance is deleted; in our case - when the process is stopped. The method waits for the event to occur within the provided timeout and then reports the results -- whether or not the event occurred and thus the process has stopped. The polling interval (that is, the interval that defines how often the method checks for the event) is specified by the CPollInterval
constant and is 100 ms by default.
VBScript
Const UMSG_ProcessNotFound = "The ""%s"" process is not running."
Const UMSG_ProcessExited = "The ""%s"" process has closed."
Const UMSG_ProcessHasntExited = "The ""%s"" process has not closed during the timeout period."
Const CPollInterval = 0.1 ' = 100 ms; Polling interval for event queries
Sub WaitForProcessExit(ProcessName, Timeout)
' Verify that the specified process is running
If Not ProcessExists(ProcessName) Then
Log.Message(aqString.Format(UMSG_ProcessNotFound, ProcessName))
Exit Sub
End If
Dim EventSource, EventItem
' Subscribe to the process termination event
Indicator.PushText(aqString.Format(UMSG_WaitingForProcessExit, ProcessName))
Set EventSource = oWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceDeletionEvent WITHIN " & CPollInterval _
& " WHERE TargetInstance ISA 'Win32_Process'" _
& " AND TargetInstance.Name='" & ProcessName & "'")
' Wait for the process to exit during the timeout period
On Error Resume Next
Set EventItem = EventSource.NextEvent(Timeout)
Set EventSource = Nothing
Indicator.PopText
' Check if the process has exited
If IsEmpty(EventItem) Then
Log.Error(aqString.Format(UMSG_ProcessHasntExited, ProcessName))
Else
Log.Message(aqString.Format(UMSG_ProcessExited, ProcessName))
End If
End Sub
GetServiceState
This method queries the Win32_Service
class instance corresponding to the service with the specified name and returns the current state of this service:
VBScript
Function GetServiceState(ServiceName)
Dim ServiceColl, ServiceItem
' Search for a service with the specified display name
Set ServiceColl = WMIService.ExecQuery _
("SELECT * FROM Win32_Service WHERE DisplayName='" & ServiceName & "'", , Flags_RtnImmedFwdOnly)
' Get the state of the service
For Each ServiceItem In ServiceColl
GetServiceState = ServiceItem.State
Exit For
Next
End Function
WaitForServiceState
This method waits until the service state changes; the service name and target state specified via the method parameters. The method implementation is similar to that of the WaitForProcessExit
. It subscribes to the __InstanceModificationEvent
WMI event generated by the Win32_Service
class instance corresponding to the specified service. This event occurs whenever a WMI class instance is modified; in our case - when the service’s State
property obtains the specified value. The method waits for the event to occur within the provided timeout and then reports the results.
VBScript
Const UMSG_ServiceNotFound = "The ""%s"" service is not registered."
Const UMSG_ServiceStateChanged = "The state of the ""%s"" service has changed to ""%s""."
Const UMSG_ServiceStateTimeout = "The state of the ""%s"" service has not changed to ""%s"" during the timeout period."
Const UMSG_WaitingForServiceStateChange = "Waiting until the state of the ""%s"" service changes..."
Sub WaitForServiceState(ServiceName, State, Timeout)
' Verify that the specified service is registered
If IsEmpty(GetServiceState(ServiceName)) Then
Log.Error(aqString.Format(UMSG_ServiceNotFound, ServiceName))
Exit Sub
End If
Dim EventSource, EventItem
' Subscribe to the service state change event
Indicator.PushText(aqString.Format(UMSG_WaitingForServiceStateChange, ServiceName))
Set Events = WMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceModificationEvent WITHIN " & CPollInterval _
& " WHERE TargetInstance ISA 'Win32_Service'" _
& " AND TargetInstance.DisplayName='" & ServiceName & "'" _
& " AND TargetInstance.State='" & State & "'")
' Wait for the service state to change during the timeout period
On Error Resume Next
Set EventItem = Events.NextEvent(Timeout)
Set Events = Nothing
Indicator.PopText
' Check if the service state has changed
If IsEmpty(EventItem) Then
Log.Error(aqString.Format(UMSG_ServiceStateTimeout, ServiceName, State))
Else
Log.Message(aqString.Format(UMSG_ServiceStateChanged, ServiceName, CurrentState))
End If
End Sub
Once you have added the methods’ code to the wmiCode unit, you can proceed to the following step where we will define these methods in the script extension’s description file.
See Also
Creating Object Methods
Creating Runtime Objects - Basic Concepts
Creating Runtime Objects