Sli*_*nky 11 windows powershell
我正在PowerShell v1中编写一个批处理脚本,它将按计划运行,每分钟说一次.不可避免地,有一段时间工作需要超过1分钟才能完成,现在我们有两个脚本运行实例,然后可能有3个等等......
我希望通过让脚本本身检查是否有自己的实例已经运行来避免这种情况,如果是,则脚本退出.
我在Linux上用其他语言完成了这个,但从未在Windows上使用PowerShell完成此操作.
例如在PHP中我可以做类似的事情:
exec("ps auxwww|grep mybatchscript.php|grep -v grep", $output);
if($output){exit;}
Run Code Online (Sandbox Code Playgroud)
在PowerShell v1中有这样的东西吗?我还没有遇到过这样的事情.
在这些常见模式中,哪一个最常用于经常运行的PowerShell脚本?
如果使用powershell.exe -File开关启动脚本,则可以检测进程命令行属性中存在脚本名称的所有powershell实例:
Get-WmiObject Win32_Process -Filter "Name='powershell.exe' AND CommandLine LIKE '%script.ps1%'"
Run Code Online (Sandbox Code Playgroud)
这是我的解决方案。它使用命令行和进程ID,因此无需创建和跟踪任何内容。并不关心您如何启动脚本的任何一个实例。
以下应按原样运行:
Function Test-IfAlreadyRunning {
<#
.SYNOPSIS
Kills CURRENT instance if this script already running.
.DESCRIPTION
Kills CURRENT instance if this script already running.
Call this function VERY early in your script.
If it sees itself already running, it exits.
Uses WMI because any other methods because we need the commandline
.PARAMETER ScriptName
Name of this script
Use the following line *OUTSIDE* of this function to get it automatically
$ScriptName = $MyInvocation.MyCommand.Name
.EXAMPLE
$ScriptName = $MyInvocation.MyCommand.Name
Test-IfAlreadyRunning -ScriptName $ScriptName
.NOTES
$PID is a Built-in Variable for the current script''s Process ID number
.LINK
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[ValidateNotNullorEmpty()]
[String]$ScriptName
)
#Get array of all powershell scripts currently running
$PsScriptsRunning = get-wmiobject win32_process | where{$_.processname -eq 'powershell.exe'} | select-object commandline,ProcessId
#Get name of current script
#$ScriptName = $MyInvocation.MyCommand.Name #NO! This gets name of *THIS FUNCTION*
#enumerate each element of array and compare
ForEach ($PsCmdLine in $PsScriptsRunning){
[Int32]$OtherPID = $PsCmdLine.ProcessId
[String]$OtherCmdLine = $PsCmdLine.commandline
#Are other instances of this script already running?
If (($OtherCmdLine -match $ScriptName) -And ($OtherPID -ne $PID) ){
Write-host "PID [$OtherPID] is already running this script [$ScriptName]"
Write-host "Exiting this instance. (PID=[$PID])..."
Start-Sleep -Second 7
Exit
}
}
} #Function Test-IfAlreadyRunning
#Main
#Get name of current script
$ScriptName = $MyInvocation.MyCommand.Name
Test-IfAlreadyRunning -ScriptName $ScriptName
write-host "(PID=[$PID]) This is the 1st and only instance allowed to run" #this only shows in one instance
read-host 'Press ENTER to continue...' # aka Pause
#Put the rest of your script here
Run Code Online (Sandbox Code Playgroud)
加载一个 Powershell 实例并非易事,每分钟加载一次会给系统带来大量开销。我只是安排一个实例,并编写脚本以在进程-睡眠-进程循环中运行。通常我会使用秒表计时器,但我认为他们在 V2 之前不会添加这些计时器。
$interval = 1
while ($true)
{
$now = get-date
$next = (get-date).AddMinutes($interval)
do-stuff
if ((get-date) -lt $next)
{
start-sleep -Seconds (($next - (get-date)).Seconds)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9138 次 |
| 最近记录: |