Build and respond to events on multiple check boxes - winforms

I am attempting to make a form with multiple check boxes, based on the array passed to the form creation function. I can calculate the correct location based on the count of what checkbox I am at is, but I am having trouble (I think) dealing with events. I have this for now (partial code, obviously)
$checkboxCount = 1
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Checked = $true
$Form.Controls.Add($checkbox)
$checkbox.Add_CheckStateChanged({
$results.$year = $checkbox.Checked
})
$checkboxCount ++
}
and the check boxes are created correctly, but when I return $results from the function they are all True. I am basing the code off of this, which works but with a static number of check boxes.
function checkbox_test{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$results = #{
one = $true
two = $true
}
$optionCount = 2
# Set the size of your form
$Form = New-Object System.Windows.Forms.Form
$Form | Format-List *
$form.FormBorderStyle = 'FixedDialog'
$form.ShowInTaskbar = $false
$Form.width = 300
$Form.height = 150
$Form.Text = ”Px Tools Updater”
# Set the font of the text to be used within the form
$Font = New-Object System.Drawing.Font("Times New Roman",12)
$Form.Font = $Font
# create your checkbox
$checkbox1 = new-object System.Windows.Forms.checkbox
$checkbox1.Location = new-object System.Drawing.Size(10,7)
$checkbox1.Size = new-object System.Drawing.Size(100,20)
$checkbox1.Text = "One"
$checkbox1.Checked = $true
$Form.Controls.Add($checkbox1)
# create your checkbox
$checkbox2 = new-object System.Windows.Forms.checkbox
$checkbox2.Location = new-object System.Drawing.Size(10,27)
$checkbox2.Size = new-object System.Drawing.Size(100,20)
$checkbox2.Text = "Two"
$checkbox2.Checked = $true
$Form.Controls.Add($checkbox2)
# Add an OK button
$OKButton = new-object System.Windows.Forms.Button
$OKButton.Location = new-object System.Drawing.Size(10,70)
$OKButton.Size = new-object System.Drawing.Size(60,30)
$OKButton.Text = "OK"
$OKButton.Add_Click({$Form.Close()})
$form.Controls.Add($OKButton)
#Add a cancel button
$CancelButton = new-object System.Windows.Forms.Button
$CancelButton.Location = new-object System.Drawing.Size(225,100)
$CancelButton.Size = new-object System.Drawing.Size(60,30)
$CancelButton.Text = "Cancel"
$CancelButton.Margin = 0
$CancelButton.Add_Click({$Form.Close()})
$form.Controls.Add($CancelButton)
$checkbox1.Add_CheckStateChanged({
$results.one = $checkbox1.Checked
})
$checkbox2.Add_CheckStateChanged({
$results.two = $checkbox2.Checked
})
# Activate the form
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
$results
}
I am not sure if I am going wrong with the way I am referencing the results hash table, or maybe the entire approach is wrong?
Edit: I had a thought, that $year is meaningless in the event handler, so I added
$checkbox.Name = $year
and revised the event handler to
$results.($checkbox.Name) = $checkbox.Checked
and
$results.($Self.Name) = $checkbox.Checked
But no joy with either. But what is weird is that using $self results in an odd extra key being added to $return. It has no key name, but the value matches the last change made to any checkbox.
EDIT #2: In further testing, I changed the handler to
$results.2019 = $checkbox.Checked
expecting that to mean any change results in that change applied to the 2019 key. not so. So I am thinking it relates to the way hash tables are passed and referenced and likely I am doing this all wrong. Perhaps worrisome is the fact that I can find tons of information on making check boxes react to and change other parts of the form, but so far nothing on just getting results back.
EDIT #3: OK, seems the answer (of sorts) is there is no need for event handlers, because I only really care about end state anyway. So, with some extra cleanup to also handle Cancel I have this, and it works. Still curious how, or if, I could interact directly with $results from an event handler though.
function checkbox_test{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$years = #('2016', '2017', '2018', '2019')
$optionCount = $years.Count
# Set the size of your form
$Form = New-Object System.Windows.Forms.Form
$form.FormBorderStyle = 'FixedDialog'
$form.ShowInTaskbar = $false
$Form.width = 300
$Form.height = ($years.Count * 30 + 50 + 40) #150
$Form.Text = ”Px Tools Updater”
# Set the font of the text to be used within the form
$Font = New-Object System.Drawing.Font("Times New Roman",12)
$Form.Font = $Font
# create Checkboxes
$checkboxCount = 1
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Name = $year
$checkbox.Checked = $true
$Form.Controls.Add($checkbox)
$checkboxCount ++
}
# Add an OK button
$OKButton = new-object System.Windows.Forms.Button
$OKButton.Size = new-object System.Drawing.Size(60,30)
$OKButton.Location = new-object System.Drawing.Size(10,($form.DisplayRectangle.Height - $OKButton.Size.Height - 10))
$OKButton.Text = "OK"
$OKButton.Add_Click({
$Form.DialogResult = [System.Windows.Forms.DialogResult]::OK
$Form.Close()
})
$form.Controls.Add($OKButton)
#Add a cancel button
$CancelButton = new-object System.Windows.Forms.Button
$CancelButton.Size = new-object System.Drawing.Size(60,30)
$CancelButton.Location = new-object System.Drawing.Size(($form.DisplayRectangle.Width - $CancelButton.Size.Width - 10),($form.DisplayRectangle.Height - $CancelButton.Size.Height - 10))
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({
$Form.Close()
})
$form.Controls.Add($CancelButton)
# Activate the form
$Form.Add_Shown({$Form.Activate()})
if ($Form.ShowDialog() -eq 'OK') {
$results = New-Object Collections.Specialized.OrderedDictionary
foreach ($control in $form.Controls) {
if ($years -contains $control.Name) {
$results.Add($control.Name, $control.Checked)
}
}
} else {
$results = $null
}
[void] $Form.Dispose
$results
}
#Call the function
$returned = checkbox_test
Foreach ($key in $returned.keys) {
Write-Host "[$key] $($returned.$key)!"
}

