Find my own process ID in VBScript

后端 未结 10 1000
小蘑菇
小蘑菇 2020-11-28 14:49

I\'m using the following code snippet to determine what process ID my vbscript is running as:

On Error Resume Next
Dim iMyPID : iMyPID = GetObject(\"winmgmts         


        
相关标签:
10条回答
  • 2020-11-28 14:57

    Powershell can be used to retrieve the calling VBScript process ID. This approach utilizes the optional argument of the exit command which specifies the program's exit code. And, if the optional 3rd argument of the WShell.Run method is set to True, then it will return the exit code (which is the VBScript process ID) after powershell has closed.

    Dim sCmd
    Dim WShell
    
    sCmd = _
    "powershell -command exit " & _
    "(gwmi Win32_Process -Filter " & _
    "\""processid='$PID'\"").parentprocessid"
    Set WShell = CreateObject("WScript.Shell")
    MsgBox WShell.Run(sCmd, 0, True)
    
    0 讨论(0)
  • 2020-11-28 15:01

    I just found this thread that partly solved my problem. Thank you all.

    "the code is unable to determine which process ID belongs to which script" : true, but as this is the first task that your script must achieve , you can keep the Pid that has the shortest lifetime.

     Set com = CreateObject("Wscript.Shell")
    
     Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
     Set colProcess = objSWbemServices.ExecQuery ("Select * From Win32_Process")
     dim toto, thisPid
    
     thisPid=""
     toto=200 ' just a high value like 200sec 
     For Each objProcess In colProcess
    
         If InStr (objProcess.CommandLine, WScript.ScriptName) <> 0  Then
            Ptime=((Cdbl(objProcess.UserModeTime)+Cdbl(objProcess.KernelModeTime))/10000000)
            if toto > Ptime then
                toto = Ptime
                thisPid = objProcess.ProcessId
            End If
         End If
     Next
    
     If thisPid="" then
        WScript.Echo "unable to get the PID"
     Else
        WScript.Echo "PID of this script : "&thisPid
     End If
    

    Except if you fired scripts quicker more than each one can retrieve their Pid, everything must be ok.

    0 讨论(0)
  • 2020-11-28 15:03

    mshta terminates itself immediately. Maybe it's too late to achieve parent process id by using WMI service.
    So, I'd use something like this to eliminate concurrent script processes.

    1. Generate random things.
    2. Determine an application which could be installed on each system, never terminates by itself (e.g. command prompt with /k parameter).
    3. Start the application in hidden mode with generated random argument (WshShell.Run).
    4. Wait a few milliseconds
    5. Query the running processes by using command line argument value.
    6. Get the ParentProcessId property.
    Function CurrProcessId
        Dim oShell, sCmd, oWMI, oChldPrcs, oCols, lOut
        lOut = 0
        Set oShell  = CreateObject("WScript.Shell")
        Set oWMI    = GetObject(_
            "winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
        sCmd = "/K " & Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
        oShell.Run "%comspec% " & sCmd, 0
        WScript.Sleep 100 'For healthier skin, get some sleep
        Set oChldPrcs = oWMI.ExecQuery(_
            "Select * From Win32_Process Where CommandLine Like '%" & sCmd & "'",,32)
        For Each oCols In oChldPrcs
            lOut = oCols.ParentProcessId 'get parent
            oCols.Terminate 'process terminated
            Exit For
        Next
        CurrProcessId = lOut
    End Function
    
    Dim ProcessId
    ProcessId = CurrProcessId 'will remain valid indefinitely
    
    WScript.Echo ProcessId
    
    0 讨论(0)
  • 2020-11-28 15:08

    I like Kul-Tigin's idea (+1), and Asok Smith's idea (based on .Exec) deserve respect (+1), and it w'd been even better if .Exec run hidden process. So, to feed my curiosity, I also toyed with this and this's what I did.

    ts1 = Timer : res1 = CurrProcessId : te1 = Timer - ts1
    ts2 = Timer : res2 = ThisProcessId : te2 = Timer - ts2
    WScript.Echo "CurrProcessId", res1, FormatNumber(te1, 6), _
        vbCrLf & "ThisProcessId", res2, FormatNumber(te2, 6), _
        vbCrLf & "CurrProcessId / ThisProcessId = " & te1 / te2
    
    '> CurrProcessId 6946 0,437500
    '> ThisProcessId 6946 0,015625
    '> CurrProcessId / ThisProcessId = 28
    
    Function ThisProcessId
        ThisProcessId = 0
        Dim sTFile, oPrc
        With CreateObject("Scripting.FileSystemObject")
            sTFile = .BuildPath(.GetSpecialFolder(2), "sleep.vbs")
            With .OpenTextFile(sTFile, 2, True)
                .Write "WScript.Sleep 1000"
            End With
        End With
        With CreateObject("WScript.Shell").Exec("WScript " & sTFile)
            For Each oPrc In GetObject("winmgmts:\\.\root\cimv2").ExecQuery(_
            "Select * From Win32_Process Where ProcessId=" & .ProcessID)
            Exit For : Next
            ThisProcessId = oPrc.ParentProcessId
        End With
    End Function
    

    28 times faster(!), not bad :)

    0 讨论(0)
  • 2020-11-28 15:12

    You may use Sleep from kernel32 instead of mshta.

    MsgBox GetProcId()
    
    Function GetProcId()
        With GetObject("winmgmts:\\.\root\CIMV2:Win32_Process.Handle='" & CreateObject("WScript.Shell").Exec("rundll32 kernel32,Sleep").ProcessId & "'")
            GetProcId = .ParentProcessId
            .Terminate
        End With
    End Function
    

    Code taken from here.

    Also there is parent process name detection based on this approach.

    0 讨论(0)
  • 2020-11-28 15:13

    Here is a better one, but in JScript (sorry, you translate it to VB ...)

    var WshShell = WScript.CreateObject("WScript.Shell");
    var objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2");
    var childProcess =
        WshShell.Exec
        (
            '"' + WshShell.Environment('PROCESS')('ComSpec') + '"'
            +
            " /C Echo \"Text lines\" && Set /p VarName="
        );
    childProcess.StdOut.ReadLine();
    var current_pid =
        objWMIService.ExecQuery
            (
            "Select * From Win32_Process Where ProcessId=" + childProcess.ProcessID
            );
    current_pid = (new Enumerator(current_pid)).item().ParentProcessId;
    if (current_pid)
    {
        childProcess.StdIn.WriteLine("value");  // child process should now exit
        WScript.Echo("Current PID: " + current_pid);
    }
    else
    {
        WScript.StdErr.WriteLine("Get current PID from WMI failed.");
        WScript.Quit(7);
    }
    
    0 讨论(0)
提交回复
热议问题