Powershell closing popup box

Viewed 5960

I'm trying to create a popup window that stays open until the script finishes.

I have the following code to create a popup box

$wshell = New-Object -ComObject Wscript.Shell

$wshell.Popup("Operation Completed",0,"Done",0x1)

$wshell.quit

I figured $wshell.quit would close the window, but it doesn't. Is there a way to close this dialog box from within the script without user interaction?

3 Answers

You can, from within power shell, open internet explorer, displaying a local html page (aka a splash screen) then, when done, close it

$IE=new-object -com internetexplorer.application
$IE.navigate2("www.microsoft.com")
$IE.visible=$true
 ...
$IE.Quit()

Some reading Here https://social.technet.microsoft.com/Forums/ie/en-US/e54555bd-00bb-4ef9-9cb0-177644ba19e2/how-to-open-url-through-powershell?forum=winserverpowershell

Some more reading Here How to properly close Internet Explorer when launched from PowerShell?

See https://msdn.microsoft.com/en-us/library/x83z1d9f(v=vs.84).aspx for the parameters. The one you need is [nSecondsToWait], if the value is 0 the script waits indeffinetly, use a value for the seconds and it wil close by itself.

intButton = wShell.Popup(strText,[nSecondsToWait],[strTitle],[nType])

Another way would be sending a keystoke to the dialog with wshShell.SendKeys "%N"

Using the first method here an example of what you could do. I'm using vbscript here, no experience with powershell but it's almost the same solution.

Set wShell = WScript.CreateObject("WScript.Shell")
count  = 1
result = -1
Do while result = -1
  result = wShell.Popup("Operation Completed", 1, "Done", 0)
  count = count + 1
  Wscript.echo count
  if count = 10 then Exit Do ' or whatever condition
Loop

The use of $wsheel.quit won't work here because in PowerShell when you execute $wshell.Popup(..) the session will wait untill the form is closed.
You won't be able to run any other command untill the window will be closed.

What you can do is to create the popup window in different session and by that you can run you code and when your code finish, search for the job and kill it.

Solution #1:

function killJobAndItChilds($jobPid){
    $childs = Get-WmiObject win32_process | where {$_.ParentProcessId -eq $jobPid}
    foreach($child in $childs){
        kill $child.ProcessId
    }
}

function Kill-PopUp($parentPid){
    killJobAndItChilds $parentPid
    Get-Job | Stop-Job
    Get-Job | Remove-Job
}

function Execute-PopUp(){
    $popupTitle = "Done"
    $popupScriptBlock = {
       param([string]$title)
       $wshell = New-Object -ComObject Wscript.Shell

       $wshell.Popup("Operation Completed",0,$title,0x1)
    }

    $job = Start-Job -ScriptBlock $popupScriptBlock -ArgumentList $popupTitle

    # Waiting till the popup will be up.
    # Can cause bugs if you have other window with the same title, so beaware for the title to be unique
    Do{
        $windowsTitle = Get-Process | where {$_.mainWindowTitle -eq $popupTitle }
    }while($windowsTitle -eq $null)
}

Execute-PopUp

#[YOUR SCRIPT STARTS HERE]
Write-Host "Your code"
Start-Sleep 3
#[YOUR SCRIPT ENDs HERE]


Kill-PopUp $pid

It creates your pop-up and only when the window is up (Verifying by the title. Notice that it can cause colissions if there is another process with the same window's title) your code will start run.
When your code will finish it will kill the job.
Notice that I didn't use Stop-Job to stop the job.
I guess it because when the job created the pop-up it can't receive any commands untill the popup will be close.
To overcome it I kill the job's process.

Solution #2 (using events):

function Kill-PopUp(){
    kill (Get-Event -SourceIdentifier ChildPID).Messagedata
    Get-Job | Stop-Job
    Get-Job | Remove-Job
}

function Execute-PopUp(){
    $popupTitle = "Done"
    $popupScriptBlock = {
       param([string]$title)
       Register-EngineEvent -SourceIdentifier ChildPID -Forward
       New-Event -SourceIdentifier ChildPID -MessageData $pid > $null
       $wshell = New-Object -ComObject Wscript.Shell

       $wshell.Popup("Operation Completed",0,$title,0x1)
    }

    $job = Start-Job -ScriptBlock $popupScriptBlock -ArgumentList $popupTitle

    # Waiting till the popup will be up.
    # Can cause bugs if you have other window with the same title, so beaware for the title to be unique
    Do{
        $windowsTitle = Get-Process | where {$_.mainWindowTitle -eq $popupTitle }
    }while($windowsTitle -eq $null)
}

Execute-PopUp

#[YOUR SCRIPT STARTS HERE]
Write-Host "Your code"
Start-Sleep 3
#[YOUR SCRIPT ENDs HERE]


Kill-PopUp
Related