Multiple Results of WMI with error handling

Hey Guys/Ladies!

I need to write up client relevance to evaluate and retrieve wmi results from encryptablevolume of WMIs root\CIMv2\Security\MicrosoftVolumeEncryption for BitLocker evaluation. The data needs to be in the format below so that it can be ingested into another application.

DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=0

The current relevance statement I have.

Q: ((selects ("DeviceID from win32_EncryptableVolume") of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"), (selects ("ProtectionStatus from win32_EncryptableVolume") of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"), (selects ("volumetype from win32_EncryptableVolume") of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"))
E: The expression could not be evaluated: Windows Error 0x80041017: Invalid query

The issue is that when an endpoint has never turned on bitlocker, the only value needed that exists is the DeviceID. I have attempted itemizing the results and adding some if then else clauses to check for existence before querying the wmi for values but I am not able to get past incompatible types when using if then else with itemized multiple sting values. Any Ideas?

If I had a quarter for every time someone posted a question about WMI giving funky results when inspecting BitLocker statusā€¦ Iā€™d have like 75 cents.

Iā€™m not sure I can explain why youā€™re not seeing results for anything other than DeviceID. On my test VM, which has never had BitLocker enabled, I get results for those, and more:

q: selects ("* from win32_EncryptableVolume") of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
A: ConversionStatus=0
A: DeviceID=\\?\Volume{ce46d318-04f1-47ae-a761-67eb5a4407a7}\
A: DriveLetter=C:
A: EncryptionMethod=0
A: IsVolumeInitializedForProtection=False
A: PersistentVolumeID=
A: ProtectionStatus=0
A: VolumeType=0
T: 67.964 ms
I: plural wmi select

Regardless, it is possible to do what youā€™re asking in your question. The issue youā€™re running into about incompatible types is that WMI queries return an object of type ā€œwmi select,ā€ not ā€œstring.ā€ Youā€™ll have to cast them explicitly as string if you want to do your own comparison. First, I want to point out that, since youā€™re querying the same WMI namespace in each one, you can simply your statement a little by using of it in your tuple:

q: (selects "DeviceID from win32_EncryptableVolume" of it, selects "ProtectionStatus from win32_EncryptableVolume" of it, selects "VolumeType from win32_EncryptableVolume" of it) of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
A: DeviceID=\\?\Volume{ce46d318-04f1-47ae-a761-67eb5a4407a7}\, ProtectionStatus=0, VolumeType=0
T: 55.903 ms
I: plural ( wmi select, wmi select, wmi select )

Now, to incorporate giving an answer if for whatever reason there isnā€™t one. In the below statement Iā€™m using the pipe operator, |, to indicate what it should report if thereā€™s no answer. In order to do that, I had to change the plural selects (which would return no value), to the singular select, which lets us specify what to do in case no value is returned. In this example, I assume you want VolumeType=0 and ProtectionStatus=0, but you could make it return whatever string you wanted.

q: (select "DeviceID from win32_EncryptableVolume" of it as string, select "ProtectionStatus from win32_EncryptableVolume" of it as string | "ProtectionStatus=0" , select "VolumeType from win32_EncryptableVolume" of it as string | "VolumeType=0") of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
A: DeviceID=\\?\Volume{ce46d318-04f1-47ae-a761-67eb5a4407a7}\, ProtectionStatus=0, VolumeType=0
T: 29.056 ms
I: plural ( string, string, string )
2 Likes

@WizKid Please use the CODE tag when posting relevance. It is a button in the toolbar and looks like </>

Nice moves there @alinder but I got hit with a plural issue on my system with 2 drives.

Try keeping the WMI stuff together as an object and then pulling apart and error catching the missing elements.

q: (property "DeviceID" of it as string| "None", property "ProtectionStatus" of it as string| "None", property "VolumeType" of it as string| "None") of select objects "DeviceID, ProtectionStatus, VolumeType from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"

2 Likes

Nice, thatā€™s much better than mine!

1 Like

@alinder Thank you, I spent a few days on the BigFix forum but I am unable to find an example that checks for the existence of the actual object. Most examples are exists WMI or exists WMI ā€œWMI Class hereā€. I have been unable to find anything checking for object existence.

@brolly33 Thank you for the heads up. Will do next time. This is what I have so far but if the object does not exist in the WMI it still throws the same issue. If results are not available, the whole query fails.

Q: (property "DeviceID" of it as string | "Device ID Unavailable", property "ProtectionStatus" of it as string | "Protection Status Unavailable", property "VolumeType" of it as string | "Volume Type Unavailable", property "IsVolumeInitializedForProtection" of it as string | "Is Volume Initialized For Protection Unavailable", property "EncryptionMethod" of it as string | "Encryption Method Unavailable") of select objects "DeviceID, ProtectionStatus, VolumeType, IsVolumeInitializedForProtection, EncryptionMethod from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
E: The expression could not be evaluated: Windows Error 0x80041017: Invalid query

Any ideas?

So, for whatever reason your systemā€™s WMI doesnā€™t seem to be returning the same properties as @alinder or @brolly33. One way to see all of the properties that your system does return is via

q: properties of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
A: __PATH=\\JASON-LAPTOP\root\CIMv2\Security\MicrosoftVolumeEncryption:Win32_EncryptableVolume.DeviceID="\\\\?\\Volume{21bbf6e2-dcd3-4b79-a6d9-7c4e32b07152}\\"
A: __NAMESPACE=root\CIMv2\Security\MicrosoftVolumeEncryption
A: __SERVER=JASON-LAPTOP
A: __DERIVATION
A: __PROPERTY_COUNT=8
A: __RELPATH=Win32_EncryptableVolume.DeviceID="\\\\?\\Volume{21bbf6e2-dcd3-4b79-a6d9-7c4e32b07152}\\"
A: __DYNASTY=Win32_EncryptableVolume
A: __SUPERCLASS
A: __CLASS=Win32_EncryptableVolume
A: __GENUS=2
A: ConversionStatus=1
A: DeviceID=\\?\Volume{21bbf6e2-dcd3-4b79-a6d9-7c4e32b07152}\
A: DriveLetter=D:
A: EncryptionMethod=6
A: IsVolumeInitializedForProtection=True
A: PersistentVolumeID={13C7219B-85F1-4889-9BBA-079A0E38DFCE}
A: ProtectionStatus=1
A: VolumeType=1
A: __PATH=\\JASON-LAPTOP\root\CIMv2\Security\MicrosoftVolumeEncryption:Win32_EncryptableVolume.DeviceID="\\\\?\\Volume{c4a1ea59-4fd2-4a8f-aa09-fd1749349bd6}\\"
A: __NAMESPACE=root\CIMv2\Security\MicrosoftVolumeEncryption
A: __SERVER=JASON-LAPTOP
A: __DERIVATION
A: __PROPERTY_COUNT=8
A: __RELPATH=Win32_EncryptableVolume.DeviceID="\\\\?\\Volume{c4a1ea59-4fd2-4a8f-aa09-fd1749349bd6}\\"
A: __DYNASTY=Win32_EncryptableVolume
A: __SUPERCLASS
A: __CLASS=Win32_EncryptableVolume
A: __GENUS=2
A: ConversionStatus=1
A: DeviceID=\\?\Volume{c4a1ea59-4fd2-4a8f-aa09-fd1749349bd6}\
A: DriveLetter=C:
A: EncryptionMethod=6
A: IsVolumeInitializedForProtection=True
A: PersistentVolumeID={8F28FEE2-12E8-454A-9831-C6C28961B15D}
A: ProtectionStatus=1
A: VolumeType=0
T: 13.327 ms
I: plural wmi select

My system also returns all of the properties that are being checked. I think youā€™ll need to select *, then iterate through the properties using the pipe operator ā€œ|ā€ for error-handling as before. In my query below, I added another ā€œDummyā€ property at the end, specifically to check that Iā€™m properly handling the case of a property that doesnā€™t exist / isnā€™t returnedā€¦the key here is that if I used select objects "A,B,C from win32_EncryptableVolume" Iā€™d have an empty result if A,B, or C didnā€™t exist; instead I use select objects "* ..." to get everything.

q: (property "DeviceID" of it as string | "Device ID Unavailable", property "ProtectionStatus" of it as string | "Protection Status Unavailable", property "VolumeType" of it as string | "Volume Type Unavailable", property "IsVolumeInitializedForProtection" of it as string | "Is Volume Initialized For Protection Unavailable", property "EncryptionMethod" of it as string | "Encryption Method Unavailable", property "Dummy" of it as string | "Dummy Unavailable") of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"
A: DeviceID=\\?\Volume{21bbf6e2-dcd3-4b79-a6d9-7c4e32b07152}\, ProtectionStatus=1, VolumeType=1, IsVolumeInitializedForProtection=True, EncryptionMethod=6, Dummy Unavailable
A: DeviceID=\\?\Volume{c4a1ea59-4fd2-4a8f-aa09-fd1749349bd6}\, ProtectionStatus=1, VolumeType=0, IsVolumeInitializedForProtection=True, EncryptionMethod=6, Dummy Unavailable
T: 14.035 ms
I: plural ( string, string, string, string, string, string )

Hereā€™s the same query, from the ā€˜Single Clauseā€™ tab, thatā€™s formatted to make it just a bit more readable

(
  property "DeviceID" of it as string | "Device ID Unavailable", 
  property "ProtectionStatus" of it as string | "Protection Status Unavailable", 
  property "VolumeType" of it as string | "Volume Type Unavailable", 
  property "IsVolumeInitializedForProtection" of it as string | "Is Volume Initialized For Protection Unavailable", 
  property "EncryptionMethod" of it as string | "Encryption Method Unavailable", 
  property "Dummy" of it as string | "Dummy Unavailable"
 ) of 
  select objects "* from win32_EncryptableVolume" of 
    WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption"

@JasonWalker This is awesome. It would have taken me forever to figure that out!

So what I am seeing is there is no real guarantee that the objects or even the class is there across assets that have never had bitlocker enabled and I would like a value returned. How can error handle the non existent class?

Q: if (exists (select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption")) then ((property "DeviceID" of it as string | "Device ID Unavailable" , property "ProtectionStatus" of it as string | "Protection Status Unavailable" , property "VolumeType" of it as string | "Volume Type Unavailable" , property "IsVolumeInitializedForProtection" of it as string | "Volume Initialized For Protection Unavailable" , property "EncryptionMethod" of it as string | "Encryption Method Unavailable") of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption" ) else "Device ID Unavailable, Protection Status Unavailable, Volume Type Unavailable, Volume Initialized For Protection Unavailable, Encryption Method Unavailable"
E: Incompatible types.

Iā€™m not at a computer now, but this may work; give a try and let me know pleae.

In an if..then..else clause, both results have to be the same type. In this case they are both strings, but the ā€˜thenā€™ returns several tuples and the ā€˜elseā€™ returns only one.

You can change the tuple items in the ā€˜thenā€™ clause into a plural result instead by swapping the commas for semicolons, and join them back together into a single string with ā€˜concatenation ofā€™, so that both the ā€˜thenā€™ and ā€˜elseā€™ retun a single string.

Q: if (exists (select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption")) then (concatenation ", " of (property "DeviceID" of it as string | "Device ID Unavailable" ; property "ProtectionStatus" of it as string | "Protection Status Unavailable" ; property "VolumeType" of it as string | "Volume Type Unavailable" ; property "IsVolumeInitializedForProtection" of it as string | "Volume Initialized For Protection Unavailable" ; property "EncryptionMethod" of it as string | "Encryption Method Unavailable") of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption" ) else "Device ID Unavailable, Protection Status Unavailable, Volume Type Unavailable, Volume Initialized For Protection Unavailable, Encryption Method Unavailable"

@JasonWalker Works very nice.

Q: if (exists (select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption")) then (concatenation ", " of (property "DeviceID" of it as string | "Device ID Unavailable" ; property "ProtectionStatus" of it as string | "Protection Status Unavailable" ; property "VolumeType" of it as string | "Volume Type Unavailable" ; property "IsVolumeInitializedForProtection" of it as string | "Volume Initialized For Protection Unavailable" ; property "EncryptionMethod" of it as string | "Encryption Method Unavailable") of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption" ) else "Device ID Unavailable, Protection Status Unavailable, Volume Type Unavailable, Volume Initialized For Protection Unavailable, Encryption Method Unavailable"
A: DeviceID=\\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}\, ProtectionStatus=0, VolumeType=2, IsVolumeInitializedForProtection=False, EncryptionMethod=0, DeviceID=\\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}\, ProtectionStatus=0, VolumeType=0, IsVolumeInitializedForProtection=False, EncryptionMethod=0
T: 70.868 ms

The results come back as one string though. I need them in separate as such.

DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{1f9d5009-d181-11e8-80b5-000c291d92ac}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=0
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=2
DeviceID=\?\Volume{fd7be577-d180-11e8-80b4-806e6f6e6963}, ProtectionStatus=0, VolumeType=0

Ah, ok, glad weā€™ve at least captured the error cases correctly. Keeping the multiple objects in separate plural results should be a matter of where we place parentheses. Afraid Iā€™m away from computer again but try

Q: if (exists (select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption")) then ((concatenation ", " of (property "DeviceID" of it as string | "Device ID Unavailable" ; property "ProtectionStatus" of it as string | "Protection Status Unavailable" ; property "VolumeType" of it as string | "Volume Type Unavailable" ; property "IsVolumeInitializedForProtection" of it as string | "Volume Initialized For Protection Unavailable" ; property "EncryptionMethod" of it as string | "Encryption Method Unavailable") of it) of select objects "* from win32_EncryptableVolume" of WMIs "root\CIMv2\Security\MicrosoftVolumeEncryption" ) else "Device ID Unavailable, Protection Status Unavailable, Volume Type Unavailable, Volume Initialized For Protection Unavailable, Encryption Method Unavailable"

I should also add that my solution for the ā€˜ifā€¦thenā€¦elseā€™ returning a different number of tuple items isnā€™t the only way to handle it. One could also make the ā€˜elseā€™ return the same number of tuple strings via

else ("Device ID Unavailable", "Protection Status Unavailable", "Volume Type Unavailable", "Volume Initialized For Protection Unavailable", "Encryption Method Unavailable")

@JasonWalker Thank you! Works beautifully!

1 Like

Glad I could help :slight_smile:

Iā€™m also curious thoughā€¦of your machines that were missing some of the properties, which properties werenā€™t returning a value?

Volume Type seems to be property missing most often, but I have seen that only the device ID seems to be the only property guaranteed to be there.

1 Like