Skip to content

Instantly share code, notes, and snippets.

@MVKozlov
Last active June 1, 2023 14:15
Show Gist options
  • Save MVKozlov/c46b2d6d162e0018578a5b1b48154917 to your computer and use it in GitHub Desktop.
Save MVKozlov/c46b2d6d162e0018578a5b1b48154917 to your computer and use it in GitHub Desktop.
Powershell: Show GUI Messagebox and wait for user input or timeout
<#
.SYNOPSIS
Show GUI Messagebox
.DESCRIPTION
Show GUI Messagebox and wait for user input or timeout
.PARAMETER Message
Message to show
.PARAMETER Title
Messagebox title
.PARAMETER Buttons
Messagebox buttons
.PARAMETER Icon
Messagebox Icon
.PARAMETER Timeout
Messagebox show timeout in seconds. After that it will autoclose
.EXAMPLE
PS C:\> Show-MessageBox -Message 'My Message' -Title 'MB title' -Buttons = 'YesNo' -Icon Information
SHow Messagebox with message, title, Yes/No buttons and Information icon
.EXAMPLE
PS C:\> Show-MessageBox -Message 'Everything Lost !' -Title 'This is the end' -Icon Exclamation -Timeout 10
SHow Messagebox with message, title, Exclamation icon with 10 sec timeout
.OUTPUTS
System.Windows.Forms.DialogResult. If timed out, return No
.LINK
https://stackoverflow.com/a/26418199
https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.tasks.task.delay?view=netframework-4.5
.NOTES
Author: Max Kozlov
Idea from stack overflow
Required Net 4.5+
TODO: set focus on messagebox window
#>
function Show-MessageBox {
[CmdletBinding()]
param(
[Parameter(Mandatory, Position=0)]
[string]$Message,
[Parameter(Position=1)]
[string]$Title = '',
[ValidateSet('OK','OKCancel','AbortRetryIgnore','YesNoCancel','YesNo','RetryCancel')]
[Parameter(Position=2)]
[string]$Buttons = 'OK',
[ValidateSet('None','Hand','Error','Stop','Question','Exclamation','Warning','Asterisk','Information')]
[Parameter(Position=3)]
[string]$Icon = 'None',
[Parameter(Position=4)]
[int]$Timeout = 0
)
Add-Type -Assembly System.Windows.Forms
$w = $null
if ($Timeout) {
$cancel = New-Object System.Threading.CancellationTokenSource
$w = New-Object System.Windows.Forms.Form
$w.Size = New-Object System.Drawing.Size (0,0)
[System.Action[System.Threading.Tasks.Task]]$action = {
param($t)
Write-Debug "Want to Close $($task.Status)"
$w.Close()
}
$task = [System.Threading.Tasks.Task]::Delay(
[timespan]::FromSeconds($Timeout), $cancel.Token
).ContinueWith($action,
[System.Threading.Tasks.TaskScheduler]::FromCurrentSynchronizationContext()
)
Write-Debug "Before $($task.Status)"
#$w.TopMost = $true
#$w.Modal = $true
$w.Show()
$w.Left = -10000
$w.Top = -10000
$w.Focus()
}
[System.Windows.Forms.MessageBox]::Show($w, $Message, $Title, $Buttons, $Icon) #Topmost
if ($Timeout) {
Write-Debug "After $($task.Status)"
if ($task.Status -ne 'RanToCompletion') {
Write-Debug "Do Cancel"
$cancel.Cancel()
$task.Wait()
$cancel.Dispose()
}
$task.Dispose()
}
}
@bigbadmoshe
Copy link

bigbadmoshe commented Aug 16, 2021

Hi this is a very nice show-messagebox.

i was able to get it topmost by adding "$w.TopMost = $true"

@MVKozlov
Copy link
Author

Thanks, This is good addition but it still not solve focus problem :(

@maxsieber
Copy link

I had to add:
$w.TopMost = true;
$w.Focus();
$w.TopMost = true;
from https://stackoverflow.com/a/47850889
I don't know if less would have worked

@MVKozlov
Copy link
Author

MVKozlov commented Jun 1, 2023

@maxsieber,
the focusing problem is that $w is the parent window, and the messagebox is the child window that should be focused
but main widow ($w) is hidden.

@MVKozlov
Copy link
Author

MVKozlov commented Jun 1, 2023

@maxsieber !
Thanx, you give me the clue :))
show() is the key

The focus problem seems solved now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment