WMI Query for Dell BIOS

Started by domvalle@comcast.net, August 19, 2024, 11:35:56 AM

Previous topic - Next topic

domvalle@comcast.net

Hi,

found a powershell script, see attached(PS works), to query Dell BIOS settings but cannot seem to translate to WBT query.
The 'Type' result is EMPTY... I'm missing something, Any suggestions?

      ...here is my try, copied from tech board: Win32_BIOS
objLocator = ObjectCreate("WbemScripting.SWbemLocator")

;'Namespace'   = 'ROOT\dcim\sysman\biosattributes' - FROM Attached Powershell
objService = objLocator.ConnectServer(".","ROOT\dcim\sysman\biosattributes","","")

objSecurity = objService.Security_
objSecurity.ImpersonationLevel = 3

;'Class' = 'EnumerationAttribute' - FROM Attached Powershell
class =  "EnumerationAttribute"

; query instances
query = "SELECT * FROM biosattributes"
colInstances = objService.ExecQuery(query)


; loop once for each instance
ForEach objInstance in colInstances
  ;Check if Object is EMPTY
  type = ObjectTypeGet(objInstance)
  pause("test type", type)
  if type=="EMPTY" then break
  propWakeOnLan = objInstance.WakeOnLan ;fails

Next

spl

Maybe not helpful, but only thing I would think was additional parameters to ExecQuery i.e. colInstances = objService.ExecQuery(query,,48).... as you seem to be connecting to remote server.
Stan - formerly stanl [ex-Pundit]

td

I don't have the Dell namespace so I can't test this but maybe you need something like "Instance = Service.InstancesOf(Class)" to access the enumeration. Stan's suggestion should be investigated too.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

domvalle@comcast.net

Yes, you need to have a Dell machine to test...
I'm a novice w/WMI so not sure how to apply the suggestions...

td

Here is an example using a standard MSFT WMI provider. It may or may not be helpful.

Locator = ObjectOpen("WbemScripting.SWbemLocator")
Service = Locator.ConnectServer(".","root/cimv2" )
Service.Security_.ImpersonationLevel = 3     
Class = "Win32_ComputerSystem"  ; Holds total memory info
Enum =  Service.InstancesOf(Class)
Ram = 0
foreach Obj in Enum
   Ram+=Obj.TotalPhysicalMemory     ;this is the total ram
next
Gb = 1024.0**3
GigRam = ram / Gb
exit


"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

domvalle@comcast.net

ok, another try is now getting a object type of 'DISPATCH' . . .hmmm

objLocator = ObjectCreate("WbemScripting.SWbemLocator")
objService = objLocator.ConnectServer(".","ROOT\dcim\sysman\biosattributes","","")
objSecurity = objService.Security_
objSecurity.ImpersonationLevel = 3
class =  "EnumerationAttribute"      
; query instances
query = "SELECT * FROM EnumerationAttribute"    
colInstances = objService.ExecQuery(query)

Instance = objService.InstancesOf(class)

ForEach objInstance in Instance
  ;Check if Object is EMPTY
  type = ObjectTypeGet(objInstance)
  pause("test type", type)  ; getting 'DISPATCH' here
  ;if type=="EMPTY" then break
Next

spl

Maybe you can iterate instance values, [just guessing]
ForEach objInstance in Instance
   A = objInstance.AttributeName
   C = objInstance.CurrentValue
   P = objInstance.PossibleValue
   Display(2,"Enumeration",A:",":C:",":P)
Next
Stan - formerly stanl [ex-Pundit]

domvalle@comcast.net

Thanks All,
thanks Stan!...

that worked!!! with one data type mismatch, see below
.....................................................
delimiter = @tab
objLocator = ObjectCreate("WbemScripting.SWbemLocator")
objService = objLocator.ConnectServer(".","ROOT\dcim\sysman\biosattributes","","")
objSecurity = objService.Security_
objSecurity.ImpersonationLevel = 3
class =  "EnumerationAttribute"   
; query instances
query = "SELECT * FROM EnumerationAttribute"   
colInstances = objService.ExecQuery(query)
Instance = objService.InstancesOf(class)

