Microsoft Access Reads Windows Services

Our last two articles were about using WMI to manage Processes which are software programs that run on our computers. Processes are like CEOs that are up front and visible. Windows Services are like the CEO’s Secretary who is the one who really gets things done in the background. Some Processes are also Services, but most Services start when the computer boots or when a Program is opened or needs to perform a particular action such as Printing.

Managing Services can be useful to the Access Developer. You may need to pause, stop, disable, enable, or start a Service before performing some action with Access. You may need to manage some SQL Server Services or Network Services.


As I was working to build a table and form to manage Windows Services I found a browser toolbar that I knew nothing about. Other examples of Services are Software Updaters, SQL Server Services, Network Services, some Drivers, Logging and Reporting Services, and much more. In fact, Services enable most everything done by a Computer.


This brings us to an important point. When you deal with Services, you better know what you are doing or you can cause yourself a lot of grief. In future articles we will Stop, Start, Pause, Resume, Disable, and Enable some Services. We could easily demonstrate how to Delete Services, but I don’t want to help some poor soul accidentally cripple their Computer.


In this article we will show you how to get Services data, append it to a table, and display it in a Form. In upcoming articles we will use this Form to manage Services.

Image of the Services Form


We have a command button on our Form that is used to get the Services data. Because Services information changes often, we don’t feel a need to keep past Services data so we delete all the existing records in our table and then fill it with the latest data.

Private Sub cmdGetServicesData_Click()
On Error GoTo Err_cmdGetServicesData_Click

    Dim db As DAO.Database
    Dim strSQL As String

    strSQL = "DELETE * FROM tblWin32_Service"

    Set db = CurrentDb

    ' Delete all records in the Table
    ' In case of error, no records are changed
    db.Execute strSQL, dbFailOnError

    Set db = Nothing

    ' The following code takes a while to run
    ' Let the user know Access is working
    DoCmd.Hourglass True

    ' Fill the Table with the current Service Data
    Call FilltblWin32_Services("tblWin32_Service", "Win32_Service")

    ' Fill the form with the new data
    Me.Requery

	' Update the Find Service Combo box
    Me.cboFindService.Requery

Exit_cmdGetServicesData_Click:
    ' Make sure the Hourglass is Off
    ' This code will run even if there is an error
    DoCmd.Hourglass False
    Exit Sub

Err_cmdGetServicesData_Click:
    MsgBox "Error " & Err.Number & " (" & Err.Description & ")" & _
    " In procedure cmdGetServicesData_Click"
    Resume Exit_cmdGetServicesData_Click

End Sub


The cmdGetServicesData_Click sub calls the FilltblWin32_Services Procedure that fills the table with data.

Sub FilltblWin32_Services(strTableName As String, strClass As String)

    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim objWMIService As Object
    Dim colInstances As Object
    Dim objInstance As Object
    Dim colProperties As Object
    Dim objProperty As Object
    Dim strComputer As String
    Dim strNameSpace As String
    Dim strPropName As String
    Dim strPropValue As String
    Dim varID

    strComputer = "."

    strNameSpace = "\root\cimv2"

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

    Set colInstances = objWMIService.ExecQuery( _
        "SELECT * FROM " & strClass, , 48)

    'Set a pointer to the Database
    Set db = CurrentDb

    'Instantiate the recordset
    Set rst = db.OpenRecordset(strTableName, dbOpenDynaset)

    ' Get Each Instance
    For Each objInstance In colInstances
        'Add a New Record to the Recordset
        rst.AddNew
        ' Get the Property Names and Values in each Instance
        Set colProperties = objInstance.Properties_

        For Each objProperty In colProperties
            strPropName = objProperty.Name

            ' Avoid errors caused by Nulls
            strPropValue = CStr(Nz(objProperty.Value, vbNullString))

            ' Change Zero Length Strings to the string "Null"
            If Len(strPropValue & vbNullString) = 0 Then
                strPropValue = "Null"
            Else
                ' Some Values need to be converted to be understood
                Select Case strPropName
                    Case "ErrorControl"
                        strPropValue = GetErrorControl(strPropValue)
                    Case "StartMode"
                        strPropValue = GetStartMode(strPropValue)
                    Case "InstallDate"
                        strPropValue = WMIDateConvert(strPropValue)
                End Select
            End If
            ' Add the value to the Recordset
            rst(strPropName) = strPropValue
        Next objProperty

        ' This table does not use Autonumber so
        ' get the previous high number and add 1
        varID = DMax("ServiceID", "tblWin32_Service") + 1
        ' If this is first one, then value will be null
        If IsNull(varID) Then varID = 1
        rst!ServiceID = varID
        ' Get the current Date and Time
        rst!LastUpdated = Now()
        ' Do not forget to save the new Record to the Recordset
        rst.Update
    Next objInstance

    ' Release Memory
    rst.Close
    Set objProperty = Nothing
    Set colProperties = Nothing
    Set objInstance = Nothing
    Set colInstances = Nothing
    Set objWMIService = Nothing
    Set rst = Nothing
    Set db = Nothing

