Archive: WMI via System plugin - query BIOS serial number


WMI via System plugin - query BIOS serial number
  The following code demonstrates the usage of the Windows Management Instrumentation (WMI) only via the System plugin.
The sample code displays the BIOS serial number in a message box.

I have not yet tried to remotely access computers via this script. Furthermore I left out a call to the CoSetProxyBlanket function because it seems that is is not needed for querying the BIOS serial number.

; Copyright (c) 2009 f0rt

>; Licensed under the zlib/libpng license (same as NSIS)
;
;Usage of Windows Management Instrumentation (WMI) only via the System plugin
>; Display BIOS serial number

OutFile "bios_sn.exe"

>!include "LogicLib.nsh"

>!define CLSCTX_INPROC_SERVER 1
>!define CLSID_WbemLocator {4590f811-1d3a-11d0-891f-00aa004b2e24}
!define IID_IWbemLocator {dc12a687-737f-11cf-884d-00aa004b2e24}

!define RPC_C_AUTHN_LEVEL_DEFAULT 0
>!define RPC_C_IMP_LEVEL_IMPERSONATE 3

>!define EOAC_NONE 0

>!define WBEM_FLAG_FORWARD_ONLY 0x20
>!define WBEM_FLAG_RETURN_IMMEDIATELY 0x10
>!define WBEM_INFINITE 0xffffffff

>; Query BIOS serial number via WMI and return it in $0
>Function bios_sn
; Save registers
Push$1
Push$2
Push$3
Push$4
Push$5
Push$6
Push$7

; Initialization of COM is done via OleInitialize in NSIS installer code
; Set general COM security level
System::Call "ole32::CoInitializeSecurity( \\
i 0, i -1, i 0, i 0, i ${RPC_C_AUTHN_LEVEL_DEFAULT}, \\
i ${RPC_C_IMP_LEVEL_IMPERSONATE}, i 0, i ${EOAC_NONE}, i 0) i.r1"
${If} $1 != 0
StrCpy$0 "failed to initialize security: $1"
Goto bios_sn_end
${EndIf}

;Create IWbemLocator interface
System::Call "ole32::CoCreateInstance( \\
g '${CLSID_WbemLocator}', i 0, \\
i ${CLSCTX_INPROC_SERVER}, \\
g '${IID_IWbemLocator}', *i .r2) i.r1"
${If} $1 != 0
StrCpy$0 "failed to create IWebmLocator object: $1"
Goto bios_sn_end
${EndIf}

;Call IWbemLocator->ConnectServer
System::Call "$2->3(w 'ROOT\CIMV2', i 0, i 0, i 0, i 0, i 0, i 0, *i .r3) i.r1"

${If} $1 != 0
StrCpy$0 "failed to connect: $1"
${Else}
;Call IWbemServices->ExecQuery
System::Call "$3->20(w 'WQL', w 'Select SerialNumber from Win32_BIOS', \\
${WBEM_FLAG_FORWARD_ONLY} | ${WBEM_FLAG_RETURN_IMMEDIATELY}, \\
i 0, *i .r4) i.r1"

${If} $1 != 0
StrCpy$0 "failed to query: $1 $3"
${Else}
;Call IEnumWbemClassObject->Next
System::Call "$4->4(i ${WBEM_INFINITE}, i 1, *i .r5, *i .r6) i.r1"
${If} $1 != 0
StrCpy$0 "failed to iterate: $1"
${Else}
${If} $6 > 0
; Variant
; (unsigned short vt, WORD wReserved1,
; WORD wReserved2, WORD wReserved3, BSTR bstrVal)
;Allocate memory for Variant
System::Call "*(i 0, i 0, i 0) i.r7"
; Call IWbemClassObject->Get
System::Call "$5->4(w 'SerialNumber', i 0, i r7, i 0, i 0) i.r1"
${If} $1 < 0
StrCpy$0 "failed to get: $1"
${Else}
; Access bstrVal from Variant
System::Call "*$7(i, i, w .r0)"
System::Call "ole32::VariantClear(i r7)"
${EndIf}
; Free memory associated with Variant
System::Free $7
${Else}
StrCpy $0 "failed: no items ***91;$6***93;"
${EndIf}
;Call IWbemClassObject->Release
System::Call "$5->2()"
${EndIf}
;Call IEnumWbemClassObject->Release
System::Call "$4->2()"
${EndIf}

;Call IWbemService->Release
System::Call "$3->2()"
${EndIf}

;Call IWbemLocator->Release
System::Call "$2->2()"

>bios_sn_end:
; Restore registers
Pop$7
Pop$6
Pop$5
Pop$4
Pop$3
Pop$2
Pop$1
FunctionEnd

>Function .onInit
InitPluginsDir
Call bios_sn
MessageBox MB_OK "BIOS Serial Number=$0"
Quit
FunctionEnd

Section
SectionEnd
>

Wow, this is a very good example of how to use the System plugin.

Anyhow, you could have used the WMIInspector plugin to get the same result

WmiInspector::Request "CIMV2" "Win32_BIOS" "SerialNumber"
Pop $0
Pop $1
MessageBox MB_OK "Result call: $0$\r$\n$\r$\nValue: $1"