The foreach loop used to assign each checkbox event handler above effectively overwrites the previous one, and therefore you only capture the last one. (2019)
Instead, assign the event hander the way it's traditionally done in Windows Forms:
$results = New-Object Collections.Specialized.OrderedDictionary;
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$Form.Controls.Add($checkbox);
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Name = $year
$checkbox.Checked = $true
$results.Add($year, $checkbox.Checked);
# HERE!
$checkbox.Add_CheckStateChanged({
# $this -eq sender, optionally $_ -eq EventArgs
$year = $this.name;
$results.$year = $this.Checked;
});
$checkboxCount++
}

Related

Struggling with an Until Loop combined with Get-Random and a Mouse Click in a PowerShell Form

I am struggling with an until loop in combination with a random picker and a mouse click in a PowerShell Form.
I am able to run a random picker without the form , where I have weekdays, picked by random and one by one day, is being removed, until the arraylist is empty. Works not bad.
$Weekdays = 'Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'
[System.Collections.ArrayList]$arraylist = $Weekdays
Write-Host $arraylist -ForegroundColor Green
pause
do {
$removetask = Get-Random $arraylist.ToArray()
$arraylist.Remove($removetask)
Write-Host $removetask
Write-Host $arraylist -ForegroundColor Red
pause
} until ($arraylist.Count -eq 0)
In another approach, I tried to do the same, but this time, I want to control the looping itself, that as soon as the first key from the arraylist is taken and shown in a label, I have to click the mouse button, so it continues to take the next random.
Without the do {} until () I got so far:
$TestForm = New-Object System.Windows.Forms.Form
$TestForm.Size = New-Object System.Drawing.Size (1200,800)
$TestForm.Text ='Random Test'
$TestForm.StartPosition = "CenterScreen"
$TestForm.AutoSize = $true
$TestForm.BringToFront()
$TestForm.BackgroundImageLayout = "Stretch"
[System.Collections.ArrayList]$Weekdays = 'Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'
$TestLabel = New-Object System.Windows.Forms.label
$TestLabel.Location = New-Object System.Drawing.Size '500,200'
$TestLabel.Size = New-Object System.Drawing.Size '600,60'
$TestLabel.Font = New-Object System.Drawing.Font ('Times New Roman','20',[System.Drawing.FontStyle]::Bold)
$TestLabel.BackColor = 'Transparent'
$TestLabel.ForeColor = "Blue"
$removetask = Get-Random $Weekdays.ToArray()
$TestLabel.Text = $removetask
$TestForm.Controls.Add($TestLabel)
$TestButton = New-Object System.Windows.Forms.Button
$TestButton.Location = New-Object System.Drawing.Size '500,600'
$TestButton.Size = New-Object System.Drawing.Size '200,75'
$TestButton.Font = New-Object System.Drawing.Font ('Arial','10',[System.Drawing.FontStyle]::Bold)
$TestButton.Text = 'Next Random'
$TestForm.Controls.Add($TestButton)
$TestButton.Add_Click()
$TestForm.ShowDialog()
$TestForm.Dispose()
Now I have a few lines of code left, I am not able to include on such way, so it works on the following way.
The testform opens, and in a label I see chosen by random one of the weekdays. Clicking next will remove the chosen weekday from the arraylist and show the next weekday by random and will continue until the arraylist is empty.
The missing pieces to the puzzle are:
### The loop itself
do {} until ()
### code to find a Random value from $weekdays and write it into $removetask
$removetask = Get-Random $Weekdays.ToArray()
### code to remove the randomly chosen day and remove it from the arraylist
$Weekdays.Remove($removetask)
#### check if array is empty
($weekdays.Count -eq 0)
I was playing around with the codes and tried with Button.Add_Click() and also with ButtonClickEvent {} but either, the loop is not running, the counter is not working correctly or I somehow messed up the code on such way, that it is stuck somewhere, that not even the form is being shown.
The following enhanced adjustment of your script implements some kind of a loop in the form.
Note that no loop keywords (like do, while, until) and even no if keyword are used:
### Load Assemblies for creating form & controls ###
if ( -not ("System.Windows.Forms.Form" -as [type]) ) {
Add-Type -AssemblyName System.Windows.Forms
}
if ( -not ("System.Drawing.Font" -as [type]) ) {
Add-Type -AssemblyName System.Drawing
}
$TestForm = New-Object System.Windows.Forms.Form
$TestForm.Size = New-Object System.Drawing.Size (1200,800)
$TestForm.Text ='Random Test'
$TestForm.StartPosition = "CenterScreen"
$TestForm.AutoSize = $true
$TestForm.BringToFront()
$TestForm.BackgroundImageLayout = "Stretch"
$TestLabel = New-Object System.Windows.Forms.label
$TestLabel.Location = New-Object System.Drawing.Size '500,200'
$TestLabel.Size = New-Object System.Drawing.Size '600,60'
$TestLabel.Font = New-Object System.Drawing.Font ('Times New Roman','20',[System.Drawing.FontStyle]::Bold)
$TestLabel.BackColor = 'Transparent'
$TestLabel.ForeColor = "Blue"
$TestForm.Controls.Add($TestLabel)
$TestLabe2 = New-Object System.Windows.Forms.Label
$TestLabe2.Location = New-Object System.Drawing.Size '200,300'
$TestLabe2.Size = New-Object System.Drawing.Size '900,200'
$TestLabe2.Font = New-Object System.Drawing.Font ([System.Windows.Forms.Label]::DefaultFont.Name,'16',[System.Drawing.FontStyle]::Italic)
$TestLabe2.BackColor = 'Transparent'
$TestLabe2.ForeColor = [System.Drawing.Color]::MidnightBlue
$TestForm.Controls.Add($TestLabe2)
$TestButton = New-Object System.Windows.Forms.Button
$TestButton.Location = New-Object System.Drawing.Size '500,600'
$TestButton.Size = New-Object System.Drawing.Size '200,75'
$TestButton.Font = New-Object System.Drawing.Font ('Arial','10',[System.Drawing.FontStyle]::Bold)
$TestButton.Text = 'Next Random'
$TestForm.Controls.Add($TestButton)
$TestButtoX = New-Object System.Windows.Forms.Button
$TestButtoX.Location = New-Object System.Drawing.Size '200,600'
$TestButtoX.Size = New-Object System.Drawing.Size '200,75'
$TestButtoX.Font = New-Object System.Drawing.Font ('Arial','10',[System.Drawing.FontStyle]::Bold)
$TestButtoX.Text = 'Next Round'
$TestButtoX.Enabled = $false
$TestForm.Controls.Add($TestButtoX)
Function Swap-Buttons {
$TestButton.Enabled = [bool]$script:Weekdays.Count
$TestButtoX.Enabled = -not [bool]$script:Weekdays.Count
}
Function RemoveWeekday {
$script:removetask = Get-Random $script:Weekdays.ToArray()
$script:Weekdays.Remove($script:removetask)
$TestLabe2.Text = ('(remain {0})' -f $script:Weekdays.Count), ($script:Weekdays -join ', ') -join ': '
$TestLabel.Text = $script:removetask
Swap-Buttons
}
Function DefineWeek {
$script:Weekdays = [System.Collections.ArrayList]([System.Enum]::GetNames([System.DayOfWeek]))
<#
# debugging: try another array list (a larger one)
$script:Weekdays = [System.Collections.ArrayList]([System.Drawing.Color] |
Get-Member -MemberType Properties -Static -Force |
Where-Object Name -match ".+blue" |
Select-Object -ExpandProperty Name
)
<##>
}
$TestButton.Add_Click({
RemoveWeekday
})
$TestButtoX.Add_Click({
DefineWeek
$TestButtoX.Enabled = $false
$TestButton.Enabled = $true
RemoveWeekday
})
$script:removetask = ''
DefineWeek
RemoveWeekday
$TestForm.ShowDialog()
$TestForm.Dispose()