ForEach objInstance in Instance
   A = objInstance.AttributeName
   ;pause("test A", A)
   C = objInstance.CurrentValue
   ;pause("test C", C)

   vals = objInstance.PossibleValue     ; keep getting Data MisMatch with this one
      pause("test vals", vals)  ; WMI says should be an 'array of string'
      ForEach val in vals     ; see below for data types
         
      next

   pause("Enumeration", A:@lf:C)
Next

*********************************************
Enumeration Attribute (EnumerationAttribute)
*********************************************

Property name           Type                Read/Write     Value                                                                   
---------------------------------------------------------------------------------
__GENUS                                     Read Only      1                                                                                       
__CLASS                                     Read Only      EnumerationAttribute                                                                     
__SUPERCLASS                                Read Only                                                                                               
__DYNASTY                                   Read Only      EnumerationAttribute                                                                     
__RELPATH                                   Read Only      EnumerationAttribute                                                                     
__PROPERTY_COUNT                            Read Only      12                                                                                       
__DERIVATION                                Read Only                                                                                               
__SERVER                                    Read Only      MV-IT-6T149R3                                                                           
__NAMESPACE                                 Read Only      ROOT\dcim\sysman\biosattributes                                                         
__PATH                                      Read Only      \\MV-IT-6T149R3\ROOT\dcim\sysman\biosattributes:EnumerationAttribute                     
AttributeName           string              Read Only                                                                                               
CurrentValue            string              Read Only                                                                                               
DefaultValue            string              Read Only                                                                                               
DisplayName             string              Read Only                                                                                               
DisplayNameLangCode     string              Read Only                                                                                               
InstanceName            string              Read Only                                                                                               
Modifiers               string              Read Only                                                                                               
PossibleValue           array of string     Read Only                                                                                               
PossibleValueCount      uint32              Read Only                                                                                               
ReadOnly                boolean             Read Only                                                                                               
ValueModifierCount      uint32              Read Only                                                                                               
ValueModifiers          array of string     Read Only         

domvalle@comcast.net

Oh ok, so this 'array of string' looks like this:
;Possible Value  : {Disabled, Basic, Enhanced, Full}

spl

Quote from: domvalle@comcast.net on August 21, 2024, 08:21:24 AMOh ok, so this 'array of string' looks like this:
;Possible Value  : {Disabled, Basic, Enhanced, Full}

Not sure the ultimate focus. But script seems it would work w/out PosibleValues iteration. If your intention is for a script to change values based on what is possible,,, that might be another interesting next step, otherwise a basic WMI query for Win32_Bios would suffice for most users interpreting BIOS.
Stan - formerly stanl [ex-Pundit]

domvalle@comcast.net

Yes, ultimately need to be able to update/change Bios settings on entire network.
WMI would be the first choice...
thanks Stan...

domvalle@comcast.net

OK, finally some useful results below...
...able to return all objects now, next to see if we can update,

;***************************************************************************
;**  Test Dell Bios Objects w/WMI
;***************************************************************************

;*********************************************
;Enumeration Attribute (EnumerationAttribute)
;*********************************************
;
;Property name           Type                Read/Write     Value   Description                                                                     
;------------------------------------------------------------------------------------------------------------
;__GENUS                                     Read Only      1                                                                                       
;__CLASS                                     Read Only      EnumerationAttribute                                                                     
;__SUPERCLASS                                Read Only                                                                                               
;__DYNASTY                                   Read Only      EnumerationAttribute                                                                     
;__RELPATH                                   Read Only      EnumerationAttribute                                                                     
;__PROPERTY_COUNT                            Read Only      12                                                                                       
;__DERIVATION                                Read Only                                                                                               
;__SERVER                                    Read Only      MV-IT-6T149R3                                                                           
;__NAMESPACE                                 Read Only      ROOT\dcim\sysman\biosattributes                                                         
;__PATH                                      Read Only      \\MV-IT-6T149R3\ROOT\dcim\sysman\biosattributes:EnumerationAttribute                     
;AttributeName           string              Read Only                                                                                               
;CurrentValue            string              Read Only                                                                                               
;DefaultValue            string              Read Only                                                                                               
;DisplayName             string              Read Only                                                                                               
;DisplayNameLangCode     string              Read Only                                                                                               
;InstanceName            string              Read Only                                                                                               
;Modifiers               string              Read Only                                                                                               
;PossibleValue           array of string     Read Only                                                                                               
;PossibleValueCount      uint32              Read Only                                                                                               
;ReadOnly                boolean             Read Only                                                                                               
;ValueModifierCount      uint32              Read Only                                                                                               
;ValueModifiers          array of string     Read Only             
;