End Sub


After the table is filled with the data, the code returns to our initial sub and requeries the Form so it will display the Services information.


You may find some Services there you do not want or need and you may find some that are not running, but you want to start. We plan to write about how to manage Services in our next article.


You can download the free sample database, WMISample.zip which contains the Form and the code used in this article at our Gaining Access website.


More Free Downloads:
Us or UK/AU Pop-up Calendar
Report Date Dialog Form in US or UK/AU Version.
ScopeSight for Access Reports Demo: get the exact data you want on your Access Reports.
Free Church Management Software now with new Contributions management.
Code Samples


Get the Access and Outlook Appointment Manager to manage all of your Outlook Calendar Appointments and Access dated information.


Happy computing,


Patrick (Pat) Wood

Gaining Access

Microsoft Access: The Terminator of Processes

Microsoft Access can Terminate Processes using WMI. In other words, Access can shut down an application that is running on a computer. This capability is very useful when using Office automation or automation with other applications. For example, you may want to open an Excel Spreadsheet, import data, and then close Excel using the code in this article.

Access VBA can also be used to terminate a program when it “hangs” or “freezes”. I have at times thorougly enjoyed terminiating some repeat offenders using Access or VBSripts.


The code below shows the basics of how we can terminate a Process. We are using the name of the process in the WQL Query so we do not have to loop through all of the running processes. For example, if we want to close Notepad we can call the procedure using the name of the process as an argument like this: Call TerminateProcess(“notepad.exe”)

Sub TerminateProcess(strProcess As String)

    Dim objWMIService As Object
    Dim colProcesses As Object
    Dim objProcess As Object
    Dim strComputer As String

    strComputer = "."

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

    Set colProcesses = objWMIService.ExecQuery _
        ("SELECT * FROM Win32_Process WHERE" & _
        " Name = '" & strProcess & "'")

    For Each objProcess In colProcesses
        objProcess.Terminate
    Next objProcess

    Set objProcess = Nothing
    Set colProcesses = Nothing
    Set objWMIService = Nothing

End Sub


We can make this code more helpful by getting the result of the Terminate Method. We can change the procedure to a function that will return the result as an integer. We can also use a Message Box. The modified code below does both.

Function ProcessTerminate(strProcess As String) As Long

    Dim objWMIService As Object
    Dim colProcesses As Object
    Dim objProcess As Object
    Dim strComputer As String
    Dim strMsg As String
    Dim intReturn As Long
    Dim booFound As Boolean

    strComputer = "."

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

    Set colProcesses = objWMIService.ExecQuery _
        ("SELECT * FROM Win32_Process WHERE" & _
        " Name = '" & strProcess & "'")

    For Each objProcess In colProcesses
        ' The Process is running - set the flag to True
        booFound = True
        ' End the Process and get the Return code
        intReturn = objProcess.Terminate
    Next objProcess

    ' Start a Message string
    strMsg = "   Process Name:  " & strProcess & "      " & vbCrLf & vbCrLf

    ' Determine the result
    Select Case intReturn
        Case 0
            If booFound = True Then
                strMsg = strMsg & "   Termination succeeded.       "
            Else
                strMsg = strMsg & "   Unknown failure.      "
                intReturn = 8
            End If
        Case 2
            strMsg = strMsg & "   Access denied.       "
        Case 3
            strMsg = strMsg & "   Insufficient privilege.       "
        Case 8
            strMsg = strMsg & "   Unknown failure.       "
        Case 9
            strMsg = strMsg & "   Path not found.       "
        Case 21
            strMsg = strMsg & "   Invalid parameter.       "
        Case Else
            strMsg = strMsg & "   Termination failed for unknown reason.       "
    End Select

    strMsg = strMsg & vbCrLf & vbCrLf & "   Time: " & Now
    MsgBox strMsg

    ProcessTerminate = intReturn

    Set objProcess = Nothing
    Set colProcesses = Nothing
    Set objWMIService = Nothing

