Multi-Runspace PowerShell/XAML script crashing on button click - powershell

I have a script which uses asynchronous runspaces in order to display a XAML/WPF GUI while processing stuff in the background. When I click the button, it crashes, but only when in a specific state. Let me elaborate.
The script begins with pinging a long list of servers to ensure that they're up. After that, it runs through a few SQL queries, WMI calls, other logic, processes all of the data, and then updates my DataGrid in the other window one row at a time with the information.
The button simply brings up a WinForm confirmation:
#$Global:uihash is my synchronized hashtable.
$Global:uihash.Button.add_click({if([System.Windows.Forms.MessageBox]::Show `
("Yes or No?", "Question",[System.Windows.Forms.MessageBoxButtons]::OKCancel) -eq "OK")
{Do stuff back in main PS Window}
If I press the button while the script is pinging all of the devices, it works perfectly. If I click the button at any other time during the script, the PS Windows immediately flip to not responding and I have to kill them.
From the application event log:
The program PowerShell_ISE.exe version 10.0.10586.117 stopped
interacting with Windows and was closed.
I'm like 95% sure it's because pinging devices is the only part of the script which has absolutely zero interaction with the other window, I just don't know how to fix this, or even work around it.
I'm wondering if anybody has seen or experienced this or something similar before, and how you got around it. Any help would be greatly appreciated. Thanks!

I was never able to completely figure this out, but I did find a good workaround for me. I put the main chunk of my script in a Do-Until loop, and made the button click change a global variable I created. That broke it out of the loop, closed the window, and let all the finishing tasks run without crashing.
#$Global:uihash is my synchronized hashtable.
#Create synchronized hash table variable
$Global:uiHash.Add(“End”,$false)
#Create Click Event
$Global:uihash.Button.add_click({if([System.Windows.Forms.MessageBox]::Show
("Yes or No?", "Question",[System.Windows.Forms.MessageBoxButtons]::OKCancel) -eq "OK")
{$Global:uiHash.End = $true}
Do {A whole bunch of stuff}
Until ($global:uiHash.end -eq $true)
#Close the window
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.Window.close() },"Normal")
#Then process the rest of the script

Related

How can I activate and deactivate the spawner in time?

I want the "Spawner Script" to stop and the "Reward Gold Spawner Script" to be active in the second picture, as shown in the 1st picture, when I click the Star Gameobject, and after a certain second I want the "Spawner Script" to be active again, but I could not do it in any way. How can I do it?
I tried a lot of things but couldn't, for example spawner scripts don't work and when I call after certain seconds it didn't call.
!Not: I solved the problem I forgot to put a loop I don't know how I overlooked it.
Have you tried disabling and reenabling the object with the script? object.SetActive(false).
If I understand your question right.

Disabled button still triggers Click event

I'm tring to prevent users to rapidly spam-click a button, which would freeze the app possibly for minutes while the code is being executed many times.
$searchBtn_clicked = {
$searchBtn.Enabled = $false
... some code that fills a listview from search result
$searchBtn.Enabled = $true
}
My problem is: the code above will be executed as many times as the button is clicked, no matter what. Disabling the button after a click changes nothing. I also tried adding a start-sleep 2 before Enabling it back.
First click triggers the code, subsequent clicks are onto the disabled button... and will still trigger the Click event, as soon as the button becomes Enabled again.
What is happening here? Some kind of asynchronous magic? All click events are somehow queued and only being processed after the button is Enabled again?
I'm new to PowerShell and very confused.
Add [System.Windows.Forms.Application]::DoEvents():
$searchBtn.Add_Click({
$this.Enabled = $false
# ... some code that fills a listview from search result
# flush out all pending events
[System.Windows.Forms.Application]::DoEvents()
$this.Enabled = $true
})
Hope that helps
Windows messages are queued and processed in order. If your code is busy, these messages (spam-clicks) are stored in that queue and processed when possible. DoEvents() tells the window to pocess all messages currently in the message queue, effectively flushing it.

Can i change button names for Out-GridView?

I have a script which filters an excel sheet (schedule) and displays the result through Out-Gridview. When the user clicks "Cancel" it opens the excel sheet after closing the Out-Gridview. When the user clicks "Ok" it only closes the Out-Gridview. But these actions are not visible for the user. So can i rename the "Ok" and "Cancel" button of Out-Gridview to lets say "Close Schedule" and "Open Excelsheet"?
And also, is it possible to run the rest of the script without waiting for the response, but keep the buttons working?
I know that if i don't use an output mode the rest of the script runs without waiting, but with outputmode (which gives me buttons) it waits for the response.
I use this code to filter a schedule and it would be nice if i can use the rest of the program without shutting down the rest of the program, maybe by starting another instance of powershell or something?
$Schedule = $ResultsTable | Out-Gridview -OutputMode Single -Title "Schedule"
if ($Schedule -eq $Null) {
Start-Process "$Fileserver\Logistics_share\Planning_Alg\TS Delivery schedule rev2.0.xlsx"
}
If it can be done with only a visual overlay, it is ok by me (Buttons)

Dynamically Change HTA Window Properties

In my HTA, I hold it it open if an error occurred, and close it if everything was successful. At the start, I have the sysmenu property set to no because I do not want the user to close the HTA until it's finished. At the end, I want them to be able to click on the close button. Here's what I typed up to try to achieve this, but it doesn't seem to work? I suspect there is something I need to do to get the HTA to refresh it's windows properties?
Please note that any solution that completely reloads the window and/or makes the script execute again is not acceptable
If Not bHoldOpen Then
Call window.close
Else
Dim tagHTA
Set tagHTA = document.getElementsByTagName("hta:application").item(0)
Call tagHTA.setAttribute("sysmenu","yes")
End If
You cannot change it at runtime, its only available in the HTA: block as its value is used to determine how the physical window is to be initially created.
I thought you could produce a warning using the onBeforeUnload event & call cancelBubble to abort the close, but I tried it in IE8 and it still seems bugged; http://support.microsoft.com/kb/946214.
It would probably be simpler and easier for the user to comprehend if you were yo just unhide a "Close" button when the process completed.

GTK: Destroy window and run an external script on button clicked

That's pretty much the question's title. I must be missing some signals interpretation here...
On PyGTK, I'm doing:
class Foo:
def __init__(self):
self.gladefile = gladefile
self.wTree = gtk.glade.XML(self.gladefile, 'some_window')
self.window = self.wTree.get_widget('some_window')
events = { 'on_code_submit_clicked' : self.submit }
self.wTree.signal_autoconnect(events)
def submit(self):
self.window.destroy()
os.system('external_script')
code = Foo()
What's happening, is that when the button is clicked, it stay pressed, then the script runs, and after the external program is closed, the window "blinks", getting destroyed and recreated again.
I also tried the "pressed" and "released" signals.
The behavior I need:
Click on the button
Destroy the current window
Run external script (that will open another program's window)
Recreate the Foo() window after closing the external app.
What I can imagine is that the event is being run during the clicked event, not after. That's why the window remain opened. The PyGTK docs don't say anything about something like gtk_signal_connect_after on the glade page, that leaves me totally lost about it.
Why not hide the window and show it after the external script?
self.window.hide()
os.system('external_script')
self.window.show()
It looks like you'll have to call the external script from a thread.
I haven't worked with threads with python, but it looks like the threading module would do the job (at least that's what I would try). Glib also has thread support, but I can't find the pygtk docs for it.
When the external script has finished, don't recreate Foo from the thread but schedule a callback function to do so using gobject.idle_add. This is because all GUI work should be done on the gtk event thread, otherwise your program may crash.
Posting my solution... it's easy as.
self.window.hide()
glib.idle_add(subprocess.call, ['external_script', 'param'])
glib.idle_add(self.window.show)