Powershell - how do I change a variable from a listbox item to a combobox item?

I'm attempting to clean up my GUI by removing listboxes of items that users can select to a constrained combobox (using DropDownList to lock user-input) in Powershell. Thus far, I haven't been able to get the variable to reflect the combobox item that is chosen.
Ideally, I want to get $Env to equal the text string chosen in the Combobox replacing $listbox
I attempted trying to follow powershell combobox items to variable to no avail as I don't understand how to use the "SelectedIndexChanged" event...I may just not fully understand the syntax on how to use this...a code example would be awesome.
The current code I have:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = "Select an environment"
$form.Size = New-Object System.Drawing.Size(190,250)
$form.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(10,180)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Please select an environment:"
$form.Controls.Add($label)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(150,20)
$listBox.Height = 140
[void] $listBox.Items.AddRange(#("PROD", "QA1", "QA2", "TR"))
$form.Controls.Add($listBox)
$form.Topmost = $True
do
{
$result = $form.ShowDialog()
if ($ListBox.SelectedIndices.Count -lt 1 -and $result -eq [System.Windows.Forms.DialogResult]::OK)
{
Write-Warning 'Nothing was selected, please select a server.'
}
}
until (($result -eq [System.Windows.Forms.DialogResult]::OK -and $listBox.SelectedIndices.Count -ge 1) -or $result -ne [System.Windows.Forms.DialogResult]::OK)
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$Env -eq $listBox.SelectedItem
}
Here is a quickguid for using events in powershell:
Use | Get-Member -MemberType Event on your WinForms-object to get a list of available events > $OKButton | Get-Member -MemberType Event.
Add a scriptblock that shall be executed, once the event triggers. > $OKButton.add_Click({$ScriptGoesHere}). Watch out for the scope of the scriptblock (PS> help about_scopes)
I reworked your script with events instead of a loop and added comments at the important parts. Events are a lot easier to handle, if you have multiple things going on. But the scopes are kind of a drawback.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = "Select an environment"
$form.Size = New-Object System.Drawing.Size(380,250)
$form.StartPosition = "CenterScreen"
$form.Topmost = $True
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(10,180)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
#$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK #Moved to the event
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Please select an environment:"
$form.Controls.Add($label)
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(150,140) # the second number is the height
#$listBox.Height = 140
[void] $listBox.Items.AddRange(#("PROD", "QA1", "QA2", "TR"))
$form.Controls.Add($listBox)
$comboBox = New-Object System.Windows.Forms.ComboBox
$comboBox.Location = New-Object System.Drawing.Point(190,40)
$comboBox.Size = New-Object System.Drawing.Size(150,20)
[void] $comboBox.Items.AddRange(#("PROD", "QA1", "QA2", "TR"))
$form.Controls.Add($comboBox)
#region Events
#register some events that trigger actions
$listBox.add_SelectedIndexChanged({
#The event is actually $listBox.SelectedIndexChanged but we want to ADD an action. add_SelectedIndexChanged is not listed in get-member.
$ListSelected = $listBox.SelectedItem
Write-Host "ListSelected = $ListSelected"
# You will note that $ListSelected is not available outside the event yet. It is in the scope of the scriptblock.
})
$comboBox.add_SelectedIndexChanged({
#To prevent trouble with the scope, define the variables in a higher scope
$script:SelectedItem = $comboBox.SelectedItem
$global:SelectedIndex = $comboBox.SelectedItem
write-host "SelectedItem = $SelectedItem"
})
$script:OKScript = {
# or define the whole ScriptBlock in a higher scope...
if( $comboBox.SelectedIndex -ge 0){
$Env = $comboBox.SelectedItem #Be carefull $env is the beginning of environmental variables like $env:path
$form.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.close()
}else{
Write-Warning 'Nothing was selected, please select a server.'
}
}
# ...and DotSource it to execute it in the same scope:
$OKButton.add_Click({. $OKScript})
#endregion
$result = $form.ShowDialog()
<# This would work but we use events
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$SelectedItem = $comboBox.SelectedItem
$SelectedIndex = $comboBox.SelectedItem
}
#>
write-host "`r`nform is closed`r`nhere are the results:"
"ListSelected = $ListSelected"
"result = $result"
"env = $env"
"SelectedIndex = $SelectedIndex"
"SelectedItem = $SelectedItem"

How to prevent null/whitespace value in Windows Form textbox (using Powershell)?

I made a Windows Form (this is the last portion of it) that allows the user to enter a search term in a textbox. The whole script checks a server for log files, and downloads them to the user's machine. The textbox data contains a string (date, account #, etc.)...and if left blank it is treated as a wildcard, downloading every log file in the folder chosen. I'm not sure if I can disable the "ok" button until data is entered or give a pop-up/message box prompting the user to enter a search term? I left the prior code/variables out of this example, as it has no bearing on the issue. I appreciate any help in advance!
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = "Enter search criteria"
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Enter search term"
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
$form.Topmost = $True
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$Search = $textBox.Text
$Search
}
$UserPath = "C:\GetFiles\getfiles"
& cmd /c $UserPath" "$Search
Here would be one way you could handle it.
$okbutton.enabled = $false # make this a default
if(![string]::IsNullOrEmpty($textbox.text)) #only enable when you have text in the text box
{
$okbutton.enabled = $true
}
You'll have to use an event from the textbox to change the value of the $okbutton to enabled once text has been entered. I believe this is the event you'll need:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.textchanged?view=netframework-4.7.2
Depending on what you are doing you may need some of the other events as well.
I figured it out. Thank you to Thom Schumacher for helping me with the syntax necessary to complete this:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = "Enter search criteria"
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = "CenterScreen"
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Enter loan number or date to search"
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
$form.Topmost = $True
$form.Add_Shown({$textBox.Select()})
do
{
$result = $form.ShowDialog()
if ([string]::IsNullOrEmpty($textbox.text))
{
Write-Warning 'Please enter search term.'
}
}
until(![string]::IsNullOrEmpty($textbox.text))
{
}
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
$Search = $textBox.Text
$Search
}