End Function


We can also Terminate more than one process by creating an array of process names.

Sub ProcessesTerminate()

    Dim objWMIService As Object
    Dim colProcesses As Object
    Dim objProcess As Object
    Dim strComputer As String
    Dim intReturn As Long
    Dim strTargetProc
    Dim arrTargetProcs

    strComputer = "."

	' Create the array of process names
    arrTargetProcs = Array("mspaint.exe", "calc.exe", "notepad.exe")

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

    Set colProcesses = objWMIService.ExecQuery( _
        "SELECT * FROM Win32_Process", , 48)

    Debug.Print "Checking for target processes ..."

    For Each objProcess In colProcesses
        For Each strTargetProc In arrTargetProcs
            ' Make all process names lowercase so they will match
            If LCase(objProcess.Name) = LCase(strTargetProc) Then
                Debug.Print vbCrLf & "Process Name: " & objProcess.Name
                Debug.Print "  Time: " & Now
                intReturn = objProcess.Terminate
                If intReturn = 0 Then
                    Debug.Print "  Terminated"
                Else
                    Debug.Print "  Unable to terminate"
                End If
            End If
        Next
    Next

    Set objProcess = Nothing
    Set colProcesses = Nothing
    Set objWMIService = Nothing

End Sub


We will learn more about how VBA can leverage the capabilities of WMI in the articles to come.


You can download the free sample database, WMISample.zip, which contains the code used in this article from our Gaining Access website. The code is located in the PAWWMIProcesses Module.


More Free Downloads:
Us or UK/AU Pop-up Calendar
Report Date Dialog Form in US or UK/AU Version.
ScopeSight for Access Reports Demo: get the exact data you want on your Access Reports.
Free Church Management Software now with new Contributions management.
Code Samples


Get the Access and Outlook Appointment Manager to manage all of your Outlook Calendar Appointments and Access dated information.


Happy computing,


Patrick (Pat) Wood

Gaining Access

Microsoft Access Reads the Processes Running On Your Computer

Are you curious to know what processes are running on your computer? You may be surprised to discover exactly what programs are running and how many run when you boot up. Just a few minutes ago I had 68 processes running. By using VBA to access WMI, I gathered an abundance of information on those processes. There was so much information the Visual Basic Editor Immediate Window could not display it all, so I saved it to a text file.

In our last article we showed how we can get Win32_OperatingSystem Class information by using VBA to access the power of WMI (Windows Management Instrumentation). The the Win32_OperatingSystem Class only has one “instance” on my computer, but there are always a number of instances of processes on a running computer. We can get that information using VBA and WMI but we need to use different code.


In order to get the information on each process running on our computer we need to access each instance in the Win32_Process class. The procedure below shows how to loop through each instance and list all the Property Names and Values of the instance.


This procedure has two arguments we must pass to it. First we pass the Name of the WMI class, Win32_Process. The next argument is the full path and name of the text file to which we want to save the data. For example, the procedure can be run by using Call SaveWMIClassInstancesData(“Win32_Process”, “C:\Win32_ProcessProperties.txt”). Using these arguments gives the code flexibility and allows us to use the same code for other classes. Why write six or seven procedures when you only need to write just one?

Sub SaveWMIClassInstancesData(strClassName As String, strTextFilePath As String)

    Dim objWMIServices As Object
    Dim colInstances As Object
    Dim objInstance As Object
    Dim colProperties As Object
    Dim objProperty As Object
    Dim fso As Object
    Dim fsoFile As Object
    Dim strComputer As String
    Dim strNameSpace As String
    Dim intCount As Long

    ' There may be too much text for the immediate window
    ' so create a text file and save the data
    Set fso = CreateObject("Scripting.FileSystemObject")

	' Create an instance of the text file
    Set fsoFile = fso.CreateTextFile(strTextFilePath)

    strComputer = "."
    strNameSpace = "\root\cimv2"

    Set objWMIServices = GetObject("winmgmts:" & _
        "{impersonationLevel=impersonate}!\" & _
        strComputer & strNameSpace)

	' Instantiate the Collection of Instances
    Set colInstances = objWMIServices.ExecQuery( _
        "SELECT * FROM " & strClassName, , 48)

    fsoFile.WriteLine "Properties of " & strClassName & " Class Instances "

	' Loop through each Instance
    intCount = 0
    For Each objInstance In colInstances
        intCount = intCount + 1
		' Get the Properties in the instance
        Set colProperties = objInstance.Properties_

		' Write some information to the text file
        fsoFile.WriteLine vbNewLine
        fsoFile.WriteLine "---------------------------------------"
        fsoFile.WriteLine "         Instance Number: " & intCount
        fsoFile.WriteLine "---------------------------------------"

		' Write the Property names and values to the text file
        For Each objProperty In colProperties
            fsoFile.WriteLine objProperty.Name & ": " & objProperty.Value
        Next objProperty
    Next objInstance

	fsoFile.Close

	' Release Memory
    Set fso = Nothing
    Set fsoFile = Nothing
    Set objProperty = Nothing
    Set colProperties = Nothing
    Set objInstance = Nothing
    Set colInstances = Nothing
    Set objWMIServices = Nothing

