1

I am trying to develop a form from PowerShell that controls and monitor the execution of an script (in my case vbs but it could be any other) on an infinite loop.

I am new to PowerShell so I apology about the code structure. English is not my mother tong so I also apology about the mistakes.

I am using PowerShell because I want my form to have an icon and a menu in the Windows notify task bar. By now, the only thing I got is the icon, but I will get also the menu. This is not a problem.

I need my form, after Button Click, to launch a VisualBasic Script in an INFINITE loop every 3 seconds until I press again the button (or other button). But what I got is an infinite loop with no way of stop because once the button is pressed, the form gets freeze because it is inside the do while loop.

Does anyone know how can I solve my problem? the main purpose is to launch the same VBS every 3 seconds until I want it to stop...

As a test, the VisualBasic Script that I am trying to launch with my PowerShell program is a simple MsgBox that I called 'hello.vbs':

MsgBox "hello world"

For doing so, I've created 3 code files. It starts with a VisualBasic Script named 'program.vbs' that calls PowerShell command:

Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & "C:\Users\XXX\Desktop\Program\program.bat" & Chr(34), 0
Set WshShell = Nothing

Secondly it is executed a bat named 'program.bat' that calls PowerShell Script:

powershell -executionpolicy bypass -file "C:\Users\XXX\Desktop\Program\program.ps1"

And finally the MAIN Script named 'program.ps1' creates the form with the control and monitor instructions:

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

$functions = {
    function Test() 
    {
        do
        {
            Invoke-Expression "C:\Users\XXX\Desktop\Programita\hello.vbs"
            Start-Sleep -Seconds 2
        }while ($Label2.Text -ne 0)
    }
}

Function Principal {
    $ProgIcon1 = "C:\Users\XXX\Desktop\Program\icon1.ico"
    $ProgIcon2 = "C:\Users\XXX\Desktop\Program\icon2.ico"
    $Form = New-Object System.Windows.Forms.Form
    $ContextMenuProg = New-Object System.Windows.Forms.ContextMenu
    $Menu = New-Object System.Windows.Forms.MenuItem
    $Icon1 = New-Object System.Drawing.Icon ($ProgIcon1)
    $Icon2 = New-Object System.Drawing.Icon ($ProgIcon2)
    $Label1 = New-Object System.Windows.Forms.Label
    $Label2 = New-Object System.Windows.Forms.Label
    $ComButt1 = New-Object System.Windows.Forms.Button
    $ComButt2 = New-Object System.Windows.Forms.Button
    $objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon

    $Form.Text = "Application stopped"

    $Form.Controls.Add($Label1)
    $Form.Controls.Add($Label2)
    $Form.Controls.Add($ComButt1)
    $Form.Controls.Add($ComButt2)

    $Form.Width = 260
    $Form.Height = 180
    $Form.FormBorderStyle = "FixedSingle"
    $Form.MaximizeBox = $False
    $Form.StartPosition = "CenterScreen"
    $Form.Icon = $Icon2

    $Label1.Text = "My first form with icon inside task bar"
    $Label1.Left = 30
    $Label1.Top = 20
    $Label1.AutoSize = $True

    $ComButt1.Text = "Start application"
    $ComButt1.Left = 12
    $ComButt1.Top = 100
    $ComButt1.Width = 102

    $ComButt2.Text = "Close application"
    $ComButt2.Left = 124
    $ComButt2.Top = 100
    $ComButt2.Width = 102
    $ComButt2.Add_Click({
        [System.Windows.Forms.DialogResult]::Cancel
    })
    $ComButt2.DialogResult = [System.Windows.Forms.DialogResult]::Cancel

    $Label2.Text=0
    $ComButt1.Add_Click(
        {
            if ($Label2.Text -eq 0)
            {
                $Form.Text = "Active application"
                $ComButt1.Text = "Application paused"
                $Label2.Text = 1
                $objNotifyIcon.Icon = $ProgIcon1
                $Form.Icon = $ProgIcon1
                #####
                Start-Job -InitializationScript $functions -ScriptBlock {Test} -Name MyJob
                #####
            }else {
                $Form.Text = "Application stopped"
                $ComButt1.Text = "Launch application"
                $Label2.Text = 0
                $objNotifyIcon.Icon = $ProgIcon2
                $Form.Icon = $ProgIcon2
                Remove-Job -Name MyJob -Force
            }
        }
    )

    $Label2.Left = 30
    $Label2.Top = 50
    $Label2.AutoSize = $True

    $objNotifyIcon.Icon = $ProgIcon2
    $objNotifyIcon.ContextMenu = $ContextMenuProg

    $objNotifyIcon.Visible = $True
    $Form.ShowDialog()
    $objNotifyIcon.Visible = $False
}

Principal
Joracosu
  • 309
  • 1
  • 14
  • 1
    Might you could use [`Start-Job`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-6). So your gui will not freeze while the job is running. You can stop / remove the job with `Stop-Job / Remove-Job` – Patrick Oct 24 '19 at 08:03
  • hummmmm. It looks nice. I did something that actually works but I am not sure if the code is correctly implemented because I had to use the complement '-Force' – Joracosu Oct 24 '19 at 09:29
  • could you add your updated code? – Patrick Oct 24 '19 at 10:41
  • First of all, encapsulate the function 'Test' into a kind of variable of functions: $functions = { function Test (){...}} – Joracosu Oct 24 '19 at 10:55
  • then, on the button to start the program: Start-Job -InitializationScript $functions -ScriptBlock {Test} -Name MyJob – Joracosu Oct 24 '19 at 10:55
  • And finally to stop the program: Remove-Job -Name MyJob -Force – Joracosu Oct 24 '19 at 10:56
  • 1
    Please add your new code to your initial post otherwise we will get a lot of comments here. Before removing a job you should stop it with `Stop-Job`. – Patrick Oct 24 '19 at 10:58
  • It is now added ;). Why is important to stop it before removing? – Joracosu Oct 24 '19 at 11:19
  • See the description of [Remove-Job](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/remove-job?view=powershell-6) -> "(...)If you try to delete a running job, Remove-Job fails. Use the Stop-Job cmdlet to stop a running job.(...)". Do you have any other issues? – Patrick Oct 24 '19 at 11:40
  • AH!... ok. Understand. I have nothing else related to this exactly issue. Thanks – Joracosu Oct 24 '19 at 11:44

2 Answers2

3

Might you could use Start-Job. So your gui will not freeze while the job is running. You can stop / remove the job with Stop-Job / Remove-Job`.

Patrick
  • 2,128
  • 16
  • 24
1

Try this:

Class Surrounding_Class
    Private Stop_Flag As Boolean = False

    Private Sub Btn_Handler(ByVal Sender As Object, ByVal e As EventArgs)
        Stop_Flag = Not Stop_Flag
        DoAction()
    End Sub

    Private Sub DoAction()
        Do
        Loop While Stop_Flag = False
    End Sub
End Class
Joracosu
  • 309
  • 1
  • 14
demoncrate
  • 390
  • 2
  • 14
  • I don't really know how to use/insert this code in mine. The problem I have occurs when inside PowerShell, not in VisualBasic – Joracosu Oct 24 '19 at 09:19
  • My bad. Although the principal might still apply to PowerShell ie. using a variable to control loop. I'm not sure how that specifically works though. – demoncrate Oct 24 '19 at 09:31