Итак, исходя из вашего первоначального примера, здесь есть кое-что, работающее по назначению.
На самом деле у меня есть 2 примера для показа.
Моей первой мыслью было сделать это без использования таймера форм, поскольку на основе вашего примера это выглядит довольно бесполезно.
Во втором примере мы применяем аналогичные логики c, но сохранить форму. В обоих случаях произошли значительные изменения, необходимые для того, чтобы это работало.
В обоих случаях
Register-ObjectEvent
использовалось для регистрации события таймера типа System.Timers.Timer
$ProcPid
передается в таймер как [ref]
, поэтому мы можем обновить его значение (хотя вы можете обновить объект через таймер, простая структура, такая как целое число и строка, не будет обновляться, если вы пытаетесь сделать это без специальной ссылки на переменную, используя [ref]
. Это потому, что исходная ссылка переопределяется при назначении нового значения
Пример # 1 - Система. Windows .timer only
Сначала я сделал этот пример, так как при просмотре вашего кода не было никакого реального использования формы, кроме ее объекта таймера. Сначала я подумал, что, возможно, вы не знали System.Timers.Timer
function ShowRunningPids($startedProcesses) {
foreach ($proc in $startedProcesses) {
Write-Host ("`$proc.Id: {0}" -f $proc.Id)
}
}
function CheckPids($procPid, $startedProcesses) {
Write-Host "Already started PIDS:"
ShowRunningPids $startedProcesses
$proc = Get-Process -Id $procPid -ErrorAction Ignore
if ($proc.Handles) {
return $procPid
}
$DeadProc = $startedProcesses.where( { $_.id -eq $procPid }, 'first') | Select -first 1
[void]$startedProcesses.Remove($DeadProc)
Write-Host ("Process with PID: {0} not running - starting new process" -f $procPid)
$processStatus = Start-Process -passthru -FilePath notepad
Write-Host ("Process with PID: {0} started" -f $processStatus.Id)
# PROBLEM: PID of closed notepad are not deleted from $startedProcesses
$startedProcesses.add($processStatus)
Write-Host ("Removed PID {0} and added PID {1}" -f $procPid, $processStatus.Id)
return $processStatus.Id
}
# Array list is deprecated.
$startedProcesses = [System.Collections.Generic.List[PSObject]]::new()
$ProcPid = 0
$Timer = [System.Timers.Timer]::new()
$Timer.Interval = 1000
$Timer.Elapsed
$Timer.AutoReset = $true
$Timer.Start()
$proc = (Start-Process 'notepad.exe' -PassThru)
$startedProcesses.Add($proc)
$procPid = $proc.Id
Unregister-Event -SourceIdentifier 'ProcessTimerEvent' -errorAction SilentlyContinue
Register-ObjectEvent $Timer elapsed -SourceIdentifier 'ProcessTimerEvent' -Action {
try {
$Data = $event.MessageData
$Data.ProcessID.value = CheckPids -procPid $Data.ProcessID.value -startedProcesses $Data.startedProcesses
}
catch {
Write-Warning $_
}
} -MessageData @{
startedProcesses = $startedProcesses
ProcessID = [ref]$procPid
}
while ($true) {
start-sleep -Seconds 1
}
Unregister-Event -SourceIdentifier 'ProcessTimerEvent'
Затем я снова подумал о ваших вопросах и подумал, что, возможно, эта форма в своей первоначальной форме содержала больше материала, чем просто пустой интерфейс, и вы фактически использовали Это.
Итак, я придумал второе решение, которое сохранило первоначальную форму на месте.
Эта новая версия использует 2 разных таймера.
- Исходный таймер из моего первого примера, который выполняется как задание на неопределенное время в отдельном потоке.
- Таймер формы, который делает
get-job -name 'TimerThing' | Receive-Job
данные из нашего другого Таймер возвращается в основной поток, и вы действительно видите все те записи-хосты, которые вы добавили в свои функции.
Когда вы существуете форму, таймер формы останавливается, и также останавливается задание, содержащее наблюдение за процессом.
Пример # 2 - запуск наблюдения процесса в отдельных потоках и используя вашу оригинальную форму
$InitScript = {
function ShowRunningPids($startedProcesses) {
foreach ($proc in $startedProcesses) {
Write-Host ("`$proc.Id: {0}" -f $proc.Id)
}
}
function CheckPids($procPid, $startedProcesses) {
Write-Host "Already started PIDS:"
ShowRunningPids $startedProcesses
$proc = Get-Process -Id $procPid -ErrorAction Ignore
if ($proc.Handles) {
return $procPid
}
$DeadProc = $startedProcesses.where( { $_.id -eq $procPid }, 'first') | Select -first 1
[void]$startedProcesses.Remove($DeadProc)
Write-Host ("Process with PID: {0} not running - starting new process" -f $procPid)
$processStatus = Start-Process -passthru -FilePath notepad
Write-Host ("Process with PID: {0} started" -f $processStatus.Id)
# PROBLEM: PID of closed notepad are not deleted from $startedProcesses
$startedProcesses.add($processStatus)
Write-Host ("Removed PID {0} and added PID {1}" -f $procPid, $processStatus.Id)
return $processStatus.Id
}
}
Start-Job -InitializationScript $InitScript -Name 'TimerThing' -ScriptBlock {
# Array list is deprecated.
$startedProcesses = [System.Collections.Generic.List[PSObject]]::new()
$ProcPid = 0
$Timer = [System.Timers.Timer]::new()
$Timer.Interval = 1000
$Timer.Elapsed
$Timer.AutoReset = $true
$Timer.Start()
$proc = (Start-Process 'notepad.exe' -PassThru)
$startedProcesses.Add($proc)
$procPid = $proc.Id
Unregister-Event -SourceIdentifier 'ProcessTimerEvent' -errorAction SilentlyContinue
Register-ObjectEvent $Timer elapsed -SourceIdentifier 'ProcessTimerEvent' -Action {
try {
$Data = $event.MessageData
$Data.ProcessID.value = CheckPids -procPid $Data.ProcessID.value -startedProcesses $Data.startedProcesses
}
catch {
Write-Warning $_
}
} -MessageData @{
startedProcesses = $startedProcesses
ProcessID = [ref]$procPid
}
while ($true) {
Start-Sleep -Seconds 1
}
}
# Form
add-type -AssemblyName 'System.Windows.Forms'
# start timer
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000
# PROBLEM: How to update PID to instance of newly created notepad?
$timer.add_tick( { get-job -name 'TimerThing' | Receive-Job })
$timer.Start()
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Auto restart of process"
$objForm.Size = New-Object System.Drawing.Size(330, 380)
$objForm.StartPosition = "CenterScreen"
$objForm.Add_Shown( { $objForm.Activate() })
$objForm.Add_Closing( { $timer.Stop(); Stop-Job -Name 'TimerThing' })
[void] $objForm.ShowDialog()