End Sub


Below is a sample of the data that was returned about Notepad.

—————————————
Instance Number: 67
—————————————
Caption: notepad.exe
CommandLine: “C:\WINDOWS\system32\notepad.exe”
CreationClassName: Win32_Process
CreationDate: 20090604134043.578125-240
CSCreationClassName: Win32_ComputerSystem
CSName: ACER-HO
Description: notepad.exe
ExecutablePath: C:\WINDOWS\system32\notepad.exe
ExecutionState:
Handle: 5640
HandleCount: 34
InstallDate:
KernelModeTime: 468750
MaximumWorkingSetSize: 1413120
MinimumWorkingSetSize: 204800
Name: notepad.exe
OSCreationClassName: Win32_OperatingSystem
OSName: Microsoft Windows XP Professional
OtherOperationCount: 111
OtherTransferCount: 400
PageFaults: 854
PageFileUsage: 1101824
ParentProcessId: 2248
PeakPageFileUsage: 1101824
PeakVirtualSize: 37982208
PeakWorkingSetSize: 3379200
Priority: 8
PrivatePageCount: 1101824
ProcessId: 5640
QuotaNonPagedPoolUsage: 2400
QuotaPagedPoolUsage: 62108
QuotaPeakNonPagedPoolUsage: 2944
QuotaPeakPagedPoolUsage: 77052
ReadOperationCount: 0
ReadTransferCount: 0
SessionId: 0
Status:
TerminationDate:
ThreadCount: 1
UserModeTime: 468750
VirtualSize: 30683136
WindowsVersion: 5.1.2600
WorkingSetSize: 3379200
WriteOperationCount: 0
WriteTransferCount: 0


The dates that are returned can be converted to a more readable format using the following procedure.

Function WMIDateConvert(dtmDate As String)
    WMIDateConvert = 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


Since the processes change each time a program is opened, a text file is a suitable way to save the data. With some other WMI classes you may want to save the data to an Access Table and the SaveWMIClassInstancesData procedure is well suited to be modified for that purpose.


You can learn more about the meaning of the values returned by opening the Win32 Classes web page and scrolling down the list of classes until you find the name of the class you need.


There is also another way to get all of the data available from each instance of a WMI class. We can use the GetObjectText_ Method. This method returns the data in MOF (Managed Object Format). Like the previous procedure, we need to provide the WMI Class Name and the text file name and path as arguments: Call SaveWMIClassMOF(“Win32_Process”, “C:\Win32_ProcessMOFProperties.txt”)

Function SaveWMIClassMOF(strClass As String, Optional strTextFilePath As String) As String

    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim fso As Object
    Dim fsoFile As Object
    Dim strComputer As String
    Dim strNameSpace As String
    Dim strMOF As String

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set fsoFile = fso.CreateTextFile(strTextFilePath)

    strComputer = "."
    strNameSpace = "\root\cimv2"

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

    Set colItems = objWMIService.ExecQuery( _
        "SELECT * FROM " & strClass, , 48)

	' This code loops through each instance
	' and returns the instance's properties and values
    ' We build the complete MOF text with the strMOF variable
    For Each objItem In colItems
	    strMOF = strMOF & objItem.GetObjectText_
    Next

    fsoFile.Write strMOF

    fsoFile.Close

    Set fso = Nothing
    Set fsoFile = Nothing
    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing

End Function


Below is the MOF data about Notepad.


