Can i change button names for Out-GridView? - powershell

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)

Related

Multiple buttons in a GUI / Add Key down Event Handler

I have already received valuable advice from another post and have already been able to expand "my little GUI project". I have built a GUI with different tabs and buttons based on a code (see screenshot 1)
If I trigger the underlying functions (search in a CSV, or ping from a target) via button, the whole thing works fine.
But I want to execute the actions when the user presses the enter key and here I have a problem. I'm trying to target the buttons with the following code:
*
Search by Site ID:
$form.KeyPreview = $true
$form.Add_Keydown({if ($_.Keycode -eq "Enter")
{$button_Search.PerformClick()}})
Ping command (under the Network tab):
$form.KeyPreview = $true
$form.Add_Keydown({if ($_.Keycode -eq "Enter")
{$button_Search_NW.PerformClick()}})
I thought I can thus uniquely identify the buttons, but still both are addressed. If I search via Enter key for a site ID, I get the site ID, but at the same time I get the message in Powershell that the "SiteID" can't be reached via ping.
I hope I have expressed myself understandably. My question: How can I make it so that I can address the buttons clearly and with the Enter key also only the action is executed, in whose tab I am also currently moving.

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.

Powershell (studio) - AutoComplete dropdown value clicks a button?

I'm building a GUI for a powershell script. It's a form built in Powershell studio.
I have this code which works well:
(Get-Content ".\historique.txt") | ? { $_.trim() -ne "" } | set-content ".\historique.txt"
$postes_historique = Get-Content ".\historique.txt"
$textboxPoste.AutoCompleteCustomSource.AddRange($postes_historique)
It takes what is in the "historique.txt" text file and suggests autocomplete values for the textbox like this:
On that texbox, i have a KEYDOWN event set up so when a user presses ENTER it clicks the button below the textbox:
$textboxPoste_KeyDown = [System.Windows.Forms.KeyEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.KeyEventArgs]
if ($_.KeyCode -eq 'Enter')
{
$buttonConnexion.PerformClick()
}
}
The strange part and my question is :
-If I click a value in the dropdown, it clicks the button. (UNWANTED BEHAVIOR)
-If I REMOVE that KeyDown enter event, it DOESN'T click the button. (Wanted behavior)
That seems very strange to me, it's as if when you click a dropdown value, the code understands it like "YOU PRESSED ENTER". What kind of weird correlation is that? I want to have both, which is being able to press down enter to click the button AND being able to choose an autocomplete value without it triggering a button click...Doesn't seem like too much to ask, no?
Thank you for your time.
Not sure if there is another solution but the work around in this case is :
REMOVE the keydown event that clicks the button when ENTER is pressed
and
REPLACE it by setting the form's AcceptButton to your button. This way when user presses ENTER, that button is triggered and the autocomplete dropdown acts as expected.

Multi-Runspace PowerShell/XAML script crashing on button click

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

How do you hide a Powershell progress message?

I think Write-Progress is a rather beautiful Cmdlet. In fact Sharepoint makes use of it with its Start-SPAdminJob commandlet.
All fine and dandy, the problem is that Start-SPAdminJob does not correctly "dispose" of the Write-Progress dialog. It is never set to 100 percent complete which means it just stays in the Powershell dialog until you exit the script - this in turn hides part of the messages underneath the "progress window".
Is there any way I can force an existing Write-Progress to "exit" or be set to 100% complete? Any way how I could find out the ID of the progress the Start-SPAdminJob cmdlet is using - that way I could manually set the percentage.
You could stop the progress bar appearing in the first place by doing the following beforehand:
$ProgressPreference = "SilentlyContinue";
You could then restore the preference to "Continue" afterwards. Not much help if you actually want the bar of course...
This code forces progress bar to be set to 100% complete and hides it:
Write-Progress "Done" "Done" -completed