Powershell - Close form after time period

I have a power-shell form prompting user if they would like to postpone a shutdown time (the time of the shutdown is given by another ps script as an argument which is calculated in the initial script).
I'd like to close the form after 30 minutes of inactivity, how would I go about this?
Powershell Code (Form):
#creating the form object
$form = New-Object System.Windows.Forms.Form
#setting the from title
$form.Text = "System warning"
#setting the form dimesnions and positions
$form.Size = New-Object System.Drawing.Size(300,250)
$form.StartPosition = "CenterScreen"
#claculate time before shut down:
$StartDate=(GET-DATE)
#this ill have to be replaced by a parameter which indicates the shut down date
$EndDate = $EndDate | Get-Date
$timeDifference = NEW-TIMESPAN –Start $StartDate –End $EndDate
$secondsTilShutdown = $timeDifference.TotalSeconds
#time remaining message
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,40)
$label.Text = "This computer is scheduled to shutdown at " + $EndDate
$form.Controls.Add($label)
#second message
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,70)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = "Postpone the shutdown by : "
$form.Controls.Add($label)
#setting up the drop down box (time in minutes)
$TimePeriods = 60, 120, 180, 240
$DropDown = new-object System.Windows.Forms.ComboBox
$DropDown.Location = new-object System.Drawing.Size(10,90)
$DropDown.Size = new-object System.Drawing.Size(130,30)
ForEach ($time in $TimePeriods) {
[void] $DropDown.Items.Add([string]($time/60) + " hours")
}
#1 hour is the default
$DropDown.SelectedItem = $DropDown.Items[0]
$Form.Controls.Add($DropDown)
#creating the postpone button
$OKButton = New-Object System.Windows.Forms.Button
#position of the button on the form
$OKButton.Location = New-Object System.Drawing.Point(25,130)
#size of the button
$OKButton.Size = New-Object System.Drawing.Size(100,50)
#text of the button
$OKButton.Text = "Postpone"
#the value that the from dialog will return if we click on ok
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
#assigns a key down on the enter key to the button
$form.AcceptButton = $OKButton
#adds the button to the form
$form.Controls.Add($OKButton)
#creating the ignore button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(175,130)
$CancelButton.Size = New-Object System.Drawing.Size(100,50)
$CancelButton.Text = "Continue with scheduled shutdown"
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
$form.Topmost = $True
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
###processing form results :
#if the postpone button button was selected
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
#logic
}
elseif($result -eq [System.Windows.Forms.DialogResult]::Cancel)
{
#we do not push back the shut down time
}
use a timer, i give you a example to timer wich close form
Function ClearAndClose()
{
$Timer.Stop();
$Form.Close();
$Form.Dispose();
$Timer.Dispose();
$Script:CountDown=5
}
Function Button_Click()
{
ClearAndClose
}
Function Timer_Tick()
{
$Label.Text = "Your system will reboot in $Script:CountDown seconds"
--$Script:CountDown
if ($Script:CountDown -lt 0)
{
ClearAndClose
}
}
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$Form = New-Object system.Windows.Forms.Form
$Form.Text = "Attention redémarrage!!"
$Form.Size = New-Object System.Drawing.Size(250,100)
$Form.StartPosition = "CenterScreen"
$Form.Topmost = $True
$Label = New-Object System.Windows.Forms.Label
$Label.AutoSize = $true
$Label.Location = New-Object System.Drawing.Size(20,5)
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(55,35)
$Button.Size = New-Object System.Drawing.Size(120,23)
$Button.Text = "STOP"
$Button.DialogResult=[System.Windows.Forms.DialogResult]::OK
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Interval = 1000
$Form.Controls.Add($Label)
$Form.Controls.Add($Button)
$Script:CountDown = 6
$Button.Add_Click({Button_Click})
$Timer.Add_Tick({ Timer_Tick})
$Timer.Start()
$Form.ShowDialog()

