Jump to content

Custom WMI Class UDF


weaponx
 Share

Recommended Posts

The goal of this UDF when I started was to be able to make a custom class in AutoIt (technically a struct since you can't define your own functions). Unfortunately, I ran into some roadblocks. Even though it doesn't have the full functionality I wanted, its still pretty interesting.

Usage:

  • Call Class_Create() to create a new WMI class with a name you provide
  • Use Class_AddProperty() to add properties to your class (One property must be a unique key)
  • Class_Spawn will create an ISWbemObjectEx object which you can then add data to
  • Class_Commit will push the new instance of your class into WMI
  • Collection_Create will gather all of the instances of your class into an ISWbemObjectSet object
This all works fine, the limitation is due to the fact that you cannot control the sorting of the collection, which means when you use For...In...Next to loop through your collection, the data is in a pretty much random order. I even tried adding a unique key to each instance, hoping it would sort by that key. Wrong.

The other option would be to run a WQL query after all of your instances are commited, but here again we hit a roadblock. Standard WQL does not support "ORDER BY" syntax, so your data is still totally random. There does exist an extended WQL syntax but it is part of Microsoft System Management Server:

http://msdn.microsoft.com/en-us/library/ms815501.aspx

What I ended up with is an overly complex Scripting.Dictionary object. Good times.

;WMI Custom Class v1.0
;Author: WeaponX (ghostofagoodthing@gmail.com)

#cs ===============================================================================
Class_AddProperty
Class_Commit
Class_Create
Class_Debug
Class_Delete
Class_Exists
Class_Properties
Class_Release
Class_Spawn
Collection_Count
Collection_Create
Collection_Debug
#ce ===============================================================================

;Define the valid CIM types of a property value.
Const $wbemCimtypeSint16 = 2 ;0x2 - Signed 16-bit integer
Const $wbemCimtypeSint32 = 3 ;0x3 - Signed 32-bit integer
Const $wbemCimtypeReal32 = 4 ;0x4 - 32-bit real number
Const $wbemCimtypeReal64 = 5 ;0x5 - 64-bit real number
Const $wbemCimtypeString = 8 ;0x8 - String datatype
Const $wbemCimtypeBoolean = 11 ;0xB - Boolean value
Const $wbemCimtypeObject = 13 ;0xD - CIM object
Const $wbemCimtypeSint8 = 16 ;0x10 - Signed 8-bit integer
Const $wbemCimtypeUint8 = 17 ;0x11 - Unsigned 8-bit integer
Const $wbemCimtypeUint16 = 18 ;0x12 - Unsigned 16-bit integer
Const $wbemCimtypeUint32 = 19 ;0x13 - Unsigned 32-bit integer
Const $wbemCimtypeSint64 = 20 ;0x14 - Signed 64-bit integer
Const $wbemCimtypeUint64 = 21 ;0x15 - Unsigned 64-bit integer
Const $wbemCimtypeDatetime = 101 ;0x65 - Date/time value
Const $wbemCimtypeReference = 102 ;0x66 - Reference to a CIM object
Const $wbemCimtypeChar16 = 103 ;0x67 - 16-bit character

;Uncomment the function at the bottom to use this, Class_Exists always throws an error if the class is not found
;$oMyError = ObjEvent("AutoIt.Error","ComErrHandler") 

;Force deletion of a class, typically used if your script hangs before Class_Release is called
;ConsoleWrite(Class_Exists("UserInfo"))
;Class_Delete("UserInfo")
;Exit

$objClass = Class_Create("UserInfo")
If @Error Then
    ConsoleWrite("Error creating class" & @CRLF)
Else
    ConsoleWrite("Class created" & @CRLF)
EndIf

Class_AddProperty($objClass, "SS", $wbemCimtypeUint32, true)
Class_AddProperty($objClass, "FirstName", $wbemCimtypeString, true) ;At least one property MUST be a unique key
Class_AddProperty($objClass, "LastName", $wbemCimtypeString)

;Dump class properties to console (Names & Types)
Class_Debug($objClass)

;Create new instance of your class (sort of like the "new" operator)
$objNewInst = Class_Spawn($objClass) ;Returns ISWbemObjectEx Object
$objNewInst.SS = 023456789
$objNewInst.FirstName = "John"
$objNewInst.LastName = "Smith"
Class_Commit($objNewInst) ;Important

;Create new instance of your class (sort of like the "new" operator)
$objNewInst = Class_Spawn($objClass) ;Returns ISWbemObjectEx Object
$objNewInst.SS = 123456789
$objNewInst.FirstName = "Jack"
$objNewInst.LastName = "Sparrow"
Class_Commit($objNewInst) ;Important

;Create new instance of your class (sort of like the "new" operator)
$objNewInst = Class_Spawn($objClass) ;Returns ISWbemObjectEx Object
$objNewInst.SS = 323456789
$objNewInst.FirstName = "Jack"
$objNewInst.LastName = "Sbarro"
Class_Commit($objNewInst) ;Important

;Retrieve all instances of your class into a collection (unknown order)
$Nodes = Collection_Create($objClass) ;Returns ISWbemObjectSet Object

;Dump class properties to console (Names & Types)
Collection_Debug($Nodes)

;CLEANUP
$result = Class_Release($objClass)
If @Error Then
    ConsoleWrite("Delete failed" & @CRLF)
Else
    ConsoleWrite("Delete succeeded" & @CRLF)
EndIf



#cs ===============================================================================
FUNCTIONS
#ce ===============================================================================

#cs ===============================================================================
Function: Class_AddProperty
Parameters:
    $oClass* - ISWbemObjectEx - Class object
    $sPropertyName - String - Name of property to add
    $iCimType - Integer - Property type (see defined constants)
    $bKey - Boolean - Determines if the parameter is a key
    $bIsArray - Boolean - Determines if parameter is an array
Return:
Errors:
    None
Notes:
    None
#ce ===============================================================================
Func Class_AddProperty(ByRef $oClass, $sPropertyName, $iCimType, $bKey = true, $bIsArray = false)
    ;Add property
    $oClass.Properties_.add($sPropertyName, $iCimType)
    
    If $bKey Then
        ;Make the property a key property 
        $oClass.Properties_($sPropertyName).Qualifiers_.Add("key", TRUE)
    EndIf
    
    Class_Commit($oClass)
EndFunc

#cs ===============================================================================
Function: Class_Commit
Parameters:
    $oClass* - ISWbemObjectEx - Class object
Return: 
    None  
Errors:
    None
Notes:
    None
#ce ===============================================================================
Func Class_Commit(ByRef $oClass)
    Local $oInstancePath = $oClass.Put_
    ;ConsoleWrite($oInstancePath.Path & @CRLF)
EndFunc

#cs ===============================================================================
Function: Class_Create
Parameters:
    $sClassName - String - Identifier name for your class
Return: 
    ISWbemObjectEx Object    
Errors:
    1 - Class already exists
    2 - Error creating ISWbemServicesEx Object
Notes:
    None
#ce ===============================================================================
Func Class_Create($sClassName)
    
    ;If class already exists, just spawn a new instance of it, otherwise create the new class
    If Class_Exists($sClassName) Then
        $oClass = ObjGet("Winmgmts:root\default:" & $sClassName)
        ConsoleWrite("Class doesn't yet exist" & @CRLF)
    Else
        Local $objSWbemService = ObjGet("Winmgmts:root\default") ;ISWbemServicesEx Object
        If @ERROR Then Return SetError(2,0,0)
        
        $oClass = $objSWbemService.Get() ;ISWbemObjectEx Object
        $oClass.Path_.Class = $sClassName        
        
        ConsoleWrite("Class already exists" & @CRLF)
        ;Return SetError(1,0,0)        

    EndIf

    ; Release SwbemServices object
    $objSWbemService = ""
    
    Return $oClass
EndFunc

#cs ===============================================================================
Function: Class_Debug
Parameters:
    $oClass* - ISWbemObjectEx - Class object
Return: 
    ISWbemPropertySet Collection Object
Errors:
    1 - Not an object / not a ISWbemObjectEx object
Notes:
    None
#ce ===============================================================================
Func Class_Debug(ByRef $oClass)
    If IsObj($oClass) AND ObjName($oClass) = "ISWbemObjectEx" Then
        $oProperties = Class_Properties($oClass)
        ConsoleWrite("+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Class Properties" & @CRLF)
        ConsoleWrite("Count: " & $oProperties.Count & @CRLF)
        For $oProperty in $oProperties
            ConsoleWrite("Name: " & $oProperty.Name & " Type: " & $oProperty.CIMType & @CRLF)
        Next
        ConsoleWrite(@CRLF)
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ----------------------------------------------------------------
Function: Class_Delete
Parameters:
    $sClassName - String - Identifier name for your class
Return: 
    None    
Errors:
    1 - Not an object / not a ISWbemObjectEx object
Notes:
    CAUTION - I don't know what this will do to non-user created classes,
    call this if your script crashed without calling Class_Release
#ce ----------------------------------------------------------------
Func Class_Delete($sClassName)
    ;$objSWbemService = ObjGet("Winmgmts:root\default") ;ISWbemServicesEx
    ;ConsoleWrite(ObjName($objSWbemService) & @CRLF)
    ;$objSWbemService.Delete($sClassName)
    
    If Class_Exists($sClassName) Then
        $objSWbemService = ObjGet("Winmgmts:root\default") ;ISWbemServicesEx
        ;ConsoleWrite(ObjName($objSWbemService) & @CRLF)
        $objSWbemService.Delete($sClassName)
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ===============================================================================
Function: Class_Exists
Parameters:
    $sClassName - String - Identifier name for your class
Return: 
    True/False
Errors:
    None
Notes:
    None
#ce ===============================================================================
Func Class_Exists($sClassName)
    ObjGet("Winmgmts:root\default:" & $sClassName)
    ;Local $objSWbemService = ObjGet("Winmgmts:root\default")
    ;$oClass = $objSWbemService.Get($sClassName) ;ISWbemObjectEx Object

    If NOT @ERROR Then
        Return True
    Else
        Return False
    EndIf
EndFunc

#cs ===============================================================================
Function: Class_Properties
Parameters:
    $oClass* - ISWbemObjectEx - Class object
Return: 
    ISWbemPropertySet Collection Object
Errors:
    1 - Not an object / not a ISWbemObjectEx object
Notes:
    None
#ce ===============================================================================
Func Class_Properties(ByRef $oClass)
    If IsObj($oClass) AND ObjName($oClass) = "ISWbemObjectEx" Then
        Local $oProperties = $oClass.Properties_
        ;ConsoleWrite(ObjName($oProperties) & @CRLF)
        Return $oProperties ;ISWbemPropertySet Object
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ----------------------------------------------------------------
Function: Class_Release
Parameters:
    $oClass - ISWbemObject Object
Return: 
    None    
Errors:
    1 - Not an object / not a ISWbemObjectEx object
Notes:
    None
#ce ----------------------------------------------------------------
Func Class_Release(ByRef $oClass)
    If IsObj($oClass) AND ObjName($oClass) = "ISWbemObjectEx" Then 
        $oClass.Delete_()
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ===============================================================================
Function: Class_Spawn
Parameters:
    $oClass* - ISWbemObjectEx - Class object
Return: 
    ISWbemObjectEx Object    
Errors:
    1 - Error creating ISWbemServicesEx Object
Notes:
    None
#ce ===============================================================================
Func Class_Spawn(ByRef $oClass)
    Local $oNewInst = ObjGet("Winmgmts:root\default:" & $oClass.Path_.Class)
    If @ERROR Then 
        Return SetError(1,0,0)
    Else
        $oNewInst = $oNewInst.SpawnInstance_
        Return $oNewInst
    EndIf
EndFunc

#cs ===============================================================================
Function: Collection_Count
Parameters:
    $oCollection* - ISWbemObjectSet - Collection object
Return: 
    Object count
Errors:
    1 - Not an object / not a ISWbemObjectSet object
Notes:
    None
#ce ===============================================================================
Func Collection_Count(ByRef $oCollection)
    If IsObj($oCollection) AND ObjName($oCollection) = "ISWbemObjectSet" Then 
        Return $oCollection.Count
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ===============================================================================
Function: Collection_Create
Parameters:
    $oClass* - ISWbemObjectEx - Class object
Return: 
    ISWbemObjectSet Collection Object
Errors:
    1 - Not an object / not a ISWbemObjectEx object
Notes:
    None
#ce ===============================================================================
Func Collection_Create(ByRef $oClass)
    If IsObj($oClass) AND ObjName($oClass) = "ISWbemObjectEx" Then
        ;Return $oClass.ExecQuery
        Return $objClass.Instances_ ;SWbemObjectSet Object
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs ===============================================================================
Function: Collection_Debug
Parameters:
    $oCollection* - ISWbemObjectSet - Collection object
Return: 
    None
Errors:
    1 - Not an object / not a ISWbemObjectSet object
Notes:
    Dump collection and all properties of its sub objects to the console (PHP print_r style)
#ce ===============================================================================
Func Collection_Debug(ByRef $oCollection)
    If IsObj($oCollection) AND ObjName($oCollection) = "ISWbemObjectSet" Then 
        ConsoleWrite("+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Collection Instances" & @CRLF)
        ConsoleWrite("Count: " & Collection_Count($oCollection) & @CRLF)
        
        For $oObject in $oCollection
            ;ConsoleWrite($oObject.ItemIndex & @CRLF)
            For $oProperty in Class_Properties($oObject)
                ConsoleWrite("[" & $oProperty.Name & "] => " & $oProperty.Value & @CRLF)
            Next
            ConsoleWrite("Absolute path: " & $oObject.Path_.Path & @CRLF) ;WMI Absolute Path
            ConsoleWrite("Relative path: " & $oObject.Path_.RelPath & @CRLF) ;WMI Relative Path
            ConsoleWrite(@CRLF)
        Next
    Else
        Return SetError(1,0,0)
    EndIf
EndFunc

#cs
Func ComErrHandler()
    $HexNumber = Hex($oMyError.number, 8)
    MsgBox(0, "COM Error", "COM Error Details:" & @CRLF & @CRLF & _
            "err.description is: " & @TAB & $oMyError.description & @CRLF & _
            "err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _
            "err.number is: " & @TAB & $HexNumber & @CRLF & _
            "err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
            "err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _
            "err.source is: " & @TAB & $oMyError.source & @CRLF & _
            "err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _
            "err.helpcontext is: " & @TAB & $oMyError.helpcontext _
            )
    SetError(1)
EndFunc  ;==>ComErrHandler
#ce
Edited by weaponx
Link to comment
Share on other sites

@weaponx

Very interesting.

Good to know, using the cmd -> wbemtest util, you can create WMI classes as well.

Good job !!

regards

ptrex

I don't think i've ever actually had to use that program but it looks helpful. I was really after a linked list or stack type of structure which has proven difficult in AutoIt without the "New" and "Delete" operators. In the end I think an ADO Recordset is my next step, but SQLite may just be the best solution.

Link to comment
Share on other sites

Excellent ! will try it out !

so i'f i understand well, this class can then be accessed by wmi without any problem ?

this could be very useful for remote custom classes.

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Link to comment
Share on other sites

Excellent ! will try it out !

so i'f i understand well, this class can then be accessed by wmi without any problem ?

this could be very useful for remote custom classes.

As long as you don't call Class_Release() or Class_Delete() I believe it is permanently added to WMI. I haven't tested that far into though. I don't see why you wouldn't be able to access the custom class remotely.

Link to comment
Share on other sites

yes there is two types : temporary or permanent providers (or consumers, didn't remember the term)

i would like to be able to access to autoit information by wmi, could be useful on a big parc of machines.

btw : i replaced root\default to root\cimv2 for wmic (wmi in command line) can work without be configured more, and any other wmi request that target root\cimv2 by default.

@ptrex :

i know wbemtest, but when i see all of the menu and options, i don't want to go further in it. So didn't know that can create classes. Thx for this suggestion :)

Edited by arcker

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Link to comment
Share on other sites

Link to comment
Share on other sites

it works, but my need would be to have an interactive class ( as Win32_Process ), that when you query it, it exec a method and return the result, and the refresh is done at every query...

i've search on google-my-friend for examples in vbscript but didn't find anything...

i'm afraid that this method of class creation is limited to "simple" classes.

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Link to comment
Share on other sites

  • 1 year later...
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...