f0rt
13th August 2009 19:58 UTC
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
>
jpderuiter
13th August 2009 21:09 UTC
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"
f0rt
14th August 2009 20:00 UTC
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.
f0rt
18th August 2009 23:20 UTC
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
>