Old 13th August 2009, 19:58   #1
f0rt
Junior Member
 
Join Date: Jul 2009
Posts: 36
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.

PHP Code:
Copyright (c2009 f0rt
Licensed under the zlib/libpng license (same as NSIS)
;
Usage of Windows Management Instrumentation (WMIonly 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} $!= 0
     StrCpy 
$"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} $!= 0
     StrCpy 
$"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} $!= 0
     StrCpy 
$"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} $!= 0
         StrCpy 
$"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} $!= 0
             StrCpy 
$"failed to iterate: $1"
         
${Else} 
             ${If} $
0
                 
Variant
                 
; (unsigned short vtWORD wReserved1
                 ;  
WORD wReserved2WORD wReserved3BSTR 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} $0
                    StrCpy 
$"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 $"failed: no items [$6]"
             
${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 
f0rt is offline   Reply With Quote
Old 13th August 2009, 21:09   #2
jpderuiter
Major Dude
 
Join Date: Feb 2007
Posts: 672
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
code:
WmiInspector::Request "CIMV2" "Win32_BIOS" "SerialNumber"
Pop $0
Pop $1
MessageBox MB_OK "Result call: $0$\r$\n$\r$\nValue: $1"

jpderuiter is offline   Reply With Quote
Old 14th August 2009, 20:00   #3
f0rt
Junior Member
 
Join Date: Jul 2009
Posts: 36
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:

PHP Code:
  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 is offline   Reply With Quote
Old 18th August 2009, 23:20   #4
f0rt
Junior Member
 
Join Date: Jul 2009
Posts: 36
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.

PHP Code:
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} $!= 0
     StrCpy 
$"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} $!= 0
     StrCpy 
$"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} $!= 0
     StrCpy 
$"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} $!= 0
         StrCpy 
$"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} $!= 0
             
Variant
             
; (unsigned short vtWORD wReserved1WORD wReserved2WORD wReserved3BSTR bstrVal)
             
System::Call "*(i 0, i 0, i 0) i.r7"
             
${If} $!= 0
                
Call IWbemClassObject->Get
                System
::Call "$5->4(w 'SerialNumber', i 0, i r7, i 0, i 0) i.r1"
                
${If} $!= 0
                   StrCpy 
$"failed to get: $1"
                
${Else} 
                   ; 
Check type of variant
                   System
::Call "*$7(i .r1)"
                   
IntOp $$0xFFFF
                   
${If} $== ${VT_BSTR}
                      ; 
Access bstrVal from Variant
                      System
::Call "*$7(i, i, w .r0)"
                   
${Else}
                      
StrCpy $"failed to access data: wrong type [$1]"
                   
${EndIf}
                   
System::Call "ole32::VariantClear(i r7)"
                
${EndIf}
                ; 
Deallocate memory of variant
                System
::Free $7
             
${Else}
                
StrCpy $"failed to allocate memory for variant"
             
${EndIf}
             ; 
Call IWbemClassObject->Release
             System
::Call "$5->2()"
         
${Else}
             
StrCpy $"failed to iterate [$6]: $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 
f0rt is offline   Reply With Quote
Old 14th August 2015, 09:01   #5
stass
Senior Member
 
Join Date: Nov 2012
Posts: 147
In Windows 7, the above code - does not work ...
Quote:
Bios Serial Number=failed to connect: -2147217394
What can be done ?
And how can you get other options WMI ?
stass is offline   Reply With Quote
Old 14th August 2015, 11:59   #6
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
Quote:
Originally Posted by stass View Post
In Windows 7, the above code - does not work ...
WBEM_E_INVALID_NAMESPACE 0x8004100E

Have you tried a different Windows 7 machine?

See also:
http://blogs.technet.com/b/askperf/a...wmi-class.aspx

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 14th August 2015, 14:06   #7
stass
Senior Member
 
Join Date: Nov 2012
Posts: 147
Anders
I tested this code on Windows 7 Pro x32 RUS and Windows 7 Pro x64 RUS.
The result - the same, that is, It does not work ...
stass is offline   Reply With Quote
Old 22nd August 2016, 21:26   #8
f0rt
Junior Member
 
Join Date: Jul 2009
Posts: 36
The PHP prettifying messed up the formatting.

I adapted the script for NSIS 3.0 and uploaded it to the NSIS Wiki.
f0rt is offline   Reply With Quote
Old 22nd August 2016, 23:36   #9
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,321
Thumbs up

Quote:
Originally Posted by f0rt View Post

I adapted the script for NSIS 3.0 and uploaded it to the NSIS Wiki.
The Target attribute is undocumented

The System plugin p type has been backported to 2.51 along with some of the pointer stuff in LogicLib.nsh and Util.nsh so it should be possible to write portable system plugin code now that targets x86-ansi (v2.51 and v3.x), x86-unicode and amd64-unicode without too much pain...

Use: !if "${NSIS_PTR_SIZE}" > 4 ; for 64-bit specific stuff and !if "${NSIS_CHAR_SIZE}" > 1 for Unicode.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
bios, plug-in, system.plug-in, wmi

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump