OK, so now when we have our script with GUI, let’s look at some of the differences between a console script and this one.
First of all, you need to know that you can’t just exit the script with an exit code, because this will freeze the form.
Therefore, if you want to stop with an error, you’d need to change your monitor element and then just exit the respective function. Let me show you what I mean
Let’s try to exit Main with error code 1
Function Main{
$txbStatus.Text="Script Started"
$txbStatus.Background="#FFA5E8B2"
exit 1
}
If we click on “Start” the form will just freeze. Now this is definitely not a desired state. The problem is that we exit the script and don’t close the form
Even more annoying, we need to close it from the task manager

What we should have used is the “return” instruction
Function Main{
$txbStatus.Text="Script Started"
$txbStatus.Background="#FFA5E8B2"
return
}
Another thing to keep in mind is that the script is running on a single thread, meaning the form is frozen, while the script is running. If we want to receive intermediate status from the execution, we need to refresh the elements.
Let’s add a Progress Bar and see how this works

if we add the following code and use the dispatcher to update the progress, the script will jump from 10% completed, to 100% completed, skipping the 50%
In other words, during longer calculations, we won’t be able to see the end result until the end of the script
Function Main{
$txbStatus.Text="Script Started"
$txbStatus.Background="#FFA5E8B2"
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=10},"Render")
$txbStatus.Text="10% Completed"
Start-Sleep 2
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=50},"Render")
$txbStatus.Text="50% Completed"
Start-Sleep 2
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=100},"Render")
$txbStatus.Text="100% Completed"
}
You can either use the Dispatcher to refresh the entire form like this
Function Main{
$txbStatus.Text="Script Started"
$txbStatus.Background="#FFA5E8B2"
$prBar1.Value=10
$txbStatus.Text="10% Completed"
$Form.Dispatcher.Invoke([action]{},"Render")
Start-Sleep 2
$prBar1.Value=50
$txbStatus.Text="50% Completed"
$Form.Dispatcher.Invoke([action]{},"Render")
Start-Sleep 2
$prBar1.Value=100
$txbStatus.Text="100% Completed"
$Form.Dispatcher.Invoke([action]{},"Render")
}

Or refresh individual components, like this
Function Main{
$txbStatus.Text="Script Started"
$txbStatus.Background="#FFA5E8B2"
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=10},"Render")
$txbStatus.Dispatcher.Invoke([action]{$txbStatus.Text="10% Completed"},"Render")
$prBar1.Dispatcher.Invoke([action]{},"Render")
Start-Sleep 2
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=50},"Render")
$txbStatus.Dispatcher.Invoke([action]{$txbStatus.Text="50% Completed"},"Render")
$prBar1.Dispatcher.Invoke([action]{},"Render")
Start-Sleep 2
$prBar1.Dispatcher.Invoke([action]{$prBar1.Value=100},"Render")
$txbStatus.Dispatcher.Invoke([action]{$txbStatus.Text="100% Completed"},"Render")
}

There are many other controls and options, so happy discovering 😉