WMI

Share your advanced PureBasic knowledge/code with the community.
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: WMI

Post by Marc56us »

Alternative: use command line tool 'wmic' with RunProgram()

RunProgram("wmic", "/node:<ip> /user:<domain\username>... ", "")
tatanas
Enthusiast
Enthusiast
Posts: 199
Joined: Wed Nov 06, 2019 10:28 am
Location: France

Re: WMI

Post by tatanas »

Thanks for the answers.
I read the wmi dll description but don't see any way to do remote connexion with credentials.
Should I use "ExecuteWMIMethod(Namespace$, Query$, Method$, ParameterArray, ParameterArraySize)" with ConnectServer method ? The problem is I should use CoSetProxyBlanket and the others too.
It doesn't seem to resolve my problem.
Indeed I could use wmic command or Powershell command or ... but PB could do that and it should work with the right paramaters.

I dug more and I found that the problem could come from the CoSetProxyBlanket function :
CoSetProxyBlanket_(pService, #RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE, 0, #RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE, *userAcct, #EOAC_NONE)
*userAcct is a pointer to COAUTHIDENTITY structure and could be the reason It doesn't work.

Code: Select all

domain$ = "domainname"
#SEC_WINNT_AUTH_IDENTITY_UNICODE = $2
authIdent.COAUTHIDENTITY
authIdent\PasswordLength = Len(password$)
authIdent\Password = @password$
authIdent\Flags = #SEC_WINNT_AUTH_IDENTITY_UNICODE
authIdent\User = @user$
authIdent\UserLength = Len(user$)
authIdent\Domain = @domain$
authIdent\DomainLength = Len(domain$)

*userAcct.COAUTHIDENTITY
*userAcct = @authIdent
But when I use *userAcct instead of #Null, I've got an error

Same problem as mine which seems to be resolved :
http://groups.google.com/group/microsof ... fac8544741


The code i'm testing :

Code: Select all

; #WBEM_INFINITE = $FFFFFFFF 
#COINIT_MULTITHREADED               = 0
#RPC_C_AUTHN_LEVEL_CONNECT          = 2     ;Authenticates the credentials of the client only when the client establishes a relationship with the server.
#RPC_C_AUTHN_LEVEL_CALL             = 3     ;Authenticates only at the beginning of each remote procedure call when the server receives the request.
#EOAC_NONE                          = 0     ;No Authentication capability flags are set
#RPC_C_AUTHN_WINNT                  = 10    ;Use the Microsoft NT LAN Manager (NTLM) SSP.
; #RPC_C_AUTHN_DEFAULT						= $FFFFFFFF
#RPC_C_AUTHZ_NONE                   = 0     ;The server performs no authorization. Currently, RPC_C_AUTHN_WINNT, RPC_C_AUTHN_GSS_SCHANNEL, And RPC_C_AUTHN_GSS_KERBEROS all use only RPC_C_AUTHZ_NONE.
#RPC_C_IMP_LEVEL_IMPERSONATE        = 3     ;The server process can impersonate the client's security context while acting on behalf of the client. When impersonating at this level, the impersonation token can only be passed across one machine boundary (can be used to access local resources such as files).
#wbemFlagReturnImmediately          = 16    ;Causes the call to return immediately.
#wbemFlagForwardOnly                = 32    ;Causes a forward-only enumerator to be returned. Forward-only enumerators are generally much faster and use less memory than conventional enumerators, but they do not allow calls to SWbemObject.Clone_.
#CLSCTX_INPROC_SERVER               = $1
#wbemFlagConnectUseMaxWait 			= $80

#CLSCTX_REMOTE_SERVER = $10

CompilerIf #PB_Compiler_Unicode
    Macro ptr(String) : @String : EndMacro
CompilerElse
    Macro ptr(String) : ansi2bstr(String) : EndMacro
CompilerEndIf

;=======================================
Procedure.i ansi2bstr(String$)
   size.i = MultiByteToWideChar_(#CP_ACP, 0, String$, Len(String$), 0, 0)
   If Size
    Dim unicode.u(size)
    MultiByteToWideChar_(#CP_ACP, 0, String$, Len(String$), @unicode(), size)   ;#CP_ACP
    For Counter.i = 0 To size
        tmp.s + Hex(unicode(Counter), #PB_Unicode)
    Next
    EndIf
    ProcedureReturn SysAllocString_(@unicode())
EndProcedure
;=======================================
Procedure.i bstr2string(bstr.i)
    Shared result.s
    result = PeekS(bstr, -1, #PB_Unicode)
    ProcedureReturn @result
EndProcedure
;=======================================


Procedure.s WMI_GetProcessOwner(Servername$, Processname$, user$, password$)
	Result$ = ""
	Select Servername$
		Case "" : Namespace$ = "\\.\root\CIMV2"
		Default : Namespace$ = "\\" + RemoveString(Servername$, "\") + "\root\CIMV2"
	EndSelect


Structure COAUTHIDENTITY
	*User
	UserLength.l
	*Domain
	DomainLength.l
	*Password
	PasswordLength.l
	Flags.l
EndStructure

domain$ = "domainname"

#SEC_WINNT_AUTH_IDENTITY_UNICODE = $2
authIdent.COAUTHIDENTITY
authIdent\PasswordLength = Len(password$)
authIdent\Password = @password$
authIdent\Flags = #SEC_WINNT_AUTH_IDENTITY_UNICODE
authIdent\User = @user$
authIdent\UserLength = Len(user$)
authIdent\Domain = @domain$
authIdent\DomainLength = Len(domain$)

*userAcct.COAUTHIDENTITY
*userAcct = @authIdent


	If CoInitializeEx_(0, #COINIT_MULTITHREADED) = 0         
		If CoInitializeSecurity_(0, -1, 0, 0, #RPC_C_AUTHN_LEVEL_DEFAULT, #RPC_C_IMP_LEVEL_IMPERSONATE, 0, #EOAC_NONE, 0) = 0             
			If CoCreateInstance_(?CLSID_WbemLocator, #Null, #CLSCTX_INPROC_SERVER, ?IID_IWbemLocator, @pLocator.IWbemLocator) = 0

				If pLocator\ConnectServer(ptr(Namespace$), @user$, @password$, #Null, #wbemFlagConnectUseMaxWait, #Null, #Null, @pService.IWbemServices) = 0
					
					If CoSetProxyBlanket_(pService, #RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE, 0, #RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE, *userAcct, #EOAC_NONE) = 0
; 						pService\queryinterface(?IID_IUnknown,@pUnknown.IUnknown) 
; 
; 						If CoSetProxyBlanket_(pUnknown, #RPC_C_AUTHN_NONE, #RPC_C_AUTHZ_NONE, 0, #RPC_C_AUTHN_LEVEL_NONE, #RPC_C_IMP_LEVEL_IMPERSONATE, 0, #EOAC_NONE) = 0

							If pService\ExecQuery(ptr("WQL"), ptr("SELECT * FROM Win32_Process"), #wbemFlagReturnImmediately|#wbemFlagForwardOnly, #Null, @pEnumerator.IEnumWbemClassObject) = 0

								If CoSetProxyBlanket_(pEnumerator, #RPC_C_AUTHN_WINNT, #RPC_C_AUTHZ_NONE, 0, #RPC_C_AUTHN_LEVEL_CALL, #RPC_C_IMP_LEVEL_IMPERSONATE, *userAcct, #EOAC_NONE) = 0

									pEnumerator\reset()
	; 								NbrReturned.i = 1
	; 								While NbrReturned 
	; 									pEnumerator\Next(#WBEM_INFINITE, 1, @pclsObj.IWbemClassObject, @NbrReturned)
	; 									;Get Processname
	; 									If pclsObj\Get(ptr("Name"), 0, @vtReturn.VARIANT, 0, 0) = 0          ;Debug PeekS(bstr2string(vtReturn\bstrVal))
	; 										Found.i = #False
	; 										If LCase(PeekS(bstr2string(vtReturn\bstrVal))) = Processname$
	; 											Found = #True
	; 											;Get Processpath
	; 											If pclsObj\Get(ptr("__PATH"), 0, @vtPath.VARIANT, 0, 0) = 0  ;Debug PeekS(bstr2string(vtPath\bstrVal))
	; 																															 ;Get Processowner
	; 												If pService\ExecMethod(vtPath\bstrVal, ptr("GetOwner"), 0, 0, 0, @pResult.IWbemClassObject, 0) = 0
	; 													If pResult\Get(ptr("User"), 0, @vtUser.VARIANT, 0, 0) = 0
	; 														Result$ = PeekS(bstr2string(vtUser\bstrVal))
	; 														VariantClear_(vtUser)
	; 													EndIf
	; 													pResult\release()   
	; 												EndIf   
	; 												VariantClear_(vtPath)       
	; 											EndIf 
	; 											Break
	; 										EndIf     
	; 										VariantClear_(vtReturn)
	; 										If Found = #False : Result$ = "Error - Unable to find the process" : EndIf
	; 									EndIf
	; 								Wend
	; 								pclsObj\release()   

								Else
									
								EndIf


							Else
								Result$ = "Error - Unable to retrieve the objects"
							EndIf
; 							pUnknown\release() 
; 						Else
; 							Result$ = "Error - Unable to set the IUnknown security"                           
; 						EndIf
					Else
						Result$ = "Error - Unable to set the proxy security"
					EndIf   
					pService\release()
				Else
					Result$ = "Error - Unable to connect to CIMV2"
				EndIf 
				pLocator\release()
			Else
				Result$ = "Error - Unable to create a WbemLocator"
			EndIf
		Else
			Result$ = "Error - Unable to set the security values for the process"
		EndIf
		CoUninitialize_()
	Else
		Result$ = "Error - Unable to launch COM"
	EndIf   
	ProcedureReturn Result$

	DataSection 
	  CLSID_IEnumWbemClassObject:
	  ;1B1CAD8C-2DAB-11D2-B604-00104B703EFD
	  Data.l $1B1CAD8C
	  Data.w $2DAB, $11D2
	  Data.b $B6, $04, $00, $10, $4B, $70, $3E, $FD
	  IID_IEnumWbemClassObject:
	  ;7C857801-7381-11CF-884D-00AA004B2E24
	  Data.l $7C857801
	  Data.w $7381, $11CF
	  Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24
	  CLSID_WbemLocator:
	  ;4590f811-1d3a-11d0-891f-00aa004b2e24
	  Data.l $4590F811
	  Data.w $1D3A, $11D0
	  Data.b $89, $1F, $00, $AA, $00, $4B, $2E, $24
	  IID_IWbemLocator:
	  ;dc12a687-737f-11cf-884d-00aa004b2e24
	  Data.l $DC12A687
	  Data.w $737F, $11CF
	  Data.b $88, $4D, $00, $AA, $00, $4B, $2E, $24
	  IID_IUnknown:
	  ;00000000-0000-0000-C000-000000000046
	  Data.l $00000000
	  Data.w $0000, $0000
	  Data.b $C0, $00, $00, $00, $00, $00, $00, $46

; 		IID_IWbemRefresher:
; 		Data.l $49353C99 : Data.w $516B, $11D1 : Data.b $AE, $A6, $00, $C0, $4F, $B6, $88, $20 
; 		CLSID_WbemRefresher:
; 		Data.l $C71566F2 : Data.w $561E, $11D1 : Data.b $AD, $87, $00, $C0, $4F, $D8, $FD, $FF 
; 		IID_IWbemConfigureRefresher:
; 		Data.l $49353C92 : Data.w $516B, $11D1 : Data.b $AE, $A6, $00, $C0, $4F, $B6, $88, $20 
; 		IID_IWbemObjectAccess:
; 		Data.l $49353C9A : Data.w $516B, $11D1 : Data.b $AE, $A6, $00, $C0, $4F, $B6, $88, $20 
	EndDataSection   
EndProcedure



;=======================================
;=======================================
;=======================================
Servername$ = "computername"
Processname$ = "processusname"

Debug WMI_GetProcessOwner(Servername$, Processname$, "user", "password")
A link to a working C++ version : https://pastebin.com/XAcDpLRH
Windows 10 Pro x64
PureBasic 6.04 x64
Marc56us
Addict
Addict
Posts: 1477
Joined: Sat Feb 08, 2014 3:26 pm

Re: WMI

Post by Marc56us »

Indeed I could use wmic command or Powershell command or ... but PB could do that and it should work with the right paramaters.
Yes, ... and no :wink:
PB cannot do it natively since all examples use APIs (function names suffixed by an underscore_)
This also means that the final program in PB can be blocked by most antivirus software. (As it would be with autoit)

It is not a defeat to call an external program (e. g. wmic.exe, especially since it is a program already integrated in Windows since XP) as the main engine in the background; we usually do it for other tools much more efficient than what we could do ourselves (Ping, Robocopy, 7zip, Tasklist/Taskkill, WinScp...) and we also avoid many bugs.
The interface and processing of the output is done with PB and the motor is subcontracted to the external program by executing it in a separate task. (RunProgram() can hide client Window)

Then we need to see if we are coding for the challenge/learning or if we are looking for a (proven) solution. It all depends on the use. 8) (Work or research)
Integrating a hundred lines of code created by others without (sometime) knowing each of the functions may be more risky than a command already made (and known by anti-virus software)

:idea: In any case, thank you for opening this subject. This allowed me to learn how to use WMI (on the network) and it works :!: very well thanks to wmic.exe.
I had a ̶g̶r̶e̶a̶t̶ ̶i̶r̶r̶i̶t̶a̶t̶i̶o̶n̶ :? little trouble (little = several hours :mrgreen: ) configuring my servers to accept remote WMI requests, but it works. All I have to do now is to make the graphical interface and process the result around the program (launched in Thread)

Thank you. Learning something new every day makes me happy.
:)

Edit: Small test done viewtopic.php?f=12&t=73972 :)
novablue
Enthusiast
Enthusiast
Posts: 165
Joined: Sun Nov 27, 2016 6:38 am

Re: WMI

Post by novablue »

I have an odd problem with this code, for some reason CoInitializeSecurity_() fails if i have EnableWindowDrop() in the code.

Code: Select all

Define Window.i = OpenWindow(#PB_Any, 0, 0, 500, 500, "Window", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)

EnableWindowDrop(Window, #PB_Drop_Files, #PB_Drag_Copy) ; Comment out and it works

;List only the "Caption" and "OSArchitecture" Properties from the "Win32_OperatingSystem" Class
Debug WMI("SELECT Caption, OSArchitecture FROM Win32_OperatingSystem")

;List all Properties (*) from the "Win32_OperatingSystem" Class
Debug WMI("Select * FROM Win32_OperatingSystem")
User avatar
chi
Addict
Addict
Posts: 1028
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: WMI

Post by chi »

novablue wrote: Tue May 24, 2022 5:19 am I have an odd problem with this code, for some reason CoInitializeSecurity_() fails if i have EnableWindowDrop() in the code.

Code: Select all

Define Window.i = OpenWindow(#PB_Any, 0, 0, 500, 500, "Window", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)

EnableWindowDrop(Window, #PB_Drop_Files, #PB_Drag_Copy) ; Comment out and it works

;List only the "Caption" and "OSArchitecture" Properties from the "Win32_OperatingSystem" Class
Debug WMI("SELECT Caption, OSArchitecture FROM Win32_OperatingSystem")

;List all Properties (*) from the "Win32_OperatingSystem" Class
Debug WMI("Select * FROM Win32_OperatingSystem")
PB already calls CoInitializeEx_ when creating windows... A quick (maybe dirty) fix would be to put CoUninitialize_ before the second call.

Code: Select all

    CoUninitialize_()
    CoInit = CoInitializeEx_(0, #COINIT_APARTMENTTHREADED | #COINIT_DISABLE_OLE1DDE)
Et cetera is my worst enemy
Post Reply