How Do I Access CheckBoxes From a Function

I've created a form and dynamically added CheckBoxes and CheckBox names. How can I programmatically check one particular CheckBox from the Get-LicenseDetails function? Missing bracket has been added.
import-module MSOnline
Function Get-LicenseDetails {
Param ($upn)
$licenses = Get-MsolUser -UserPrincipalName $upn
ForEach ($license in $licenses.Licenses) {
If ($license.AccountSkuId -like '*ENTERPRISEPACK') {
$serviceName = $serviceStatus.ServicePlan.ServiceName
$checkBox.Checked = $true
}
}
}
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$System_Drawing_Point = New-Object System.Drawing.Point
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object Windows.Forms.Form
$form.Text = "Office 365 Licensing"
$form.Name = "Form1"
$form.Size = New-Object Drawing.Size #(316, 510)
#SEARCH BUTTON
$searchBtn = New-Object System.Windows.Forms.Button
$System_Drawing_Point.X = 226
$System_Drawing_Point.Y = 38
$searchBtn.Location = $System_Drawing_Point
$searchBtn.add_click({Get-LicenseDetails "user.name#domain.com"})
$searchBtn.Size = New-Object System.Drawing.Size(67, 23)
$searchBtn.Text = "Click Me"
$form.Controls.Add($searchBtn)
#CHECKBOXES
$y = 80
$Services = (Get-MsolAccountSku | Where-Object {$_.SkuPartNumber -eq "ENTERPRISEPACK"}).ServiceStatus.ServicePlan.ServiceName
ForEach ($service in $Services) {
$checkbox = New-Object System.Windows.Forms.CheckBox
$checkbox.Text = $service
$checkbox.Name = "CheckBox_$service"
$checkbox.Size = New-Object System.Drawing.Size(260,17)
$checkbox.Location = New-Object System.Drawing.Size(10,$y)
$y += 25
$form.Controls.Add($checkbox)
}
$drc = $form.ShowDialog()
First of all, you are missing a square Bracket where you load the System.Drawing Assembly.
You could access the CheckBox in the Get-LicenseDetails bei either passing them to the function or by accessing them using $global:. However, I wouldn't pass GUI elements to that function. Instead I would create a model (new object) and pass that to the Get-LicenseDetails method.
OK, I've figured it out. I used these lines in the function:
$checkBoxName = "CheckBox_" + $serviceName
$checkbox = $form.Controls | Where-Object {$_.name -eq $checkBoxName}
$checkbox.Checked = $true

Resources