WMI header

From NSIS Wiki
Jump to navigationJump to search

Description

This header includes macros to get WMI information, kill processes on 32 and 64 bit OS systems, and set process priority through the WMIC command line.

The results for getting information are returned to variables within a callback function to allow you to read through multiple results.

There is a huge amount of information that can be retrieved using WMI so I would suggest downloading the WMI Code Creator as a reference rather than listing them here. Most of the useful information uses "root\CIMV2" as the namespace.

This includes cryonyx's Explode macro.

Usage

${WMIGetInfo} Namespace Classes Property callbackfunction

Returns the following information to a function:

$R0 = current result number
$R1 = total number of results found
$R2 = requested information
${WMIKillProcess} name.exe

Returns the following information to the stack:

1 = if the process found and killed
0 = if the process was not found
${WMISetPriority} name.exe priority

Priority can be

Low
BelowNormal
Normal
AboveNormal
High
Realtime

Returns the following information to the stack:

1 = if the process priority was changed
0 = if the process was not found

Header file - Save this as WMI.nsh

!ifndef __WMI_Included__
!define __WMI_Included__
!include LogicLib.nsh
!include "TextFunc.nsh"
!define Explode_WMI "!insertmacro Explode_WMI"
 
!define WMIGetInfo "!Insertmacro WMIGetInfo"
!define WMIKillProcess "!Insertmacro WMIKillProcess"
!define WMISetPriority "!Insertmacro WMISetPriority"
 
!macro  Explode_WMI Length  Separator   String
    Push    `${Separator}`
    Push    `${String}`
    Call    Explode_WMI
    Pop     `${Length}`
!macroend
 
Function Explode_WMI
  ; Initialize variables
  Var /GLOBAL explString
  Var /GLOBAL explSeparator
  Var /GLOBAL explStrLen
  Var /GLOBAL explSepLen
  Var /GLOBAL explOffset
  Var /GLOBAL explTmp
  Var /GLOBAL explTmp2
  Var /GLOBAL explTmp3
  Var /GLOBAL explArrCount
 
  ; Get input from user
  Pop $explString
  Pop $explSeparator
 
  ; Calculates initial values
  StrLen $explStrLen $explString
  StrLen $explSepLen $explSeparator
  StrCpy $explArrCount 1
 
  ${If}   $explStrLen <= 1          ;   If we got a single character
  ${OrIf} $explSepLen > $explStrLen ;   or separator is larger than the string,
    Push    $explString             ;   then we return initial string with no change
    Push    1                       ;   and set array's length to 1
    Return
  ${EndIf}
 
  ; Set offset to the last symbol of the string
  StrCpy $explOffset $explStrLen
  IntOp  $explOffset $explOffset - 1
 
  ; Clear temp string to exclude the possibility of appearance of occasional data
  StrCpy $explTmp   ""
  StrCpy $explTmp2  ""
  StrCpy $explTmp3  ""
 
  ; Loop until the offset becomes negative
  ${Do}
    ;   If offset becomes negative, it is time to leave the function
    ${IfThen} $explOffset == -1 ${|} ${ExitDo} ${|}
 
    ;   Remove everything before and after the searched part ("TempStr")
    StrCpy $explTmp $explString $explSepLen $explOffset
 
    ${If} $explTmp == $explSeparator
        ;   Calculating offset to start copy from
        IntOp   $explTmp2 $explOffset + $explSepLen ;   Offset equals to the current offset plus length of separator
        StrCpy  $explTmp3 $explString "" $explTmp2
 
        Push    $explTmp3                           ;   Throwing array item to the stack
        IntOp   $explArrCount $explArrCount + 1     ;   Increasing array's counter
 
        StrCpy  $explString $explString $explOffset 0   ;   Cutting all characters beginning with the separator entry
        StrLen  $explStrLen $explString
    ${EndIf}
 
    ${If} $explOffset = 0                       ;   If the beginning of the line met and there is no separator,
                                                ;   copying the rest of the string
        ${If} $explSeparator == ""              ;   Fix for the empty separator
            IntOp   $explArrCount   $explArrCount - 1
        ${Else}
            Push    $explString
        ${EndIf}
    ${EndIf}
 
    IntOp   $explOffset $explOffset - 1
  ${Loop}
 
  Push $explArrCount