instance of Win32_Process
{
Caption = “notepad.exe”;
CommandLine = “\”C:\WINDOWS\system32\notepad.exe\” “;
CreationClassName = “Win32_Process”;
CreationDate = “20090604134043.578125-240″;
CSCreationClassName = “Win32_ComputerSystem”;
CSName = “ACER-HO”;
Description = “notepad.exe”;
ExecutablePath = “C:\WINDOWS\system32\notepad.exe”;
Handle = “5640″;
HandleCount = 34;
KernelModeTime = “468750″;
MaximumWorkingSetSize = 1413120;
MinimumWorkingSetSize = 204800;
Name = “notepad.exe”;
OSCreationClassName = “Win32_OperatingSystem”;
OSName = “Microsoft Windows XP Professional”;
OtherOperationCount = “111″;
OtherTransferCount = “400″;
PageFaults = 854;
PageFileUsage = 1101824;
ParentProcessId = 2248;
PeakPageFileUsage = 1101824;
PeakVirtualSize = “37982208″;
PeakWorkingSetSize = 3379200;
Priority = 8;
PrivatePageCount = “1101824″;
ProcessId = 5640;
QuotaNonPagedPoolUsage = 2400;
QuotaPagedPoolUsage = 62108;
QuotaPeakNonPagedPoolUsage = 2944;
QuotaPeakPagedPoolUsage = 77052;
ReadOperationCount = “0″;
ReadTransferCount = “0″;
SessionId = 0;
ThreadCount = 1;
UserModeTime = “468750″;
VirtualSize = “30683136″;
WindowsVersion = “5.1.2600″;
WorkingSetSize = “3379200″;
WriteOperationCount = “0″;
WriteTransferCount = “0″;
};


You may notice when you get MOF data all of the Properties may not be listed. If a Property Value is Null MOF does not return the Property.


The MOF data can be added to an Access table but requires a bit of work. We were able to use string functions to clean up the text and the Split Function to create an array of instances and another array of Properties to add the MOF data to a Table. Modifying the SaveWMIClassInstancesData procedure to add the data to a Table requires much less work and is less likely to produce errors in the data.


MOF is used not only to return data, but also to create new WMI Classes, Properties, and Methods.

Information about WMI Classes is contained in MOF files and describe all of the Properties and Methods of each WMI Class, provide information about Enumerations, and details the the data types that are used. We can access that information using code that returns amended qualifiers as well as the detailed Class information. As before, we use the Class name and a text file path as arguments in calling the Function: Call SaveWMIClassDescription(“Win32_Service”, “C:\Win32_ServiceMOFDescription.txt”)

Function SaveWMIClassDescription(strClass As String, strTextFilePath As String) As String

    Dim objClass As Object
    Dim objWMIService As Object
    Dim fso As Object
    Dim fsoFile As Object
    Dim strNameSpace As String
    Dim strComputer As String
    Dim strMOF As String

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set fsoFile = fso.CreateTextFile(strTextFilePath)

    strComputer = "."
    strNameSpace = "\root\cimv2"

    'The wbemFlagUseAmendedQualifiers flag is required to get the amended
    ' Qualifiers and the Class Property and Method description
    Const wbemFlagUseAmendedQualifiers = &H20000

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

    Set objClass = objWMIService.Get(strClass, wbemFlagUseAmendedQualifiers)

    strMOF = objClass.GetObjectText_

	' Formatting the text makes it much easier to read
	' Comment out this block of code to see the raw data
    strMOF = Replace(strMOF, ";", ";" & Chr(10))
    strMOF = Replace(strMOF, Chr(9), vbNullString)
    strMOF = Replace(strMOF, ".\n", "." & Chr(10) & "\n")
    strMOF = Replace(strMOF, ":\n", ":" & Chr(10) & "\n")
    strMOF = Replace(strMOF, ": \n", ":" & Chr(10) & "\n")
    strMOF = Replace(strMOF, "ToSubClass", Chr(10) & "ToSubClass")

    SaveWMIClassDescription = strMOF
    fsoFile.Write strMOF

    fsoFile.Close

    Set fsoFile = Nothing
    Set fso = Nothing
    Set objClass = Nothing
    Set objWMIService = Nothing

End Function


We will not take up the space to show a sample returned by this procedure since it will take up a lot of space to display a fairly representative sample.