delimiter = @tab
objLocator = ObjectCreate("WbemScripting.SWbemLocator")
objService = objLocator.ConnectServer(".","ROOT\dcim\sysman\biosattributes","","")
objSecurity = objService.Security_
objSecurity.ImpersonationLevel = 3
class =  "EnumerationAttribute"
; query instances
query = "SELECT * FROM EnumerationAttribute"
colInstances = objService.ExecQuery(query)
Instance = objService.InstancesOf(class)

ForEach objInstance in Instance
   A = objInstance.AttributeName
   ;pause("test A", A)
   C = objInstance.CurrentValue
   ;pause("test C", C)
   Vcnt = objInstance.PossibleValueCount
   ;pause("test cnt", cnt)
   vals = objInstance.PossibleValue
   ;type = ObjectTypeGet(vals)     ;this is a SAFEARRAY | ARRAY in VARIANT
   ;pause("test type", type)
   strList = ArrayItemize( vals, "," )
   ;pause("test strList", strList)

   pause("Enumeration", "NAME: " : A : @lf : "CurrentValue: " : C : @lf : "PossibleValues: " : "%strList%" )

   ;will display results:
      ;          NAME: RemoteWipeInternalDrives
      ;  CurrentValue: Unarmed
      ;PossibleValues: Unarmed,Armed,Complete,Error
Next


; close object handles
ObjectClose(colInstances)
ObjectClose(objSecurity)
ObjectClose(objService)
ObjectClose(objLocator)

spl

Quote from: domvalle@comcast.net on August 21, 2024, 08:48:52 PMOK, finally some useful results below...
...able to return all objects now, next to see if we can update,

I assume you reviewed the Dell Bios article https://www.configjon.com/dell-bios-settings-management-wmi/ which covers the BIOSAttributeInterface class and the SetAttribute method. Looks like the PS code can be converted to WB w/out much difficulty.
Stan - formerly stanl [ex-Pundit]

domvalle@comcast.net

Yes, but looked too complicated at first... but I will review again, thanks Stan!

domvalle@comcast.net

here is another version for the SetAttribute...
as per: https://dl.dell.com/manuals/common/dell-agentless-client-manageability.pdf

   $BAI = Get-WmiObject -Namespace root/dcim/sysman/biosattributes -Class
   BIOSAttributeInterface

   Note that you are storing the instance in a PowerShell environment variable called $BAI. This will allow you to use the same instance for future configuration settings. Once you have the class instance, executing a Set   operation becomes simple.

   $BAI.SetAttribute(0,0,0,"UefiNwStack","Disabled")
   Note that the first three arguments are set to zero if BIOS administrator password is not set on the system.

however I get an error when I tried this:

    if A == "NumLockLed"  ;(objInstance)     
         ; as per: https://dl.dell.com/manuals/common/dell-agentless-client-manageability.pdf
         objInstance.SetAttribute(0,0,0,"NumLockLed","Disabled")    ;getting UnKnown Name  <---
           y = objInstance.CurrentValue
      pause("test y", y)
    else
   endif

spl

