3

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?

Pickle
  • 1,064
  • 9
  • 33
  • 51
  • I don't think a popup like that is designed to be closed programmatically. One solution would be to create your own form and close that. Basically, a custom made message box? – Jason Snell Sep 22 '17 at 18:47

3 Answers3

0

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?

Fred Kerber
  • 155
  • 3
  • 13
0

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
peter
  • 41,770
  • 5
  • 64
  • 108
  • You don't need to count it because you already set the `nSecondsToWait` to 1 so the pop-up will last for 1 second. Btw, in powershell your code will look like that: `$wshell = New-Object -ComObject Wscript.Shell $count = 1 $result = 0 While($result -eq 0){ $result = $wshell.Popup("Operation Completed",1,"Done",0) # '= 1' not sure what you wanted here $count += 1 Write-Host $count if($count -eq 10){ Exit } }` Anyway, he wants the popup to stays open **until the script finishes**. – E235 Sep 23 '17 at 12:03
  • @E235, iaa you don't get it, this way you can let the dialog wait as long as you want AND close it when you want as the OP requests, and no, if you use a 0 the script wil never finish unless you press the button or end the task – peter Sep 23 '17 at 19:58
  • I ran it as VBS script and I understand what you meant. But when I ran it, it changes the title to number "2" and after you press "OK" it change it to "3" and so on till 10. And also, in VBS you can run `wShell.Popup(..)` and then it will go to the next command, but in powershell when you run `$wshell.Popup(..)` it will stay stuck untill you will close the window form and in this case you will need to use powershel's jobs. – E235 Sep 23 '17 at 20:40
0

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
E235
  • 11,560
  • 24
  • 91
  • 141