As you can see VBA can use WMI to provide an abundance of information. We can also read and write to the Registry, read Event Logs, start and stop processes, change hardware settings, install and uninstall software, and much more. We look forward to discovering more about using the capabilities of VBA and WMI in our next article.


You can download the free sample database, WMISample.zip which contains the code used here at our Gaining Access website.


More Free Downloads:
Report Date Dialog Form in US or UK Version.
Pop-up Calendar
ScopeSight for Access Reports Demo: get the exact data you want on your Access Reports.
Free Church Management Software now with new Contributions management.
Code Samples


Get the Access and Outlook Appointment Manager to manage all of your Outlook Calendar Appointments and Access dated information.


Happy computing,


Patrick (Pat) Wood

Gaining Access

Get Operating System Information Using Microsoft Access VBA and WMI

In our last article we learned that we can access the power of scripting with VBA. This article will show how to get vital information from WMI Classes by listing Class Property names and values.

The Win32_OperatingSystem Class grants us access to a wealth of useful information about the Computer Operating System. It also enables us to set the computer time and safely reboot or shutdown a computer. The image of the Form below demonstrates the information that is available including the Registered User, Windows XP Product Serial Number, the Service Pack Version, the Build Number, Computer Name, Free Physical Memory, etc.

The free sample database containing this form can be downloaded at my Gaining Access Free Downloads page.

On this computer WMI has over 500 Classes that allow me to perform actions using the Class’s Methods and get information from the Class’s Properties. But how do we know what Methods and Properties are available and the meaning of the Property Values? In the form above I converted several numeric values to their values in text so they could be understood. How can we get the information we need about a Class?


One way is by using Microsoft’s online documentation of the Win32 Classes. After the web page loads, we can then scroll down the left pane and select the Win32_OperatingSystem page. This page contains documentation about the Methods and Properties of the Class. We need the information to understand what why the CurrentTimeZone Property for my computer is -240 and what is the meaning of the numbers returned by LargeSystemCache, OSLanguage, OSType, etc.


How Do We Get the Win32_OperatingSystem Information?


It is easy to use VBA to get a list of Property names from a WMI Class. But to get the values of those Properties we need to do the following:


1) Learn the name of the Property that is a “Key” Property (also known as a Qualifier).


2) Get the Property Value from an “instance” of the Win32_OperatingSystem Class key Property.


3) Use the Key Property Name and Value in a WQL Query.


Since your Operating System may be different from mine, you need the Key Property Value to make the code in this article work for you.


The Key to Getting the Data: Get the Key Property Value


First we must learn which Property is the Key Property. Occasionally Microsoft does not provide the full documentation we need which is the case with the Win32_OperatingSystem Class web page. Fortunately there is another way to get both the key Property Name and its Value. We can use the Windows Management Instrumentation Tester (wbemtest.exe). This is a very helpful and powerful tool which can do far more than we have time to mention. In a later article we will discuss some of the many tools that are available.


Use the Windows Management Instrumentation Tester


To open the WMIT we click “Start”, then “Run” and type “wbemtest” at the command prompt. When the dialog appears we click the “Connect” button.


We then change “root\default” to “root\cimv2″ which will connect us to the latest version of the CIM repository on our computer.


We click “Connect” again.


We now need to connect to an instance of the Class so we click the “Enum Instances” button.


A Class Info dialog box appears and we enter the name of our Class, Win32_OperatingSystem, and click “OK”.


The Query Result dialog appears containing a line for each instance of the Class showing the key Property and its value. The Win32_OperatingSystem Class only has one instance. On my computer I see Win32_OperatingSystem.Name=”Microsoft Windows XP Professional|C:\WINDOWS|\Device\Harddisk0\Partition1″. Your Name value may be different but it should start with Win32_OperatingSystem.Name=. This shows us that “Name” is the key Property of the instance.


Next, double-click the instance value line in the Query Result dialog and this will open the Object Editor.


To find the key Property we scroll down until we see the “Name” Property and double-click on that. This opens the Property Editor dialog.


Now we can get the value of the key Property that we need. Right-click on the value in the “Value” box and select “copy”. You can now paste that value somewhere safe so you can have it to use in your code.


Using VBA to Get the Information


Now that we have the key Value we can use the code below to get all of the Property Names and their Values from the Win32_OperatingSystem Class. We start by calling the procedure using the Name Value we got from the Windows Management Instrumentation Tester.


Call GetOperatingSystemInfo(“Microsoft Windows XP Professional|C:\WINDOWS|\Device\Harddisk0\Partition1″)