Not sure how to help. Only experience I had was circa 2008 when I managed a SQL Server network for DISH installations where they set up 12-16 workstations for sales promotions. So persons were hired for promotion calls usually ending at 10-11 PM. My boss was suspicious that many might be using the network to browse porn sites or other nefarious subjects and wanted proof. So I set up WakeOnLan and from home after midnight could investigate their IE cache even if they had supposedly deleted their browsing history and closed down. The PC's were ACER but BIOS is BIOS [I think].

Long story short. Maybe you can investigate a specific attribute like WakeOnLan, script a GetAttribute and attempt a set attribute. My 2008 code was pure WB, and if I can dig it up might be useful.
Stan - formerly stanl [ex-Pundit]

domvalle@comcast.net

thanks Stan... I will update if I get something to work...

td

Quote from: domvalle@comcast.net on August 23, 2024, 04:49:52 AMhere is another version for the SetAttribute...
as per: https://dl.dell.com/manuals/common/dell-agentless-client-manageability.pdf

   $BAI = Get-WmiObject -Namespace root/dcim/sysman/biosattributes -Class
   BIOSAttributeInterface

   Note that you are storing the instance in a PowerShell environment variable called $BAI. This will allow you to use the same instance for future configuration settings. Once you have the class instance, executing a Set   operation becomes simple.

   $BAI.SetAttribute(0,0,0,"UefiNwStack","Disabled")
   Note that the first three arguments are set to zero if BIOS administrator password is not set on the system.

however I get an error when I tried this:

    if A == "NumLockLed"  ;(objInstance)     
         ; as per: https://dl.dell.com/manuals/common/dell-agentless-client-manageability.pdf
         objInstance.SetAttribute(0,0,0,"NumLockLed","Disabled")    ;getting UnKnown Name  <---
           y = objInstance.CurrentValue
      pause("test y", y)
    else
   endif

Is it possible that you need to use "SetAttributes" instead of "SetAttribute" as the object method name?
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

domvalle@comcast.net

...same result COM: UnKnown Name

td

Then how are you populating the "objInstance" variable?
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

spl

Quote from: td on August 23, 2024, 01:18:40 PMThen how are you populating the "objInstance" variable?

Perhaps, following same logic for a class
objLocator = ObjectCreate("WbemScripting.SWbemLocator")
objService = objLocator.ConnectServer(".","ROOT\dcim\sysman\biosattributes","","")
objSecurity = objService.Security_
objSecurity.ImpersonationLevel = 3
class =  "BIOSAttributeInterface"
query = "SELECT * FROM  BIOSAttributeInterface"
colInstances = objService.ExecQuery(query)
Instance = objService.InstancesOf(class)
Instance.SetAttribute(0,0,0,"NumLockLed","Disabled")
Stan - formerly stanl [ex-Pundit]

domvalle@comcast.net

...I see, you have a point re the instance of BIOSAttributeInterface,

it did not work either so I tried powershell from the Dell doc and that did not work either.
here is the txt from the powershell screen, also attached a screen shot

PS C:\Windows\System32> $BAI = Get-WmiObject -Namespace root/dcim/sysman/biosattributes -Class BIOSAttributeInterface

PS C:\Windows\System32> $BAI  ...to show the response

RunspaceId      : 8a6bffd0-b09d-49ee-8637-64116023bb70
__GENUS          : 2
__CLASS          : BIOSAttributeInterface
__SUPERCLASS    :
__DYNASTY        : BIOSAttributeInterface
__RELPATH        : BIOSAttributeInterface.InstanceName="ACPI\\PNP0C14\\WBAT_0"
__PROPERTY_COUNT : 2
__DERIVATION    : {}
__SERVER        : MV-IT-6T149R3
__NAMESPACE      : root\dcim\sysman\biosattributes
__PATH          : \\MV-IT-6T149R3\root\dcim\sysman\biosattributes:BIOSAttributeInterface.InstanceName="ACPI\\PNP0C14\\
                  WBAT_0"
Active          : True
InstanceName    : ACPI\PNP0C14\WBAT_0

