VBScript to check for open process by user

不打扰是莪最后的温柔 提交于 2019-12-23 15:10:31

问题


I need a VBScript that will check if a process is in use by a specific user:

Agent clicks program icon --> batch file calls for progcheck.vbs -->

progcheck.vbs looks to see is "whatever.exe" is running under that user only -->

if program is running under that user then MsgBox "Program running" --> wscript.quit (this needs to terminate out of the batch file)

else --> return to batch file.

I have tried this with tasklist in a batch file and the script works, but takes forever to run for a domain user. Want to do this in vbscript anyway.

*** UPDATED SCRIPT WITH MODS 10/12 *****

OPTION EXPLICIT

    DIM strComputer,strProcess, strUserName,wshShell

    Set wshShell = WScript.CreateObject( "WScript.Shell" )
    strUserName = wshShell.ExpandEnvironmentStrings( "%USERNAME%" )

    strComputer = "." ' 
    strProcess = "notepad.exe"


    IF isProcessRunning(strComputer,strProcess,strUserName) THEN
            If MsgBox ("Notepad needs to be closed.", 1) = 1 then
                wscript.Quit(1)
            End If
    END IF

FUNCTION isProcessRunning(BYVAL strComputer,BYVAL strProcessName,BYVAL strUserName)

    DIM objWMIService, strWMIQuery

    strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "' AND owner like '" &strUserName& "'" 

    SET objWMIService = GETOBJECT("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _ 
            & strComputer & "\root\cimv2") 


    IF objWMIService.ExecQuery(strWMIQuery).Count > 0 THEN
        isProcessRunning = TRUE
    ELSE
        isProcessRunning = FALSE
    END If

End Function

Let me know what you think and where I have it wrong. Thanks in advance.


回答1:


UPDATED CODE v3: review comments for help

OPTION EXPLICIT

    DIM strComputer, strProcess, strUserName, wshShell

    Set wshShell = WScript.CreateObject( "WScript.Shell" )
    strUserName = wshShell.ExpandEnvironmentStrings( "%USERNAME%" )
    strComputer = "."
    strProcess = "notepad.exe" 'change this to whatever you are trying to detect

    IF isProcessRunning(strComputer, strProcess, strUserName) THEN
        If MsgBox ("Notepad needs to be closed.", 1) = 1 then
            wscript.Quit(1) 'you need to terminate the process if that's your intention before quitting
        End If
    Else
        msgbox ("Process is not running") 'optional for debug, you can remove this
    END IF

FUNCTION isProcessRunning(ByRef strComputer, ByRef strProcess, ByRef strUserName)

    DIM objWMIService, strWMIQuery, objProcess, strOwner, Response

    strWMIQuery = "SELECT * FROM Win32_Process WHERE NAME = '" & strProcess & "'"

    SET objWMIService = GETOBJECT("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2").ExecQuery(strWMIQuery)

    IF objWMIService.Count > 0 THEN
        msgbox "We have at least ONE instance of Notepad"
        For Each objProcess in objWMIService
            Response = objProcess.GetOwner(strOwner)
            If Response <> 0 Then
                'we didn't get any owner information - maybe not permitted by current user to ask for it
                Wscript.Echo "Could not get owner info for process [" & objProcess.Name & "]" & VBNewLine & "Error: " & Return
            Else 
                Wscript.Echo "Process [" & objProcess.Name & "] is owned by [" & strOwner & "]" 'for debug you can remove it
                if strUserName = strOwner Then
                    msgbox "we have the user who is running notepad"
                    isProcessRunning = TRUE
                Else
                    'do nothing as you only want to detect the current user running it
                    isProcessRunning = FALSE
                End If
            End If
        Next
    ELSE
        msgbox "We have NO instance of Notepad - Username is Irrelevant"
        isProcessRunning = FALSE
    END If

End Function

You can use the following function:

FUNCTION isProcessRunning(BYVAL strComputer,BYVAL strProcessName)

    DIM objWMIService, strWMIQuery

    strWMIQuery = "Select * from Win32_Process where name like '" & strProcessName & "'"

    SET objWMIService = GETOBJECT("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" _ 
            & strComputer & "\root\cimv2") 


    IF objWMIService.ExecQuery(strWMIQuery).Count > 0 THEN
        isProcessRunning = TRUE
    ELSE
        isProcessRunning = FALSE
    END IF

END FUNCTION

For local computer you would use "."

For the process name, you would use the executable "notepad.exe"

For the rest of the code, you could can use something simple:

OPTION EXPLICIT
DIM strComputer,strProcess

strComputer = "." ' local computer
strProcess = "notepad.exe" 'whatever is the executable

IF isProcessRunning(strComputer,strProcess) THEN
    'do something
ELSE
    'do something else or nothing
    wscript.echo strProcess & " is NOT running on computer '" & strComputer & "'"
END IF

That should do it.

EXTRA

To show every process running, then just run:

Option Explicit
Dim objWMIService, objProcess, colProcess
Dim strComputer, strList

strComputer = "."

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _ 
& strComputer & "\root\cimv2") 

Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process")

For Each objProcess in colProcess
    strList = strList & vbCr & _
    objProcess.Name
Next

WSCript.Echo strList
WScript.Quit



回答2:


in terminal server this function can be very slow, all the GetOwner calls are terrible in performance.

A very fast solution i created is to narrow the query using SessionID of the current user (assuming we want only current user's processes) So I added this code:

SessionID can be obtained this way:

Dim oExec, sOutput, iUserPos, iUserLen, iStatePos, SessionID
dim oShell, userName

Set oShell = CreateObject("Wscript.Shell")
userName = oShell.ExpandEnvironmentStrings("%USERNAME%")

Set oExec = oShell.Exec("query session %username%")
sOutput = LCase(oExec.StdOut.ReadAll)
iUserPos = InStr(sOutput, LCase(userName))
iStatePos = InStr(sOutput, "active")
iUserLen = Len(userName)

SessionID = CInt(Trim(Mid(sOutput, iUserPos+iUserLen, iStatePos-iUserPos-iUserLen)))

Changed the function from the previous post:

Function isProcessRunning(ByRef strComputer, ByRef strProcess, ByRef strUserName, byRef sessionID)
    DIM objWMIService, strWMIQuery, objProcess, strOwner, Response

    strWMIQuery = "SELECT * FROM Win32_Process WHERE SessionId = " & sessionID & " And NAME = '" & strProcess & "'"

    SET objWMIService = GETOBJECT("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2").ExecQuery(strWMIQuery)

    IF objWMIService.Count > 0 THEN
        'msgbox "We have at least ONE instance of Notepad"
        For Each objProcess in objWMIService
            Response = objProcess.GetOwner(strOwner)
            If Response = 0 Then
                'Wscript.Echo "Process [" & objProcess.Name & "] is owned by [" & strOwner & "]" 'for debug you can remove it
                if strUserName = strOwner Then
                    'msgbox "we have the user who is running notepad"
                    isProcessRunning = TRUE
                Else
                    'do nothing as you only want to detect the current user running it
                    isProcessRunning = FALSE
                End If
                'else 
                 'we didn't get any owner information - maybe not permitted by current user to ask for it
                 'Wscript.Echo "Could not get owner info for process [" & objProcess.Name & "]" & VBNewLine & "Error: " & Return
            End If
        Next
    ELSE
        'msgbox "We have NO instance of Notepad - Username is Irrelevant"
        isProcessRunning = FALSE
    END If

End Function


来源:https://stackoverflow.com/questions/19328981/vbscript-to-check-for-open-process-by-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!