I am trying to execute exit after closing the form when clicking "NO" button, but exit causes a system error
Code:
function No {
$Form.close()
exit
}
$NoButton.Add_Click({No})
Without exit, it closes the form but it continues executing the script
System error:
Unhandled exception has occured in a component in your application. If you click Continue, the application will ignore this error and
attempt to continue.
System error.
Full button code:
function No {
$Form.close()
exit
} #end No
# No button
$NoButton = New-Object System.Windows.Forms.Button
$NoButton.Location = New-Object System.Drawing.Size(95,80)
$NoButton.Size = New-Object System.Drawing.Size(80,20)
$NoButton.Text = "No"
$NoButton.Add_Click({No})
$NoButton.Cursor = [System.Windows.Forms.Cursors]::Hand
$Form.Controls.Add($NoButton)
You need to wait till the $Form is actually closed and then better kill it's own process:
$NoButton = New-Object System.Windows.Forms.Button
$NoButton.Location = New-Object System.Drawing.Size(95,80)
$NoButton.Size = New-Object System.Drawing.Size(80,20)
$NoButton.Text = "No"
$NoButton.Add_Click({$Form.close()})
$NoButton.Cursor = [System.Windows.Forms.Cursors]::Hand
$Form.Controls.Add($NoButton)
$Form.Add_Closed({Stop-Process -ID $PID}) # Kill it's own process when the form is closed
Related
I'm trying to develop a script to pop up a messagebox to a user who has the computer connected at a certain hour of the day. If the user confirms he's using the computer by pressing a button of the messagebox then the process stops.
If the user does not press anything for 30 m means he's not at the computer, and we shut down the computer.
I can pop up the messagebox with the message, but how can I check if the button has been pressed or give it a wait 30 m and then if nothing happens, do something else?
You can use the Wscript.Shell COM object's .Popup() method, which supports specifying a timeout after which the dialog (message box) is automatically closed.
In the simplest case:
# Show a message box with an OK button that auto-closes
# after 3 seconds.
# Return value is:
# -1, if the dialog auto-closes
# 1 if the user pressed OK
$response =
(New-Object -ComObject WScript.Shell).Popup(
'I will close in 3 seconds',
3, # timeout in seconds
'Title',
48 # exclamation-point icon; OK button by default
)
if ($response -eq -1) { 'Auto-closed.' } else { 'User pressed OK.' }
A complete example that shows a dialog with OK and Cancel buttons: if the dialog auto-closes or the user presses OK, the script continues; otherwise, processing is aborted:
# How long to display the dialog before it closes automatically.
$timeoutSecs = 30 * 60 # 30 minutes.
# Translate this into the time of day, to show to the user.
$timeoutTimeOfDay = (Get-Date).AddSeconds($timeoutSecs).ToString('T')
# Put up a message box with a timeout and OK / Cancel buttons.
$response =
(New-Object -ComObject WScript.Shell).Popup(
#"
Your computer will shut down at $timeoutTimeOfDay.
Press OK to shut down now, or Cancel to cancel the shutdown.
"#,
$timeoutSecs,
'Pending shutdown',
49 # 48 + 1 == exclamation-point icon + OK / Cancel buttons
)
if ($response -eq 2) { # Cancel pressed.
Write-Warning 'Shutdown aborted by user request.'
exit 2
}
# OK pressed ($response -eq 1) or timed out ($response -eq -1),
# proceed with shutdown.
'Shutting down...'
# Restart-Computer -Force
Note:
The above dialog is statically shows only the time of day at which the shutdown will be initiated.
If you want a realtime countdown of the seconds remaining, more work is needed: see Fitzgery's helpful answer.
Here's that Function that I mentioned in my comment
Function Invoke-RestartTimer {
<#
.SYNOPSIS
Restart Computer After Timer reaches 0
.DESCRIPTION
Pops-Up a GUI Window that Counts Down Seconds until the Computer restarts. It also has buttons to either Restart Now or Cancel the Restart.
If the Restart is Cancelled it will write to the host with Write-Warning that the Restart was cancelled by the Current User.
.PARAMETER Seconds
Identifies the Amount of Seconds the Timer will countdown from
.EXAMPLE
Restart-Computer -Seconds 30
.NOTES
Multi-use Advanced Function for performing a Visual Countdown Restart.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$false)]
[Int32]$Seconds = "15"
)
#Builds Assemblies for Custom Forms used in the function
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
#Identifies logged on user for if restart is cancelled
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
#Adds 1 to the identified time to ensure restart happens at 0 seconds and not -1 seconds.
#$Seconds++
#Builds Form
$RestartForm = New-Object System.Windows.Forms.Form
$RestartForm.StartPosition = "CenterScreen"
$RestartForm.Size = New-Object System.Drawing.Size(300,150)
$RestartForm.Text = "Restart Window"
$RestartForm.AllowTransparency = $true
$RestartForm.BackColor = "LightGray"
$RestartForm.FormBorderStyle = "Fixed3D"
#Builds Text Label
$Script:TimerLabel = New-Object System.Windows.Forms.Label
$TimerLabel.AutoSize = $true
$TimerLabel.Font = "Microsoft Lucida Console,10"
$RestartForm.Controls.Add($TimerLabel)
#Builds Timer
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Interval = 1000 #1 second countdown, in milliseconds
$script:CountDown = $Seconds #seconds to countdown from
$Timer.add_Tick({
$Script:TimerLabel.Text = "
The Computer will restart in $CountDown seconds.
Press the Restart Button to Restart Now."
$Script:CountDown--
If($CountDown -eq "-2"){#Needs to be 2 below wanted value. i.e 0 = -2
$Timer.Stop()
$RestartForm.Close()
Restart-Computer -Force
}
})
$Timer.Start()
#Builds a Restart Button
$RestartButton = New-Object System.Windows.Forms.Button
$RestartButton.Text = "Restart"
$RestartButton.FlatStyle = "Popup"
$RestartButton.Location = New-Object System.Drawing.Size(50,80)
$RestartButton.Size = New-Object System.Drawing.Size(80,23)
$RestartButton.Font = "Microsoft Lucida Console,10"
$RestartButton.Add_Click({
$Timer.Stop()
$RestartForm.Close()
Restart-Computer -Force
})
$RestartForm.Controls.Add($RestartButton)
#Builds a Cancel Button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Text = "Cancel"
$CancelButton.FlatStyle = "Popup"
$CancelButton.Location = New-Object System.Drawing.Size(150,80)
$CancelButton.Size = New-Object System.Drawing.Size(80,23)
$CancelButton.Font = "Microsoft Lucida Console,10"
$CancelButton.Add_Click({
$Timer.Stop()
$RestartForm.Close()
Write-Warning "Restart was aborted by $CurrentUser"
})
$RestartForm.Controls.Add($CancelButton)
[void]$RestartForm.ShowDialog()
}
I have cmd script. I want to use timer for 10 second to give a decision to continue cmd script process or to pause it.
I want to put this script at the first line of my cmd script
powershell.exe -ExecutionPolicy Bypass -File %~dp0\Pause_GUI.ps1
It will pop up 10s countdown, after 10s, it will continue the cmd script process by return errorlevel, but if we click button pause, the cmd script will pause, also by return errorlevel.
Anyone can help please
UPDATED
#------------------------------------------- Add in Forms Controls -------------------------------------------#
Add-Type -AssemblyName System.Windows.Forms
#-------------------------------------------------------------------------------------------------------------#
#---------------------------------------- Begins creation of the form ----------------------------------------#
$MainForm = New-Object System.Windows.Forms.Form
$MainForm.Text = "Message"
$MainForm.Width = 500
$MainForm.Height = 200
$MainForm.StartPosition = "CenterScreen"
$MainForm.BackColor = "#e2e2e2"
#-------------------------------------------------------------------------------------------------------------#
#----------------------------------------------- Button Clicks -----------------------------------------------#
$Auto_Button = ({ $global:result=1
$MainForm.Close() })
$Manual_Button = ({ $global:result=0
$MainForm.Close() })
#-------------------------------------------------------------------------------------------------------------#
#-------------------------------------------------- Buttons --------------------------------------------------#
$Automatic = New-Object System.Windows.Forms.Button
$Automatic.Location = New-Object System.Drawing.Size(110,80)
$Automatic.Size = New-Object System.Drawing.Size(120,30)
$Automatic.Text = "Continue After 10s"
$Automatic.BackColor = "#e47104"
$Automatic.Add_Click($Auto_Button)
$MainForm.Controls.Add($Automatic)
$Manual = New-Object System.Windows.Forms.Button
$Manual.Location = New-Object System.Drawing.Size(270,80)
$Manual.Size = New-Object System.Drawing.Size(100,30)
$Manual.Text = "Pause"
$Manual.BackColor = "#e47104"
$Manual.Add_Click($Manual_Button)
$MainForm.Controls.Add($Manual)
#-------------------------------------------------------------------------------------------------------------#
#--------------------------------------------- Displays the Form ---------------------------------------------#
$result=0
$MainForm.ShowDialog()
exit $result
#-------------------------------------------------------------------------------------------------------------#
How to handle the button "Continue after 10s" as a timer? And the GUI will close automatically after 10s
You need a System.Windows.Forms.Timer-object that counts your time and a .tick-event that will trigger when the time has come. However you need to stop (and dispose) the timer or it will keep on triggering the event even when the window is closed. (In Powershell ISE that could cause windows to close as soon as you load them). To grab the timer from within it's own event you need to adress it in the right scope. I used the global-scope for that.
$Auto_Button = ({
$global:Counter = 0
$global:timer = New-Object -type System.Windows.Forms.Timer
$global:timer.Interval = 1000
$global:timer.add_Tick({
if ($Counter -eq 10){
write-host $global:counter
$global:timer.Stop()
$global:timer.Dispose()
$result=1
$MainForm.Close()
$global:Counter++
}else{
write-host $global:counter
$global:Counter++
}
})
$global:timer.Start()
})
I would like to create a GUI that shows a loading bar while a job is running in the background. For simplicity, I've made the job an infinite loop so it should always be running. I've only included necessary parts of the code:
$Label = new-object system.windows.forms.Label
$Label.Font = 'Ariel,12pt'
$Label.Text = ""
$Label.AutoSize = $True
$Label.Location = new-object system.drawing.size(50,10)
$Form.Controls.Add($Label)
$LoadingAnimation = #(".....","0....",".0...","..0..","...0.","....0",".....")
$AnimationCount = 0
$test = start-job -Name Job -ScriptBlock { for($t=1;$t -gt 0; $t++){} }
while ($test.JobStateInfo.State -eq "Running")
{
$Label.Text = $LoadingAnimation[($AnimationCount)]
$AnimationCount++
if ($AnimationCount -eq $LoadingAnimation.Count){$AnimationCount = 0}
Start-Sleep -Milliseconds 200
}
Upon testing this code in the console, just using Write-Host instead of $Label.Text, it works just fine. What needs to be done differently to get this to work in a windows form created by PowerShell?
In PowerShell, you can create all sorts of status, including multi-level, using Write-Progress. Don't forget to call with -Completed when done (a common mistake I see).
Get-Help Write-Progress
After going through the little details of the script, I found the problem. This is how I activated my form:
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
This caused the script to stop when the form was launched, ShowDialog stops the script to allow interaction. The fix was:
$Form.Add_Shown({$Form.Activate()})
[void] $Form.Show()
Using Form.Show lets the script to continue to run because it doesn't require interaction.
I am trying to run a powershell script remotely that displays a pop-up alert. We are attempting to create a sort of "Emergency Notification System". On the admin machine there is a script to choose which emergency alert to send to everyone, and then it should run/appear on everyone's screen.
I've used the /msg command to achieve this, but the message is so plain that it doesn't catch the user's attention and the text can't be customized (unless it can be, which in that case PLEASE enlighten me).
I am receiving the error below when attempting to do this. I've also attempted to do it via PsExec but receive the same error.
Error:
Exception calling "ShowDialog" with "0" argument(s): "Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application."
Below is the PowerShell script. It's nothing fancy, just wanting something that works for our purpose.
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object system.Windows.Forms.Form
$Form.Text = "Disaster Alert!"
$Form.AutoScroll = $True
$Form.AutoSize = $True
$Form.AutoSizeMode = "GrowAndShrink"
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen"
$Form.Font = New-Object System.Drawing.Font("Calibri",60,[System.Drawing.FontStyle]::Bold)
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(500,200)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "Close"
$OKButton.Font = New-Object System.Drawing.Font("Calibri",11)
$OKButton.UseVisualStyleBackColor = $True
$OKButton.Add_Click({$Form.Close()})
$Form.Controls.Add($OKButton)
$Label = New-Object System.Windows.Forms.Label
$Label.Text = "Please Exit the Building`nBuilding Fire Alarm Sounding!!"
$Label.ForeColor = "Red"
$Label.TextAlign = "MiddleCenter"
$Label.AutoSize = $True
$Form.Controls.Add($Label)
$Form.ShowDialog()
Is it possible to have a pop-up via PowerShell? If not, does anyone have any recommendations?
Thank you very much in advance.
I'm trying to create a message dialogue in Powershell where the user has no option to action on the message as that is the intention. So the message will have the X button grayed along with the buttons (not showing buttons are even better).
The closest I could reach was disabling the X via below code:
$wshell = New-Object -ComObject Wscript.Shell -ErrorAction Stop
$wshell.Popup("Aborted",0,"ERROR!",48+4)
But cannot figure out disabling button part. Below MS articles were of little help as well:
http://blogs.technet.com/b/heyscriptingguy/archive/2006/07/27/how-can-i-display-a-message-box-that-has-no-buttons-and-that-disappears-after-a-specified-period-of-time.aspx
https://msdn.microsoft.com/en-us/library/x83z1d9f(v=vs.84).aspx
Referred to few other articles over net some even suggesting custom made buttons using HTML, or VB library. But not what I was looking for.
Any help/hint/suggestion would be deeply appreciated.
Regards,
Shakti
Dig into the .NET Windows.Forms namespace, you can make pretty much any kind of window you want with that:
https://msdn.microsoft.com/en-us/library/system.windows.forms.aspx
Here's a quick sample window w/ no buttons that can't be moved/closed by the user, but closes itself after 5 seconds:
Function Generate-Form {
Add-Type -AssemblyName System.Windows.Forms
# Build Form
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Test"
$objForm.Size = New-Object System.Drawing.Size(220,100)
# Add Label
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(80,20)
$objLabel.Size = New-Object System.Drawing.Size(100,20)
$objLabel.Text = "Hi there!"
$objForm.Controls.Add($objLabel)
# Show the form
$objForm.Show()| Out-Null
# wait 5 seconds
Start-Sleep -Seconds 5
# destroy form
$objForm.Close() | Out-Null
}
generate-form
Using the script above as a launching point I'm attempting to make a function that will allow me to popup a please wait message run some more script then close the popup
Function Popup-Message {
param ([switch]$show,[switch]$close)
Add-Type -AssemblyName System.Windows.Forms
# Build Form
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Test"
$objForm.Size = New-Object System.Drawing.Size(220,100)
# Add Label
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(80,20)
$objLabel.Size = New-Object System.Drawing.Size(100,20)
$objLabel.Text = "Hi there!"
$objForm.Controls.Add($objLabel)
If ($show)
{
$objForm.Show() | Out-Null
$global:test = "Show"
}
If ($close)
{
# destroy form
$objForm.Close() | Out-Null
$global:test = "Close"
}
}
I can then get the popup to display by:
Popup-Message -show
At this point I can see the $test variable as Show
But when I try to close the window with:
Popup-Message -close
But the popup window will not close
If I look at $test again it will show as Close
I'm assuming this has something to do with keeping the function in the Global Scope but I can't figure out how to do this with the form