PS C:\Windows\System32> $BAI.SetAttribute(0,0,0,"NumLockLed","Disabled")
>>
InvalidOperation: Method invocation failed because [Deserialized.System.Management.ManagementObject#root\dcim\sysman\biosattributes\BIOSAttributeInterface] does not contain a method named 'SetAttribute'.
PS C:\Windows\System32> $BAI.SetAttribute(0,0,0,"UefiNwStack","Disabled")
InvalidOperation: Method invocation failed because [Deserialized.System.Management.ManagementObject#root\dcim\sysman\biosattributes\BIOSAttributeInterface] does not contain a method named 'SetAttribute'.
PS C:\Windows\System32>

spl

Again, just guessing, but looks like the first parameter of SetAttribute() is either 0 [BIOS PW not set] or 1 [PW is set] although not related to the error(s).

Have you looked at https://www.dell.com/support/kbdoc/en-us/000177240/dell-command-powershell-provider

[EDIT]

Gonna have to look at what PS means by Serialization... I've had several scripts where that was the initial error but meant having to address the 'type' for variables or parameters. But, if you cannot come up with PS code to set attributes no use any PS=>WB conversion attempts. Bummer, since the first attempt seemed to work for you.
Stan - formerly stanl [ex-Pundit]

spl

Figured I'd throw this out. Supposedly DELL includes PS module with install, but it can be installed manually. There is also PS modules for BIOS get/set. Below is my StdOut WB script adapted. I ran it for my HP with arguments for the more general module, but included commented arguments for the Dell specific provider. While WMI may well be the way to go for your project, at least seeing if PS can get/set attributes.
;Windows BIOS Status
;save as ..\StdOut_BIOS.wbt
;Stan Littlefield 8/26/2024
;==========================================================
Gosub udfs

module = "GetBIOS"
;NOTE: there is also a SetBIOS module available
command = "Get-BIOS -ShowDescription"

;comment above and uncomment next 2 lines for DELL specific Provider
;module =  "DellBIOSProvider"
;command = "Get-Item -Path DellSmbios:\Security\IsAdminPasswordSet"

args = $"if (!(Get-Module -ListAvailable -Name |module|)) { Install-Module -Name |module| -Scope CurrentUser -allowclobber -force }
Import-Module |module|
|command|
$"
args = StrReplace(args,"|module|",module)
args = StrReplace(args,"|command|",command)
cmd="Powershell"
msg='BIOS Attributes'

BoxOpen("Running...",cmd:" ":args:@LF:"PLEASE WAIT...MAY TAKE SOME TIME")
TimeDelay(2)
vals = Get_stdout()
vals = StrReplace(vals,'"','')
Message(msg,vals) ;output may look messy
;optional - create output file with links, for further scraping
;FilePut("c:\temp\Defender.txt",vals)
Exit
;==========================================================
:udfs
#DefineSubroutine Get_stdout()
ObjectClrOption("useany","System")
objInfo = ObjectClrNew("System.Diagnostics.ProcessStartInfo")
Output=""
objInfo.FileName = cmd
objInfo.RedirectStandardError = ObjectType("BOOL",@TRUE)
objInfo.RedirectStandardOutput = ObjectType("BOOL",@TRUE)
objInfo.UseShellExecute = ObjectType("BOOL",@FALSE)
objInfo.CreateNoWindow = ObjectType("BOOL",@TRUE)
objInfo.Arguments = args
oProcess = ObjectClrNew("System.Diagnostics.Process")
oProcess.StartInfo = objInfo
BoxShut()
oProcess.Start()
oProcess.WaitForExit()
STDOUT = oProcess.StandardOutput.ReadToEnd()
STDERR = oProcess.StandardError.ReadToEnd()
Output = Output:STDOUT:@CRLF
If STDERR<>""
   Output = Output:"STDERR:":STDERR:@CRLF
Endif
oProcess = 0
objInfo = 0

Return (Output)
#EndSubroutine
Return
;==========================================================
Stan - formerly stanl [ex-Pundit]