Powershell -notin array won't trigger if statement

Viewed 174

I've recently begun to create a powershell script including a GUI.
To prevent the GUI from freezing I've created a background job in which my function "xyz" runs...
I want to capture a specific window title. If this window closes the if should be fired.

Now my problem with this script is the following:
If I run the script without putting it in the background job it does notice the if statement and returns the value I want to have.

If I run the script and put the task into the background job this job won't stop and won't recognize the if statement.
Does someone have a solution for this problem?

Function xyz {
    $global:TitleArray = @("Termius - Hosts","Some Window Title","...")
    $global:WindowClosed = $false
    $global:TitleArray | Out-Host
    $global:Job = start-job -Name FindGame {
        Do {
            (Get-Process | Where-Object {$_.MainWindowTitle -ne ""} | Select-Object MainWindowTitle) | % {
                if($_.MainWindowTitle -in $global:TitleArray){
                    $global:WindowFound = $true
                    $global:FoundWindowName = $_.MainWindowTitle
                    do {
                        $WindowArray = @()
                        (Get-Process | Where-Object {$_.MainWindowTitle -ne ""} | Select-Object MainWindowTitle) | % {
                           $WindowArray += $_.MainWindowTitle
                        }
                        if($global:FoundWindowName -notin $WindowArray){
                            $global:WindowClosed = $true
                        }
                         Sleep 1
                    } while ($global:WindowClosed -ne $true)
                }

                if($global:WindowClosed){
                    $Global:FoundWindowName | Out-Host
                    exit
                }
                Sleep 1
            }         
        } while ($true)
    }
}

xyz
1 Answers

PowerShell jobs (of type PSJob) run in a separate process, so they have no access whatsoever to your calling program's environment, not even variables in the Global scope.

To get information into the job, you should define a param() block in the job's script block, and then use the -ArgumentList parameter of Start-Job to send in values. Do note that this will be a one time passing in of values.

To return data from the job, you just send it out through the pipeline as usual, and to access the data you'll need to use Get-Job to determine whether the job "has additional data", and if it does, you use Receive-Job to retrieve that data.

Unfortunately all this means that you still need your main thread to be managing the background job, defeating the purpose.

You might look into Register-ObjectEvent instead, and pair that with some kind of .Net object that can raise events. It appears that these do run in-process, but more than that, they can fire based on events you might actually be interested in without managing a loop.

So at its simplest, and maybe just to get acquainted you can look at a timer example where a timer object fires the event on an interval:

$timer = new-object timers.timer 

$action = {write-host "Timer Elapse Event: $(get-date -Format ‘HH:mm:ss’)"} 
$timer.Interval = 3000 #3 seconds  

Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier  thetimer -Action $action 

$timer.start()

#to stop run 
$timer.stop() 
#cleanup 
Unregister-Event thetimer

But the examples on the Microsoft page even include monitoring a Process Creation Event from WMI, so that and/or and process exit event(?) might be worth looking into.

Related