Sub GetOperatingSystemInfo(strKeyValue As String)

    ' We are using late binding
    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim strWMINamespace As String
    Dim strComputer As String
    Dim strWMIQuery As String

    strComputer = "."

    strWMINamespace = "\root\CIMV2"

    ' We use strKeyValue to specify the value of the Key Property to get the "instance"
    ' of the Win32_OperatingSystem Class in order to get the Property Values
    strWMIQuery = ":Win32_OperatingSystem.Name='" & strKeyValue & "'"

    Set objWMIService = GetObject("winmgmts:\" & strComputer & strWMINamespace & strWMIQuery)

    For Each objItem In objWMIService.Properties_
        Debug.Print objItem.Name & ": " & objItem.Value
    Next

    ' Release Memory
    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing

End Sub


We can also use code to get the Value of the Key Property if we know its name.

Function GetOSName(strClassName As String) As String

    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim strComputer As String
    Dim strOSName As String
    Dim strWQL As String

    strComputer = "."

    strWQL = "SELECT * FROM " & strClassName

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

    Set colItems = objWMIService.ExecQuery(strWQL, , 48)

    For Each objItem In colItems
        ' Get the Value of the Name Property
        strOSName = objItem.Name
    Next

    GetOSName = strOSName

    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing

End Function


Since we can now get the Key Value through code, we can now use these two procedures to list the Properties and Values by modifying our first procedure:

Sub ListWMIPropsAndValues(strClassName As String, strKeyName As String)

    ' We are using late binding
    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object
    Dim strWMINamespace As String
    Dim strComputer As String
    Dim strWMIQuery As String
    Dim strKeyValue As String

    strComputer = "."

    strWMINamespace = "\root\CIMV2"

    ' strKeyValue holds the Key Property's Value so we can get an "instance"
    ' of the Win32 Class in order to get all the Property Values
    strKeyValue = GetOSName(strClassName)

    strWMIQuery = ":" & strClassName & "." & strKeyName & "='" & strKeyValue & "'"

    Set objWMIService = GetObject("winmgmts:\" & strComputer & strWMINamespace & strWMIQuery)

    For Each objItem In objWMIService.Properties_
        Debug.Print objItem.Name & ": " & objItem.Value
    Next

    ' Release Memory
    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing

End Sub


Now we can list all of the Property Names and Values without knowing the key Value since we are getting that through code. We call the procedure like this:

Call ListWMIPropsAndValues(“Win32_OperatingSystem”, “Name”)

We have more good news: You can easily copy and modify these Procedures to get information from other WMI Classes. Once you discover the name of the key Property you can change the code accordingly.


We used the code here as part of a couple of procedures to fill the Form you saw at the beginning of this article with data. You can download the free sample database, WMISample.zip.


We thank Mitch Tulloch who wrote a very helpful article on this subject.


We look forward to discovering more ways to access WMI with VBA in our next article.


You can download the free Report Date Dialog Form in the US or UK Version at our Gaining Access website.


More Free Downloads:
Pop-up Calendar
ScopeSight for Access Reports Demo: get the exact data you want on your Access Reports.
Free Church Management Software now with new Contributions management.
Code Samples


Get the Access and Outlook Appointment Manager to manage all of your Outlook Calendar Appointments and Access dated information.


Happy computing,


Patrick (Pat) Wood

Gaining Access

Using the Power of VBScripts and WMI in Microsoft Access VBA

Lately I have been exploring the powerful capabilities of Scripting and WMI. It was very exciting to discover that it is very easy to convert VBScript for WMI into VBA code that works just like the scripts. While there are a few VBSript functions that cannot be used in VBA, most scripts can be easily modified to run from Access or other Office Applications. Why am I excited? With VBA and WMI you can do many things that are not possible using Windows API’s. WMI is so powerful one needs to be careful not to do some serious damage to your local Computer, a remote PC. or Windows Server!

Why is WMI so powerful? “…WMI is the core management-enabling technology built into Windows 2000, Windows XP, and the Windows Server 2003 family of operating systems. Based on industry standards overseen by the Distributed Management Task Force (DMTF), WMI is the instrumentation and plumbing through which all—well, almost all—Windows resources can be accessed, configured, managed, and monitored.” The last sentence is the one that lays out the power of WMI, which you, yes you, have in your VBA typing fingertips!


Using VBA and WMI here are a few of the things you can do on Local or Remote Computers:

  • Manage Users and Group Policies
  • Read and save Event Logs to files
  • Get the size of a hard drive’s free Memory
  • Get the Version of Microsoft Office
  • Get the attributes of Printers
  • Get the Operating System Service Pack Version (CSDVersion–ServicePackLast)
  • Get the Operating System Name
  • Get the Operating System Version Number
  • Get the Operating System Build Number
  • Windows Operating System Product/Serial Number
  • Get Scheduled Jobs
  • Count Running Processes
  • List Running Processes
  • Terminate Processes
  • Delete software
  • Install software
  • Upgrade software
  • List all Windows installed software
  • List Microsoft software Product IDs
  • Get the Registered User


In fact, the greatest difficulty with using WMI is there are thousands of Properties and Methods that are available for you to access. WMI has Classes, Properties, and Methods and its own VBScript query dialect called WQL. WMI uses the Common Information Model (CIM) to access information and perform actions. The CIM grants us access to almost everything about a PC. You can learn more about CIM here.


The following is an example of VBA code using WMI. This code gets the ProcessorID of a local computer which can be very useful.  This code can be used as a template of sorts to access much of the information you will want to get using WMI.

Function ProcessorID() As String

    ' Using late binding to avoid a Reference problem
    Dim strComputer As String
    Dim objWMIService As Object
    Dim colItems As Object
    Dim objItem As Object

    strComputer = "."

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

    Set colItems = objWMIService.ExecQuery( _
        "SELECT * FROM Win32_Processor", , 48)

    For Each objItem In colItems
        ProcessorID = Nz(objItem.ProcessorID, 0)
    Next

    Set objItem = Nothing
    Set colItems = Nothing
    Set objWMIService = Nothing

End Function

How does the code work?

After declaring some variables, we create an instance of a WMI Object using GetObject(“winmgmts:”)

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

We use winmgmts, the CIM Object Manager, to access the “root” (“\root\cimv2″) of the CIM library. If we are accessing a remote computer “{impersonationLevel=impersonate}!\” grants us access if we have the right security credentials.

The strComputer variable is given a value of “.” when we are accessing the local computer. If we want to access a remote computer, instead of using “.” we need to use the path and name of the remote computer: GetObject(“winmgmts:\TargetComputer”) or GetObject(“winmgmts:\DomainName\TargetComputer”).


Next we instantiate a collection of properties of the WMI Win32_Processor Class.

Set colItems = objWMIService.ExecQuery( _
    "SELECT * FROM Win32_Processor", , 48)

We use a WQL query to select all the Properties in the Class. You can learn more about WQL, the WMI Query Language, here.

Finally we get the Processor ID serial number which is actually a string.

    For Each objItem In colItems
        ProcessorID = Nz(objItem.ProcessorID, 0)
    Next

The ProcessorID can help provide some level of security, enabling us to know if the database has been copied to a different computer. If we have already saved the ProcessorID to a Custom Database Property we can check to see if the value has changed using the following code which can be called by the AutoExec Macro or a Splash Form. Warning: Make backup copy of your database files before using the following code.

Function StartSafe() As Boolean
    Dim strProcessorID As String

    ' Get the stored ProcessorID from
    ' the custom Database property
    strProcessorID = GetDBPropValue("dbPrpProcessorID")

    If strProcessorID = ProcessorID Then
        StartSafe= True
    Else
        StartSafe= False
        ' The database has been copied to an unauthorized computer!
        ' Delete the Back End Database to protect your data
        Kill (CurrentProject.Path & "\BackEndDB.mdb")
        ' If this is the back end add code to Delete all tables
        ' Add code to Delete all Modules
        DoCmd.Quit
    End If
End Function

In our next article we will learn more about using the power of WMI with VBA.

I still have a lot to learn about VBScript and WMI. I would appreciate any corrections if I make an error in these posts.


To download the code used in this article visit our Free CodeSamples Page.


You can download the completed and free Report Date Dialog Form in the US or UK Version at our Gaining Access website.


More Free Downloads:
Pop-up Calendar
ScopeSight for Access Reports Demo: get the exact data you want on your Access Reports.
Free Church Management Software now with new Contributions management.
Code Samples


Get the Access and Outlook Appointment Manager to manage all of your Outlook Calendar Appointments and Access dated information.


Happy computing,


Patrick (Pat) Wood

Gaining Access