如何防止同一PowerShell 7脚本的多个实例?

发布于 2025-02-11 17:56:01 字数 1155 浏览 1 评论 0原文

在构建服务器上的上下文

,将启动PowerShell 7脚本script.ps1,并将在远程计算机的后台运行。

我想要

一个保险箱以确保script.ps1脚本最多1个实例始终在构建服务器或远程计算机上运行。

我尝试的是:

我尝试处理PowerShell 7背景作业(通过执行script.ps1作为包装脚本中的作业wrapper.ps1),但是这没有解决问题,因为在其他PowerShell会议上没有继续(也无法访问)工作。

我尝试的是这样:

# inside wrapper.ps1

$running_jobs = $(Get-Job -State Running) | Where-Object {$_.Name -eq "ImportantJob"}

if ($running_jobs.count -eq 0) {
    Start-Job .\script.ps1 -Name "ImportantJob" -ArgumentList @($some_variables)
} else {
    Write-Warning "Could not start new job; Existing job detected must be terminated beforehand."
}

重申一下,问题是$ running_jobs仅返回当前会话中运行的作业,因此此代码仅限制每个会话的一个作业,允许多个实例如果多个会议被错误打开,请进行。

我还尝试了:

我尝试查看get-ciminstance

 $processes = Get-CimInstance -ClassName Win32_Process | Where-Object {$_.Name -eq "pwsh.exe"}

虽然这确实返回了当前运行的PowerShell实例,但这些元素没有对正在执行的脚本进行任何信息,如我运行后所示:

foreach ($p in $processes) {
     $p | Format-List *
}

因此,我迷路了,我觉得我缺少一些东西。 感谢任何帮助或建议。

Context

On a build server, a PowerShell 7 script script.ps1 will be started and will be running in the background in the remote computer.

What I want

A safenet to ensure that at most 1 instance of the script.ps1 script is running at once on the build server or remote computer, at all times.

What I tried:

I tried meddling with PowerShell 7 background jobs (by executing the script.ps1 as a job inside a wrapper script wrapper.ps1), however that didn't solve the problem as jobs do not carry over (and can't be accessed) in other PowerShell sessions.

What I tried looks like this:

# inside wrapper.ps1

$running_jobs = $(Get-Job -State Running) | Where-Object {$_.Name -eq "ImportantJob"}

if ($running_jobs.count -eq 0) {
    Start-Job .\script.ps1 -Name "ImportantJob" -ArgumentList @($some_variables)
} else {
    Write-Warning "Could not start new job; Existing job detected must be terminated beforehand."
}

To reiterate, the problem with that is that $running_jobs only returns the jobs running in the current session, so this code only limits one job per session, allowing for multiple instances to be ran if multiple sessions were mistakenly opened.

What I also tried:

I tried to look into Get-CimInstance:

 $processes = Get-CimInstance -ClassName Win32_Process | Where-Object {$_.Name -eq "pwsh.exe"}

While this does return the current running PowerShell instances, these elements carry no information on the script that is being executed, as shown after I run:

foreach ($p in $processes) {
     $p | Format-List *
}

I'm therefore lost and I feel like I'm missing something.
I appreciate any help or suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

简美 2025-02-18 17:56:01

我喜欢使用$ env:programData使用companyname \ projectName方案的位置定义配置路径,以便我可以将“每个系统”配置放置。
您可以将类似的方案与定义位置使用类似的方案来存储脚本运行并在其末尾删除时创建的锁定文件(如注释中所建议的)。

然后,如果需要,则由您添加其他检查(如果锁定在锁定仍然存在的情况下脚本过早退出会发生


# Define default path (Not user specific)
$ConfigLocation = "$Env:ProgramData\CompanyName\ProjectName"
# Create path if it does not exist
New-Item -ItemType Directory -Path $ConfigLocation -EA 0 | Out-Null

$LockFilePath =  "$ConfigLocation\Instance.Lock"

$Locked = $null -ne (Get-Item -Path $LockFilePath -EA 0)
if ($Locked) {Exit}


# Lock
New-Item -Path $LockFilePath

# Do stuff 

# Remove lock
Remove-Item -Path $LockFilePath

什么 一个时间表和设置“如果任务已经运行,则适用以下规则:不启动新实例”。从那里开始,您没有调用原始脚本,而是调用刚刚启动计划任务的代理脚本。

I like to define a config path in the $env:ProgramData location using a CompanyName\ProjectName scheme so I can put "per system" configuration.
You could use a similar scheme with a defined location to store a lock file created when the script run and deleted at the end of it (as suggested already within the comments).

Then, it is up to you to add additional checks if needed (What happen if the script exit prematurely while the lock is still present ?)

Example


# Define default path (Not user specific)
$ConfigLocation = "$Env:ProgramData\CompanyName\ProjectName"
# Create path if it does not exist
New-Item -ItemType Directory -Path $ConfigLocation -EA 0 | Out-Null

$LockFilePath =  "$ConfigLocation\Instance.Lock"

$Locked = $null -ne (Get-Item -Path $LockFilePath -EA 0)
if ($Locked) {Exit}


# Lock
New-Item -Path $LockFilePath

# Do stuff 

# Remove lock
Remove-Item -Path $LockFilePath

Alternatively, on Windows, you could also use a scheduled task without a schedule and with the setting "If the task is already running, then the following rule applies: Do not start a new instance". From there, instead of calling the original script, you call a proxy script that just launch the scheduled task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文