Überprüfen von Werten eines Objekts

  • Moin,

    ich schreibe gerade ein Tool zur Abfrage von System- und Hardwareinformationen mittels WMI. Allerdings habe ich das Problem, dass manche Werte der Klassen nicht in allen Betriebssystemen vorhanden ist. So kann ich z.B. unter Windows 7 die HDD-Serial abfragen, unter Windows XP crashed das komplette Script mit der Rückgabe weiter unten.

    Gibt es eine Möglichkeit, vor der Abfrage des Wertes zu überprüfen, ob dieser überhaupt vorhanden ist?
    Hier die Fehlermeldung:

    Zitat

    ==> The requested action with this object has failed.:
    $lResult = "HDD" & $i & "SerialNumber" & "|" & $objItem.SerialNumber
    $lResult = "HDD" & $i & "SerialNumber" & "|" & $objItem.SerialNumber^ ERROR
    >Exit code: 1

    Und hier der Ausschnitt des Codes:

    [autoit]


    Func _EnumerateHardwareWmi(ByRef $lArray) ;
    $wbemFlagReturnImmediately = 0x10
    $wbemFlagForwardOnly = 0x20
    $colItems = ""
    $strComputer = "localhost"

    [/autoit][autoit][/autoit][autoit]

    $i = 0
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    If IsObj($colItems) then
    For $objItem In $colItems
    $i += 1
    $lResult = "HDD" & $i & "InterfaceType" & "|" & $objItem.InterfaceType
    _Array2DAdd($lArray, $lResult)
    $lResult = "HDD" & $i & "SerialNumber" & "|" & $objItem.SerialNumber
    _Array2DAdd($lArray, $lResult)
    $lResult = "HDD" & $i & "MediaType" & "|" & $objItem.MediaType
    _Array2DAdd($lArray, $lResult)
    $lResult = "HDD" & $i & "Model" & "|" & $objItem.Model
    _Array2DAdd($lArray, $lResult)

    next
    Else
    _WriteDebug('ERR ;_EnumerateInstalledSoftwareWmi;No WMI Objects Found for class: "Win32_DiskDrive"')
    SetError(1)
    Endif

    [/autoit]

    Danke Euch schon mal im Voraus.

    • Offizieller Beitrag

    So habe ich es in meinem ComputerInfo gemacht:

    Spoiler anzeigen
    [autoit]


    Func _CI_GetHarddrives($strComputer = '.')
    Local $aReturn[1][8] = [[ _
    'Bezeichnung:', 'Größe:', 'Anschluss:', 'Bytes/Sektor:', 'Anzahl der Sektoren:', _
    'PNPDeviceID:', 'Status:', 'Seriennr. (Hardware):']]
    Local $x = 0, $objWMIService, $colItems
    $objWMIService = ObjGet('winmgmts:\\' & $strComputer & '\root\cimv2')
    If Not IsObj($objWMIService) Then Return SetError(1, 0, 0)
    $colItems = $objWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive', 'WQL', 0x30)
    If IsObj($colItems) Then
    For $objItem In $colItems
    $x += 1
    ReDim $aReturn[$x + 1][8]
    $aReturn[$x][0] = $objItem.Model
    $aReturn[$x][1] = _ByteAutoSize($objItem.Size)
    $aReturn[$x][2] = $objItem.InterfaceType
    $aReturn[$x][3] = $objItem.BytesPerSector
    $aReturn[$x][4] = $objItem.TotalSectors
    $aReturn[$x][5] = $objItem.PNPDeviceID
    $aReturn[$x][6] = $objItem.Status
    Switch @OSVersion
    Case 'WIN_VISTA', 'WIN_7'
    If Number($objItem.SerialNumber) > 0 Then
    $aReturn[$x][7] = $objItem.SerialNumber & ' ("' & _CI_SerialToString($objItem.SerialNumber) & '")'
    Else
    $aReturn[$x][7] = 'nicht vorhanden'
    EndIf
    Case Else
    $aReturn[$x][7] = 'Wird von ' & @OSVersion & ' nicht unterstützt!'
    EndSwitch
    Next
    EndIf
    Return $aReturn
    EndFunc ;==>_CI_GetHarddrives

    [/autoit] [autoit][/autoit] [autoit]

    Func _CI_SerialToString($sSerial)
    Local $sOut = ''
    For $i = 1 To StringLen($sSerial) Step 2
    $sOut &= Chr(Dec(StringMid($sSerial, $i, 2)))
    Next
    Return $sOut
    EndFunc ;==>_CI_SerialToString

    [/autoit]
  • Danke Oscar für Dein Script.

    Allerdings hilft dies nur, wenn man im Voraus weiß, welche Werte in welchen OS nicht vorhanden sind. Mir ging es eher generell um eine Überprüfung, ob dieser Wert unter dem ausführenden OS vorhanden ist und falls nicht, dieser Wert gar nicht erst abgefragt wird.
    Ich weiß ja leider nicht, auf welchen OS oder SP Leveln das Script ausgeführt wird.

  • Du kannst dir dafür einen eigenen Errorhandler bauen mit

    [autoit]

    ObjEvent("AutoIt.Error", "MyErrFunc")
    ;...

    [/autoit][autoit][/autoit][autoit]

    Func MyErrFunc()
    MsgBox(0, "", "Fehler beim kommunizieren mit dem Objekt")
    EndFunc

    [/autoit]
  • Du kannst dir dafür einen eigenen Errorhandler bauen mit

    Genau darauf bin ich auch gerade gestoßen. :D Aber vielen Dank für den Hinweis.

    Gibt es eine Möglichkeit das Item, welches den Fehler ausgelöst hat auszugeben? Also in meinem Fall "$objItem.SerialNumber"?

  • Wir jetzt über COM Error abgefangen und in ulqadbg.log ausgegeben

    [autoit]

    $oMyError = ObjEvent("AutoIt.Error","_MyErrFunc") ; Initialize a COM error handler

    [/autoit][autoit]

    Func _MyErrFunc() ; self defined error handler

    [/autoit][autoit][/autoit][autoit]

    _WriteDebug("ERR ;MyErrFunc;COM error: ")
    _WriteDebug("ERR ;MyErrFunc;+> err.description is: " & $oMyError.description)
    _WriteDebug("ERR ;MyErrFunc;+> err.windescription:" & $oMyError.windescription)
    _WriteDebug("ERR ;MyErrFunc;+> err.number is: " & hex($oMyError.number,8))
    _WriteDebug("ERR ;MyErrFunc;+> err.lastdllerror is: " & $oMyError.lastdllerror)
    _WriteDebug("ERR ;MyErrFunc;+> err.scriptline is: " & $oMyError.scriptline)

    [/autoit][autoit][/autoit][autoit]

    Local $err = $oMyError.number
    If $err = 0 Then $err = -1

    Endfunc

    [/autoit][autoit]

    Func _WriteDebug($lParam) ; $lType, $lFunc, $lString) ; creates debuglog for analyzing problems
    local $lArray[4]
    local $lResult

    local $lArrayTemp = StringSplit($lParam, ";")
    if @error Then
    Dim $lArrayTemp[4]
    ;~ $lArrayTemp[0] bleibt leer
    $lArrayTemp[1] = "ERR "
    $lArrayTemp[2] = "_WriteDebug"
    $lArrayTemp[3] = "StringSplit failed"
    EndIf

    [/autoit][autoit][/autoit][autoit]

    for $i = 1 to $lArrayTemp[0]
    if $i > 1 Then $lResult = $lResult & @CRLF
    $lResult = $lResult & $lArray[$i] & $lArrayTemp[$i]
    Next

    FileWriteLine($gDbgFile, @MDAY & @MON & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC & " - " & $lArrayTemp[1] & " - " & $lArrayTemp[2] & " - " & $lArrayTemp[3])
    EndFunc

    [/autoit]

    Wenn mir jetzt noch einer die Frage aus meinem letzten Posting beantworten kann, bin ich glücklich. ;)

  • Würde dir lieber eine Alternative vorschlagen.
    Damit kannst du die existieren Property-Namen einer WMI-Klasse bekommen:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    Global $oWMI = ObjGet("winmgmts:\\localhost\")

    [/autoit] [autoit][/autoit] [autoit]

    $aProperties = WMIClassGetProperties($oWMI, "Win32_BIOS")
    If Not @error Then _ArrayDisplay($aProperties, "Eigenschaften von Win32_BIOS")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func WMIClassGetProperties(ByRef $oWMI, Const $sClassName)
    ; By AspirinJunkie
    Local $sRet = ""
    Local $oClass = $oWMI.Get($sClassName)
    If @error Then Return SetError(1, @error, "")

    [/autoit] [autoit][/autoit] [autoit]

    For $i In $oClass.Properties_()
    $sRet &= $i.Name & "|"
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Return StringSplit(StringTrimRight($sRet, 1), "|", 2)
    EndFunc ;==>WMIClassGetProperties

    [/autoit]