Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Windows Forms Locks up PowerShell ISE minutes after script has terminated

I have an interesting issue here. I'm creating a calendar picker for use when we create accounts. It works fine and is still in progress but I have noticed that when I run the script in powershell ISE, after a few minutes it locks up (I am able to edit and save the code for a few minutes prior to that). There is nothing in the event log. I get a dialog box saying that powershell is non responsive. Memory usage seems normal as well. I do not know what is happening.

This occurs no matter how I run Powershell ISE (Run as Administrator, Run as another account, and normal ISE) I am running windows 8.1.

A coworker suggested it may be the apartment model, so I've tried STA and MTA, but the problem occurs either way. It does not happen when the same code is run from the console host.

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

$objForm = New-Object Windows.Forms.Form 

$objForm.Text = "Select a Date" 
$objForm.Size = New-Object Drawing.Size @(490,250)
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True

$objForm.Add_KeyDown({
    if ($_.KeyCode -eq "Enter") 
        {
            $script:dtmDate=$objCalendar.SelectionStart
            $objForm.Close()
        }
    })

$objForm.Add_KeyDown({
    if ($_.KeyCode -eq "Escape") 
        {
            $objForm.Close()
        }
    })

$objCalendar = New-Object System.Windows.Forms.MonthCalendar 
$objCalendar.Text = "Start"
$objCalendar.ShowTodayCircle = $False
$objCalendar.MaxSelectionCount = 1
$objForm.Controls.Add($objCalendar) 

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})  
[void] $objForm.ShowDialog() 

if ($dtmDate)
    {
        Write-Host "Date selected: $dtmDate"
    }

$objForm.Dispose()

In Response to @The Unique Paul Smith

function Find-CalenderDateTest {
[CmdletBinding()]
param(
    [Parameter(
        Mandatory=$false
    )]
    [ValidateSet('long','short','powerpoint')]
    [ValidateNotNullOrEmpty()]
    [string]
    $DateFormat

)

Begin{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

$objForm = New-Object Windows.Forms.Form 

$objForm.Text = "Select a Date" 
$objForm.Size = New-Object Drawing.Size @(243,250) 
$objForm.StartPosition = "CenterScreen"

$objForm.KeyPreview = $True

$dtmDate = $null

$objForm.Add_KeyDown( {
    if ($_.KeyCode -eq "Enter") 
        {
            $dtmDate=$objCalendar.SelectionStart
            $objForm.Close()
        }
    })


$objForm.Add_KeyDown({
    if ($_.KeyCode -eq "Escape") 
        {
            $objForm.Close()
        }
    })

#region   OK Button
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(20,175)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"

# Got rid of the Click event for OK Button, and instead just assigned its DialogResult property to OK.
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK

$objForm.Controls.Add($OKButton)

# Setting the form's AcceptButton property causes it to automatically intercept the Enter keystroke and
# treat it as clicking the OK button (without having to write your own KeyDown events).
$objForm.AcceptButton = $OKButton
#endregion 

#region Cancel Button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(80,175)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"

# Got rid of the Click event for Cancel Button, and instead just assigned its DialogResult property to Cancel.
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel

$objForm.Controls.Add($CancelButton)

# Setting the form's CancelButton property causes it to automatically intercept the Escape keystroke and
# treat it as clicking the OK button (without having to write your own KeyDown events).
$objForm.CancelButton = $CancelButton
#endregion 

$objCalendar = New-Object System.Windows.Forms.MonthCalendar 
$objCalendar.ShowTodayCircle = $False
$objCalendar.MaxSelectionCount = 1
$objForm.Controls.Add($objCalendar) 

$objForm.Topmost = $True

$objForm.Add_Shown({$objForm.Activate()})  

$Results = $objForm.ShowDialog()
}

Process{}

End{
if ($Results -eq "OK")
    {
    $objCalendar.SelectionStart
    }

$objForm.Dispose()

}
}
like image 980
DJ Torres Avatar asked Jun 12 '15 16:06

DJ Torres


3 Answers

The error is MTA/STA

Don't use

$form.showDialog()

Use

[system.windows.forms.application]::run($form)

instead

and it works fine every time

Another way is to put it in another thread:

$code
{
  //form code here
  $form.showDialog()
}
$newThread = [Powershell]::Create()
$newThread.AddScript($code)
$handle = $newThread.BeginInvoke() 

Provide variables from the calling script:

$newThread.Runspace.SessionStateProxy.SetVariable("variablenname",value)

before the BeginInvoke use variablenname without $...

like image 147
Dennis Avatar answered Oct 20 '22 01:10

Dennis


It's a long shot but the problem might be that powershell is not closing the $objForm object correctly, leaving it running in memory while the ISE waits for input after the script has terminated. If you check your taskmanager, is the form still running in the background? You could also try adding 'Remove-Variable objForm' (no $) after the dispose() and see if that helps.

More information: https://technet.microsoft.com/en-us/library/ff730962.aspx

As I say, it's a long shot.

like image 36
user3046742 Avatar answered Oct 20 '22 00:10

user3046742


I was using combobox.items.add:

$configCombo.Items.Add($wks)

and I looked up how to keep the keys from printing to the console - and changed the add to:

[void]$configCombo.Items.Add($wks)

Since then I have added the void - I have been running it in ISE and it has not hung since.

like image 26
Don Fouts Avatar answered Oct 20 '22 01:10

Don Fouts