FunctionEnd
 
!macro WMIGetInfo _NameSpace _Class _Property _CallBackFunction
#Push registers to stack
Push $0
Push $1
Push $2
Push $R0
Push $R1
Push $R2
 
#Execute WMI command to stack
nsexec::exectostack "wmic /NAMESPACE:\\${_NameSpace} path ${_Class} get ${_Property}"
pop $0
pop $1
 
#Trim blank lines
${TrimNewLines} "$1" $1
 
#Explode each result to a stack
${Explode_WMI}  $R1  "$\n" "$1"
 
#The first line is the same as ${_Property} so we remove it from the stack and subtract it from the results
Pop $2
IntOp $R1 $R1 - 1
 
#Loop through results and do stuff here
${For} $1 1 $R1
	Pop $2
	StrCpy $R0 $1
	StrCpy $R2 $2
	Call ${_CallBackFunction}
${Next}
 
Pop $R2
Pop $R1
Pop $R0
Pop $2
Pop $1
Pop $0
!macroend
 
!macro WMIKillProcess _ProcName
Push $0
Push $1
nsexec::exectostack "wmic process where name='${_ProcName}' delete"
pop $0
pop $0
StrCpy $0 $0 2
${If} $0 == "No"
pop $0
pop $0
push 0
${Else}
pop $0
pop $0
push 1
${EndIf}
!macroend
 
!macro WMISetPriority _ProcName _Priority
push $0
 
StrCpy $0 ''
 
${If} ${_Priority} == Low
StrCpy $0 64
${ElseIf} ${_Priority} == BelowNormal
StrCpy $0 16384
${ElseIf} ${_Priority} == Normal
StrCpy $0 32
${ElseIf} ${_Priority} == AboveNormal
StrCpy $0 32768
${ElseIf} ${_Priority} == High
StrCpy $0 128
${ElseIf} ${_Priority} == RealTime
StrCpy $0 16384
${EndIf}
 
${If} $0 != ''
nsexec::exectostack "wmic process where name='${_ProcName}' call setpriority $0"
pop $0
pop $0
StrCpy $0 $0 2
${If} $0 == "No"
pop $0
pop $0
push 0
${Else}
pop $0
pop $0
push 1
${EndIf}
${EndIf}
!macroend
!endif

Example

Name WMI
OutFile WMI.exe
RequestExecutionLevel Admin
!include WMI.nsh
!include LogicLib.nsh
 
 
Section "test"
#List disk drive models:
${WMIGetInfo} root\CIMV2 Win32_DiskDrive model callback_Function
 
#List network adapters:
${WMIGetInfo} root\CIMV2 Win32_NetworkAdapter name callback_Function
 
#List user accounts on local computer:
${WMIGetInfo} root\CIMV2 Win32_UserAccount name callback_Function
 
 
Messagebox MB_YESNO "Launch calc.exe" IDNO +3
exec "calc.exe"
sleep 1000
${WMIKillProcess} calc.exe 
pop $0
 
${If} $0 == 0
detailprint "calc.exe not found"
${ElseIf} $0 == 1
detailprint "calc.exe was found and killed"
${EndIf}
 
Messagebox MB_YESNO "Launch calc.exe" IDNO +3
exec "calc.exe"
sleep 1000
${WMISetPriority} calc.exe High
pop $0
 
${If} $0 == 0
detailprint "calc.exe not found"
${ElseIf} $0 == 1
detailprint "calc.exe was found set to high priority"
${EndIf}
 
SectionEnd
 
Function callback_Function
detailprint "$R0/$R1=$R2"
FunctionEnd