полезный ответ AdminOfThings и полезный ответ Compo оба предоставляют надежные решения .
Вот альтернативное решение, котороеработает, если вы готовы сделать одно предположение :
- Если ваш пакет с именем, скажем,
foo.cmd
, найдет любой процесс cmd.exe
, выполняющий пакетный файл с именем foo.cmd
действительно выполняет тот же пакетный файл.
Решение использует два преимущества:
A cmd.exe
В консольном окне добавляется имя / путь(в зависимости от специфики вызова) к заголовку окна ;например, если вы вызываете foo.cmd
из текущего каталога, заголовок окна изменится на Command Prompt - foo.cmd
.
tasklist.exe /v
также выводит заголовки главного окна соответствующих процессов,
@echo off
setlocal
rem # Count the cmd.exe processes that have the name of this batch file
rem # in their window title.
for /f %%c in ('tasklist /v /fi "imagename eq cmd.exe" ^| find /C "%~nx0"') do (
REM # If more than 1 process matches, another instance of this batch file
REM # must already be running, so issue a warning and exit.
if %%c GTR 1 echo Powershell script already running, wait for it to finish. >&2 & exit /b 1
)
echo Running PowerShell script...
rem # Run the PowerShell script.
rem # As @Compo advises, it's better to use -File to invoke scripts
rem # and to use -ExecutionPolicy Bypass if needed (and you trust the script).
powershell.exe -file U:\path\to\your\PowerShellScript.ps1
pause
С большим усилием вы можете сделать решение более устойчивым :
Назначить уникальный заголовок пользовательского окна в текущем окне консоли.
Сначала проверьте cmd.exe
процессов с этим заголовком: если найдено, выйдите;если нет, задайте уникальный заголовок окна и запустите сценарий PowerShell.
Предупреждение : вы должны сбросить заголовок окна при завершении , в противном случаеон будет задерживаться после выполнения командного файла:
Проблема в том, что если кто-то прервет ваш командный файл с помощью Ctrl + C , вы не получитешанс сбросить заголовок.
Однако это не будет проблемой, если ваш пакетный файл был запущен в окне консоли, которое автоматически закрывается, когда пакетный файл заканчивается, например, еслион был запущен с рабочего стола или из Проводника.
@echo off
setlocal
rem # Get and save the current window title.
rem # Note: This - complex and somewhat slow - solution is necessary,
rem # because the `title` only supports *setting* a window title,
rem # not *getting it*.
for /f "usebackq delims=" %%t in (`powershell -noprofile -c "[Console]::Title.Replace(' - '+[Environment]::CommandLine,'') -replace '(.+) - .+', '$1'"`) do set origTitle=%%t
rem # Choose a unique window title.
set "titleWhileRunning=Some.ps1 is running..."
rem # If a cmd.exe process with the same window title already exists
rem # we issue a warning and exit
tasklist /v /fi "imagename eq cmd.exe" /fi "windowtitle eq %titleWhileRunning%" | find "%titleWhileRunning%" >NUL
if %ERRORLEVEL% EQU 0 echo Powershell script already running, wait for it to finish. >&2 & exit /b 1
rem # Set the new title that indicates that the script is running.
title %titleWhileRunning%
echo Running PowerShell script...
rem # Run the PowerShell script.
rem # As @Compo advises, it's better to use -File to invoke scripts
rem # and to use -ExecutionPolicy Bypass if needed (and you trust the script).
powershell.exe -file U:\path\to\your\PowerShellScript.ps1
rem # Restore the original window title.
title %origTitle%
pause