1

Тема: VBScript: защита от повторного запуска скрипта

Скрипт демонстрирует простейший способ защиты от повторного запуска:

Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FileExists("C:\" & WScript.ScriptName & ".txt") Then
    MsgBox "Скрипт уже запущен"
    WScript.Quit
End If
FSO.CreateTextFile "C:\" & WScript.ScriptName & ".txt"
WScript.Sleep 60000 'вместо этой строки следует вставить операторы своей программы
FSO.DeleteFile "C:\" & WScript.ScriptName & ".txt"
Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

2

Re: VBScript: защита от повторного запуска скрипта

Другой способ. Ищем в запущенных процессах имя нашего скрипта в командных строках этих процессов:

On Error Resume Next
Set objService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\CIMV2")
If Err.Number <> 0 Then
    WScript.Echo Err.Number & ": " & Err.Description
    WScript.Quit
End If
QueryText = "SELECT * FROM Win32_Process WHERE CommandLine LIKE '%" & WScript.ScriptName & "%'"
Set colProc = objService.ExecQuery(QueryText)
If colProc.Count > 1 Then
    WScript.Echo "Скрипт уже запущен"
    WScript.Quit
End If
WScript.Sleep 60000 'вместо этой строки следует вставить операторы своей программы
Предложения в русском языке начинаются с большой буквы и заканчиваются точкой.
В названии ветки всегда должен быть указан язык программирования или среда исполнения скрипта, если это возможно.

3

Re: VBScript: защита от повторного запуска скрипта

Уточнённый текст WQL-запроса (в предыдущем примере скрипт, открытый в Блокноте, воспринимался как уже запущенный), учитывающий, что исполняющими хостами для WSH могут быть только «wscript.exe» или «cscript.exe» (если Вы используете дополнительные хосты — исправьте WQL-запрос соответствующим образом):

"SELECT Name, CommandLine, ProcessID FROM Win32_Process WHERE " & _
"Name LIKE '%[cw]script.exe' AND " & _
"CommandLine LIKE '%[cw]script%" & WScript.ScriptName & "%'", "WQL", 0)

Расширенный пример:

Option Explicit

Dim objSWbemServicesEx

Dim collSWbemObjectSet
Dim objSWbemObjectEx

Dim currPID


Set objSWbemServicesEx = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

currPID = GetScriptProcessID()

Set collSWbemObjectSet = objSWbemServicesEx.ExecQuery( _
    "SELECT Name, CommandLine, ProcessID FROM Win32_Process WHERE " & _
    "Name LIKE '%[cw]script.exe' AND " & _
    "CommandLine LIKE '%[cw]script%" & WScript.ScriptName & "%'", "WQL", 0)

If collSWbemObjectSet.Count > 1 Then
    WScript.Echo "Скрипт уже запущен (* — текущий процесс):"
    
    For Each objSWbemObjectEx In collSWbemObjectSet
        If currPID = objSWbemObjectEx.ProcessID Then
            WScript.Echo " * PID:" & vbTab & objSWbemObjectEx.ProcessID & vbTab & "Command line: " & objSWbemObjectEx.CommandLine
        Else
            WScript.Echo "   PID:" & vbTab & objSWbemObjectEx.ProcessID & vbTab & "Command line: " & objSWbemObjectEx.CommandLine
        End If
    Next
    
    WScript.Quit 1
End If

WScript.Echo "Единственный экземпляр скрипта:"

For Each objSWbemObjectEx In collSWbemObjectSet
    WScript.Echo " * PID:" & vbTab & objSWbemObjectEx.ProcessID & vbTab & "Command line: " & objSWbemObjectEx.CommandLine
Next

WScript.Echo
WScript.Echo "Здесь операторы Вашего скрипта. В примере же просто ждём 60 секунд."
WScript.Echo "Вы можете за это время попробовать запустить другой экземпляр этого же скрипта."

WScript.Sleep 60 * 1000


Set collSWbemObjectSet = Nothing
Set objSWbemServicesEx = Nothing

WScript.Quit 0
'=============================================================================

'=============================================================================
' WSH: как из скрипта определить его идентификатор процесса (PID)
' (http://forum.script-coding.com/viewtopic.php?id=2454)
'
Function GetScriptProcessID()
    With WScript.CreateObject("WScript.Shell").Exec("""mshta.exe"" ""<HTML><HEAD><HTA:APPLICATION APPLICATIONNAME='GetParentPID' WINDOWSTATE='minimize' SHOWINTASKBAR='no'</HEAD></HTML>""")
        GetScriptProcessID = objSWbemServicesEx.Get("Win32_Process.Handle='" & CStr(.ProcessID) &"'").ParentProcessID
        .Terminate
    End With
End Function
'=============================================================================

Первый запуск скрипта:

Единственный экземпляр скрипта:
 * PID:    5888    Command line: CScript.exe "C:\Песочница\39\0001.vbs" 

Здесь операторы Вашего скрипта. В примере же просто ждём 60 секунд.
Вы можете за это время попробовать запустить другой экземпляр этого же скрипта.

Второй запуск скрипта (во время работы первого):

Скрипт уже запущен (* - текущий процесс):
   PID:    4912    Command line: CScript.exe "C:\Песочница\39\0001.vbs" 
 * PID:    4708    Command line: CScript.exe "C:\Песочница\39\0001.vbs"