WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

Samples from Users
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Account Name Associated with a Process


Question:

Is there a way to associate a process ID with the network user that spawned it?

We have an application that runs as a service and takes request from users to open, read and write to files. So for example if I want to open file X, I tell the Dataserver what file I want to open and the data I want from it. Then it spawns a service specifically for me(my account) and it will go open the file(locally..) then read the data from the file then send it all back to me. This is keeps my machine from handling all the traffic that would be required to do all those operations and reduces it down to just sending a few requests. The problem is that when the file is opened it is opened locally by the spawned process so MS File Management stuff wont report it and I need to see who has what files opened and to do that I need to see which spawn of the proserv.exe file belongs to which user.

Answer:

There is probably a way to do this that requires some Win32 API function calls to make it happen.

Here's some code to look over. I have not added any error handling to the UDF, but it works on my test system. I need still need to test it on a workstation that is a domain member with a domain user logged on, but the basic principle of the UDF is sound and should work OK for your needs.

; GetAccountFromPID_UDF.wbt
; 32-bit
;
; UDF library to obtain the account name associated with a process.
;
; Rigorous error handling has not been implemented in this UDF.
;
;


#DEFINEFUNCTION udfGetAccountFromPID(nPID)

if (!IsInt(nPID)) then return ''

; Set up the constants & binary buffers needed to do the job.

hProcess = 0
hToken = 0
AcctName = ''
DomainName = ''

; #define PROCESS_QUERY_INFORMATION (0x0400) 
; #define TOKEN_QUERY (0x0008)

ProcQueryInfo = 1024
TokQueryInfo = 8

TokenUser = 1

nHandleBufSize = 4
hHandleBuf = BinaryAlloc(nHandleBufSize)

nDWORDBufSize = 4
hDWORDBuf = BinaryAlloc(nDWORDBufSize)

nSIDBufSize = 1024 ; Semi-arbitrary length that is good for all known SID values as of Win2K3 & older
hSIDBuf = BinaryAlloc(nSIDBufSize)

nNameBufSize = 512 ; Semi-arbitrary length that is good for all known account name values as of Win2K3 & older
hNameBuf = BinaryAlloc(nNameBufSize)

nNameLenBufSize = 4
hNameLenBuf = BinaryAlloc(nNameLenBufSize)

nDomainBufSize = 512 ; Semi-arbitrary length that is good for all known account name values as of Win2K3 & older
hDomainBuf = BinaryAlloc(nDomainBufSize)

nDomainLenBufSize = 4
hDomainLenBuf = BinaryAlloc(nDomainLenBufSize)


; Open a handle to the process for query information access.

hProcess = DllCall('KERNEL32.DLL',long:'OpenProcess',long:ProcQueryInfo,long:0,long:nPID)

; Open a handle to the process' access token for query information access.

Result = DllCall('ADVAPI32.DLL',long:'OpenProcessToken',long:hProcess,long:TokQueryInfo,lpbinary:hHandleBuf)

BinaryEodSet(hHandleBuf,nHandleBufSize)

hToken = BinaryPeek4(hHandleBuf,0)

; Obtain the SID associated with the access token.

Result = DllCall('ADVAPI32.DLL',long:'GetTokenInformation',long:hToken,long:TokenUser,lpbinary:hSIDBuf,long:nSIDBufSize,lpbinary:hDWORDBuf)

BinaryEodSet(hSIDBuf,BinaryPeek4(hDWORDBuf,0))

; Lookup the account name associated with the SID.
; Please note that we cannot use the lpbinary parameter passing method with hSIDBuf as the actual SID pointer within the buffer
; does not translate properly once the binary buffer is being manipulated within WinBatch. To work around this, we must account
; for the fact that the SID structure within the buffer begins 8 bytes after the start of the buffer. So, we're going to revert
; to using an IntControl() call that existed prior to the implementation of lpbinary in order to get the address of the buffer's
; data segment in memory and then we'll do some pointer arithmetic to make things work out properly.

BinaryPoke4(hNameLenBuf,0,nNameBufSize)
BinaryPoke4(hDomainLenBuf,0,nDomainBufSize)

Result = DllCall('ADVAPI32.DLL',long:'LookupAccountSidA',lpnull,long:IntControl(42,hSIDBuf,0,0,0)+8,lpbinary:hNameBuf,lpbinary:hNameLenBuf,lpbinary:hDomainBuf,lpbinary:hDomainLenBuf,lpbinary:hDWORDBuf)
RC = DllLastError()

BinaryEodSet(hNameBuf,BinaryPeek4(hNameLenBuf,0))
BinaryEodSet(hDomainBuf,BinaryPeek4(hDomainLenBuf,0))

AcctName = BinaryPeekStr(hNameBuf,0,nNameBufSize)
DomainName = BinaryPeekStr(hDomainBuf,0,nDomainBufSize)

if (DomainName == 'BUILTIN') then DomainName = ''

if (DomainName != '')
AcctName = StrCat(DomainName,'\',AcctName)
endif


; Close the handles we used.

Result = DllCall('KERNEL32.DLL',long:'CloseHandle',long:hProcess)
hProcess = 0

Result = DllCall('KERNEL32.DLL',long:'CloseHandle',long:hToken)
hToken = 0


; Free up the buffers we used.

hHandleBuf = BinaryFree(hHandleBuf)
hDWORDBuf = BinaryFree(hDWORDBuf)
hSIDBuf = BinaryFree(hSIDBuf)
hNameBuf = BinaryFree(hNameBuf)
hNameLenBuf = BinaryFree(hNameLenBuf)
hDomainBuf = BinaryFree(hDomainBuf)
hDomainLenBuf = BinaryFree(hDomainLenBuf)

return AcctName

#ENDFUNCTION


; Sample code
;
;Title01 = 'Get Account Name From PID'
; Provide a valid PID value (integer)
;PID = 0
;Result = udfGetAccountFromPID(PID)
;TempMsg = StrCat('PID = ',PID,@CRLF,'User = "',Result,'"')
;Message(Title01,TempMsg)
;exit

Article ID:   W16679
File Created: 2005:02:18:12:21:52
Last Updated: 2005:02:18:12:21:52