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()
}
}
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 $...
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With