The WMIInspector plugin is fine as well.

The advantage of the System plugin is that it is shipped with NSIS.

Somehow a backslash (\) got lost in the call to IWbemLocator->ConnectServer. It should be:


  ; Call IWbemLocator->ConnectServer

System
::Call "$2->3(w 'ROOT\\CIMV2', i 0, i 0, i 0, i 0, i 0, i 0, *i .r3) i.r1"
I could no longer edit my previous post. So I just replied to the thread.

The disadvantage of the System plugin is that you need to be very careful with allocating and freeing memory.

So here comes a new version which frees the previously allocated memory for the variant.


OutFile "bios_sn.exe"


>!include "LogicLib.nsh"

>!define CLSCTX_INPROC_SERVER 1
>!define CLSID_WbemLocator {4590f811-1d3a-11d0-891f-00aa004b2e24}
!
define IID_IWbemLocator {dc12a687-737f-11cf-884d-00aa004b2e24}

!define RPC_C_AUTHN_LEVEL_DEFAULT 0
>!define RPC_C_IMP_LEVEL_IMPERSONATE 3

>!define EOAC_NONE 0

>!define WBEM_FLAG_FORWARD_ONLY 0x20
>!define WBEM_FLAG_RETURN_IMMEDIATELY 0x10
>!define WBEM_INFINITE 0xffffffff

>!define VT_BSTR 8

>Function bios_sn
; Save registers
Push$1
Push$2
Push$3
Push$4
Push$5
Push$6
Push$7

; Initialization of COM is done via OleInitialize in NSIS installer code
; Set general COM security level
System::Call "ole32::CoInitializeSecurity( \\
i 0, i -1, i 0, i 0, i ${RPC_C_AUTHN_LEVEL_DEFAULT}, \\
i ${RPC_C_IMP_LEVEL_IMPERSONATE}, i 0, i ${EOAC_NONE}, i 0) i.r1"
${If} $1 != 0
StrCpy$0 "failed to initialize security: $1"
Goto bios_sn_end
${EndIf}

;Create IWbemLocator interface
System::Call "ole32::CoCreateInstance( \\
g '${CLSID_WbemLocator}', i 0, \\
i ${CLSCTX_INPROC_SERVER}, \\
g '${IID_IWbemLocator}', *i .r2) i.r1"
${If} $1 != 0
StrCpy$0 "failed to create IWebmLocator object: $1"
Goto bios_sn_end
${EndIf}

;Call IWbemLocator->ConnectServer
System::Call "$2->3(w 'ROOT\\CIMV2', i 0, i 0, i 0, i 0, i 0, i 0, *i .r3) i.r1"

${If} $1 != 0
StrCpy$0 "failed to connect: $1"
${Else}
;Call IWbemServices->ExecQuery
System::Call "$3->20(w 'WQL', w 'Select SerialNumber from Win32_BIOS', \\
${WBEM_FLAG_FORWARD_ONLY} | ${WBEM_FLAG_RETURN_IMMEDIATELY}, \\
i 0, *i .r4) i.r1"
${If} $1 != 0
StrCpy$0 "failed to query: $1 $3"
${Else}
;Call IEnumWbemClassObject->Next
System::Call "$4->4(i ${WBEM_INFINITE}, i 1, *i .r5, *i .r6) i.r1"
${If} $6 != 0
; Variant
; (unsigned short vt, WORD wReserved1, WORD wReserved2, WORD wReserved3, BSTR bstrVal)
System::Call "*(i 0, i 0, i 0) i.r7"
${If} $7 != 0
; Call IWbemClassObject->Get
System::Call "$5->4(w 'SerialNumber', i 0, i r7, i 0, i 0) i.r1"
${If} $1 != 0
StrCpy$0 "failed to get: $1"
${Else}
; Check type of variant
System::Call "*$7(i .r1)"
IntOp $1 $1 & 0xFFFF
${If} $1 == ${VT_BSTR}
; Access bstrVal from Variant
System::Call "*$7(i, i, w .r0)"
${Else}
StrCpy $0 "failed to access data: wrong type ***91;$1***93;"
${EndIf}
System::Call "ole32::VariantClear(i r7)"
${EndIf}
; Deallocate memory of variant
System::Free $7
${Else}
StrCpy $0 "failed to allocate memory for variant"
${EndIf}
;Call IWbemClassObject->Release
System::Call "$5->2()"
${Else}
StrCpy $0 "failed to iterate ***91;$6***93;: $1"
${EndIf}
;Call IEnumWbemClassObject->Release
System::Call "$4->2()"
${EndIf}

;Call IWbemService->Release
System::Call "$3->2()"
${EndIf}

;Call IWbemLocator->Release
System::Call "$2->2()"

>bios_sn_end:
; Restore registers
Pop$7
Pop$6
Pop$5
Pop$4
Pop$3
Pop$2
Pop$1
FunctionEnd

>Function .onInit
InitPluginsDir
Call bios_sn
MessageBox MB_OK "Bios Serial Number=$0"
Quit
FunctionEnd

Section
SectionEnd
>