PowerShell show array item one at a time - arrays

I have an array and want to display each item one at a time. Each item should also be shown at different times intervals. I think I should use Start-Sleep -s 5.
Here is my code so far.
function GenerateForm {
$a=
"Downloading Files",
"Setting up VPN Connection",
"Getting computer information",
"Install Complete",
"Cluster Flux Technologies",
"You are Free to close this application"
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms")
[reflection.assembly]::loadwithpartialname("System.Drawing")
#endregion
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$richTextBox1 = New-Object System.Windows.Forms.RichTextBox
$pictureBox1 = New-Object System.Windows.Forms.PictureBox
$btn1 = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$btn1_OnClick= {
$richTextBox1.Text = $a | Out-String
}
#----------------------------------------------
#region Generated Form Code
$form1.BackColor = [System.Drawing.Color]::FromArgb(255,212,208,200)
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 658
$System_Drawing_Size.Width = 1072
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon('C:\Users\502706436\Desktop\tight vnc\cluster.ico')
$form1.Name = "form1"
$form1.Text = "Cluster Flux Technologies: VNC Installer"
$richTextBox1.BackColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
$richTextBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$richTextBox1.Enabled = $False
$richTextBox1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",12,0,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 566
$System_Drawing_Point.Y = 570
$richTextBox1.Location = $System_Drawing_Point
$richTextBox1.Name = "richTextBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 39
$System_Drawing_Size.Width = 348
$richTextBox1.Size = $System_Drawing_Size
$richTextBox1.TabIndex = 2
$richTextBox1.Text = ""
$form1.Controls.Add($richTextBox1)
$pictureBox1.BackgroundImage = [System.Drawing.Image]::FromFile('C:\Users\502706436\Desktop\tight vnc\cluster2 logo.png')
$pictureBox1.BackgroundImageLayout = 2
$pictureBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 41
$System_Drawing_Point.Y = 35
$pictureBox1.Location = $System_Drawing_Point
$pictureBox1.Name = "pictureBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 454
$System_Drawing_Size.Width = 949
$pictureBox1.Size = $System_Drawing_Size
$pictureBox1.TabIndex = 1
$pictureBox1.TabStop = $False
$form1.Controls.Add($pictureBox1)
$btn1.DataBindings.DefaultDataSourceUpdateMode = 0
$btn1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",12,0,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 71
$System_Drawing_Point.Y = 570
$btn1.Location = $System_Drawing_Point
$btn1.Name = "btn1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 39
$System_Drawing_Size.Width = 292
$btn1.Size = $System_Drawing_Size
$btn1.TabIndex = 0
$btn1.TabStop = $False
$btn1.Text = "Click to install connection"
$btn1.UseVisualStyleBackColor = $True
$btn1.add_Click($btn1_OnClick)
$form1.Controls.Add($btn1)
#endregion Generated Form Code
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Show the Form
$form1.ShowDialog()
} #End Function
#Call the Function
GenerateForm
If anyone knows or has advice on how to achieve this I would appreciate it.
Thanks

For updating the text ,you can use :
$btn1_OnClick= {
$a | %{ $richTextBox1.Text = $_ | Out-String;Start-Sleep -s 5}
}
but the above simplistic approach will freeze ui while the above block is running.you can try the below runspace approach ,which will ensure that ui is responsive during the update:
$btn1_OnClick= {
$Runspace = [runspacefactory]::CreateRunspace()
$PowerShell = [powershell]::Create()
$PowerShell.runspace = $Runspace
$Runspace.Open()
[void]$PowerShell.AddScript({
param($richTextBox1)
$a=
"Downloading Files",
"Setting up VPN Connection",
"Getting computer information",
"Install Complete",
"Cluster Flux Technologies",
"You are Free to close this application"
$a | %{ $richTextBox1.Text = $_ | Out-String;Start-Sleep -s 5;}
}).addargument($richTextBox1)
$AsyncObject = $PowerShell.BeginInvoke()
}

Related

Refresh Array checkboxes with Powershell

I am trying to create a script that lets the user choose a server from a drop down list. Each server is mapped to a unique array which goes to a foreach loop. The loop cycles through the array and prints a check box on to the form with the value that is in the array. This works with no issue. The problem is when I select the different Server from the drop down list and click "Select Server" button the new values in the Array do not overwrite the existing values. In other words the check box values on the form are not updating with the new array values. What I would like to happen is when you click the "Select Server" button the check box values update to reflect the array values associated with their corresponding server.
Here is an example.
Choose ServerA from drop down
Select 'Select Server'
The following check boxes will list out on to the form in checkbox's:#('Zero','One','Two','Three')
Now if you click ServerB and select "Select Server" I would expect new check boxes to overwrite the existing check boxes with these values: #('0','1','2','3')
Unfortunately the values do not update. I need to have the array values update when the "Select Server" button is selected... Ive looked around at forums and have found some possible solutions but they all seems to fall short.
Thank you in advance.
function GenerateForm
{
$PC=
{
$hostname = $dropdown.SelectedItem
if ($hostname -eq "ServerA")
{ $CheckBoxLabels = #('Zero','One','Two','Three')
}
elseif($hostname -eq "ServerB")
{
$CheckBoxLabels = #('0','1','2','3')
}
$name = New-Object System.Windows.Forms.Label -Property #{
Text = "Start Time"
Location = "900, 220"
ForeColor = "Black"
Height = 22
Width = 200
}
$form1.Controls.Add($hostname)
$CheckBoxCounter = 1
$CheckBoxes = foreach($Label in $CheckBoxLabels)
{
$CheckBox = New-Object System.Windows.Forms.CheckBox
$CheckBox.UseVisualStyleBackColor = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 104
$System_Drawing_Size.Height = 24
$CheckBox.Size = $System_Drawing_Size
$CheckBox.TabIndex = 2
$CheckBox.Text = $Label
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 27
# Make sure to vertically space them dynamically, counter comes in handy
$System_Drawing_Point.Y = 200 + (($CheckBoxCounter - 1) * 31) #Controls location on Y axis
$CheckBox.Location = $System_Drawing_Point
$CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0
# Give it a unique name based on our counter
$CheckBox.Name = "CheckBox$CheckBoxCounter"
$form1.Controls.Add($CheckBox)
# return object ref to array
$Global:CheckBox
# increment our counter
$CheckBoxCounter++
}
}
$form1 = New-Object System.Windows.Forms.Form
$form1.Text = "UCCE Log Collector - Version 2.0"
$form1.Name = "form1"
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 1150
$System_Drawing_Size.Height = 500
$form1.ClientSize = $System_Drawing_Size
$dropdown = New-Object System.Windows.Forms.ListBox
$dropdown.Location = New-Object System.Drawing.Point(10,50)
$dropdown.Size = New-Object System.Drawing.Size(100,20)
$dropdown.Height = 80
[void] $dropdown.Items.Add('ServerA')
[void] $dropdown.Items.Add('ServerB')
$form1.Controls.Add($dropdown)
######### Select Server Button
$SelectPC = New-Object System.Windows.Forms.Button
$SelectPC.TabIndex = 4
$SelectPC.Name = "SelectPC"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 120
$System_Drawing_Size.Height = 30
$SelectPC.Size = $System_Drawing_Size
$SelectPC.UseVisualStyleBackColor = $True
$SelectPC.Text = "Select Server"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 0 # 0
$System_Drawing_Point.Y = 150 #150
$SelectPC.Location = $System_Drawing_Point
$SelectPC.DataBindings.DefaultDataSourceUpdateMode = 0
$SelectPC.add_Click($PC)
$form1.Controls.Add($SelectPC)
$result = $form1.ShowDialog()
$result
}
GenerateForm
Per the request in the comments to accommodate a variable number of properties for each host, first we'll create a Panel to hold our CheckBoxes and add it to our Form...
# Create a Panel to contain the dynamic collection of CheckBoxes
$HostPropertiesPanel = New-Object -TypeName 'System.Windows.Forms.Panel' -Property #{
# To illustrate the changing Size of the Panel
BackColor = [System.Drawing.Color]::GreenYellow
Location = New-Object -TypeName 'System.Drawing.Point' -Property #{
X = 27
Y = 200
}
Name = 'HostPropertiesPanel'
Size = [System.Drawing.Size]::Empty
}
$form1.Controls.Add($HostPropertiesPanel)
This eliminates the need to keep track of the CheckBoxes ourselves since we'll know they're all contained within this Panel. The Size is initially Empty since there's no CheckBoxes to display until a host is selected.
Inside of Click/$PC we'll then change how our host properties are defined...
# Set $hostProperties to a Hashtable array for the corresponding value of $hostname
# The IsChecked values are arbitrary for demonstration purposes
#TODO: Replace if...elseif with a switch statement; see "help about_Switch"
$hostProperties = if ($hostname -eq "ServerA") {
#{ Label = 'Zero'; IsChecked = $false },
#{ Label = 'One'; IsChecked = $true },
#{ Label = 'Two'; IsChecked = $true },
#{ Label = 'Three'; IsChecked = $false }
}
elseif ($hostname -eq "ServerB") {
#{ Label = '0'; IsChecked = $true },
#{ Label = '1'; IsChecked = $false },
#{ Label = '2'; IsChecked = $false },
#{ Label = '3'; IsChecked = $true }
}
elseif ($hostname -eq "ServerC") {
#{ Label = 'A'; IsChecked = $true },
#{ Label = 'B'; IsChecked = $true },
#{ Label = 'C'; IsChecked = $false }
}
elseif ($hostname -eq "ServerD") {
# Create a property (Hashtable) for each day of the week
[Enum]::GetNames([DayOfWeek]) | ForEach-Object -Process {
#{
Label = $_
# Check the box if the day name has an odd number of vowels
IsChecked = [Regex]::Matches($_, '[aeiou]').Count % 2 -eq 1
}
}
}
else {
# Oops! A host with no properties defined was selected...
}
Instead of using one array to store labels and another to store CheckBox states, we get one array of Hashtables based on which host has been selected and store it in $hostProperties.
Before we create the new CheckBoxes we must remove any existing ones from $HostPropertiesPanel and resize it based on the Length of the selected host's properties...
# Remove all existing CheckBoxes from the Panel
$HostPropertiesPanel.Controls.Clear()
# Resize the Panel to accommodate the new count of host properties
$HostPropertiesPanel.Size = New-Object -TypeName 'System.Drawing.Size' -Property #{
Width = 104
Height = if ($hostProperties.Length -gt 0) {
($hostProperties.Length - 1) * 31 + 24
}
else {
0
}
}
Then we just need to tweak the code that creates and configures each CheckBox...
for ($index = 0; $index -lt $hostProperties.Length; $index++) {
$CheckBox = New-Object System.Windows.Forms.CheckBox
$CheckBox.UseVisualStyleBackColor = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 104
$System_Drawing_Size.Height = 24
$CheckBox.Size = $System_Drawing_Size
$CheckBox.TabIndex = 2
$CheckBox.Text = $hostProperties[$index].Label
$CheckBox.Checked = $hostProperties[$index].IsChecked
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 0
# Make sure to vertically space them dynamically, counter comes in handy
$System_Drawing_Point.Y = $index * 31 #Controls location on Y axis
$CheckBox.Location = $System_Drawing_Point
$CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0
# Give it a unique name based on our counter
$CheckBox.Name = "CheckBox$index"
$HostPropertiesPanel.Controls.Add($CheckBox)
}
The key change is to retrieve the Text and Checked values for the new CheckBox using the current of $index in $hostProperties.
The final change is to update the list of host names...
$dropdown.Items.AddRange(
#('ServerA', 'ServerB', 'ServerC', 'ServerD', 'ServerX')
)
$form1.Controls.Add($dropdown)
The full script then looks like this...
function GenerateForm {
$PC = {
$hostname = $dropdown.SelectedItem
# Set $hostProperties to a Hashtable array for the corresponding value of $hostname
# The IsChecked values are arbitrary for demonstration purposes
#TODO: Replace if...elseif with a switch statement; see "help about_Switch"
$hostProperties = if ($hostname -eq "ServerA") {
#{ Label = 'Zero'; IsChecked = $false },
#{ Label = 'One'; IsChecked = $true },
#{ Label = 'Two'; IsChecked = $true },
#{ Label = 'Three'; IsChecked = $false }
}
elseif ($hostname -eq "ServerB") {
#{ Label = '0'; IsChecked = $true },
#{ Label = '1'; IsChecked = $false },
#{ Label = '2'; IsChecked = $false },
#{ Label = '3'; IsChecked = $true }
}
elseif ($hostname -eq "ServerC") {
#{ Label = 'A'; IsChecked = $true },
#{ Label = 'B'; IsChecked = $true },
#{ Label = 'C'; IsChecked = $false }
}
elseif ($hostname -eq "ServerD") {
# Create a property (Hashtable) for each day of the week
[Enum]::GetNames([DayOfWeek]) | ForEach-Object -Process {
#{
Label = $_
# Check the box if the day name has an odd number of vowels
IsChecked = [Regex]::Matches($_, '[aeiou]').Count % 2 -eq 1
}
}
}
else {
# Oops! A host with no properties defined was selected...
}
# Don't execute any layout logic until all changes are complete
$HostPropertiesPanel.SuspendLayout()
# Remove all existing CheckBoxes from the Panel
$HostPropertiesPanel.Controls.Clear()
# Resize the Panel to accommodate the new count of host properties
$HostPropertiesPanel.Size = New-Object -TypeName 'System.Drawing.Size' -Property #{
Width = 104
Height = if ($hostProperties.Length -gt 0) {
($hostProperties.Length - 1) * 31 + 24
}
else {
0
}
}
for ($index = 0; $index -lt $hostProperties.Length; $index++) {
$CheckBox = New-Object System.Windows.Forms.CheckBox
$CheckBox.UseVisualStyleBackColor = $True
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 104
$System_Drawing_Size.Height = 24
$CheckBox.Size = $System_Drawing_Size
$CheckBox.TabIndex = 2
$CheckBox.Text = $hostProperties[$index].Label
$CheckBox.Checked = $hostProperties[$index].IsChecked
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 0
# Make sure to vertically space them dynamically, counter comes in handy
$System_Drawing_Point.Y = $index * 31 #Controls location on Y axis
$CheckBox.Location = $System_Drawing_Point
$CheckBox.DataBindings.DefaultDataSourceUpdateMode = 0
# Give it a unique name based on our counter
$CheckBox.Name = "CheckBox$index"
$HostPropertiesPanel.Controls.Add($CheckBox)
}
# All changes are complete, so resume layout logic
$HostPropertiesPanel.ResumeLayout()
}
$form1 = New-Object System.Windows.Forms.Form
$form1.Text = "UCCE Log Collector - Version 2.0"
$form1.Name = "form1"
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 1150
$System_Drawing_Size.Height = 500
$form1.ClientSize = $System_Drawing_Size
$dropdown = New-Object System.Windows.Forms.ListBox
$dropdown.Location = New-Object System.Drawing.Point(10, 50)
$dropdown.Size = New-Object System.Drawing.Size(100, 20)
$dropdown.Height = 80
$dropdown.Items.AddRange(
#('ServerA', 'ServerB', 'ServerC', 'ServerD', 'ServerX')
)
$form1.Controls.Add($dropdown)
######### Select Server Button
$SelectPC = New-Object System.Windows.Forms.Button
$SelectPC.TabIndex = 4
$SelectPC.Name = "SelectPC"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 120
$System_Drawing_Size.Height = 30
$SelectPC.Size = $System_Drawing_Size
$SelectPC.UseVisualStyleBackColor = $True
$SelectPC.Text = "Select Server"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 0 # 0
$System_Drawing_Point.Y = 150 #150
$SelectPC.Location = $System_Drawing_Point
$SelectPC.DataBindings.DefaultDataSourceUpdateMode = 0
$SelectPC.add_Click($PC)
$form1.Controls.Add($SelectPC)
# Create a Panel to contain the dynamic collection of CheckBoxes
$HostPropertiesPanel = New-Object -TypeName 'System.Windows.Forms.Panel' -Property #{
# To illustrate the changing Size of the Panel
BackColor = [System.Drawing.Color]::GreenYellow
Location = New-Object -TypeName 'System.Drawing.Point' -Property #{
X = 27
Y = 200
}
Name = 'HostPropertiesPanel'
Size = [System.Drawing.Size]::Empty
}
$form1.Controls.Add($HostPropertiesPanel)
$name = New-Object System.Windows.Forms.Label -Property #{
Text = "Start Time"
Location = "900, 220"
ForeColor = "Black"
Height = 22
Width = 200
}
$form1.Controls.Add($name)
$result = $form1.ShowDialog()
$result
}
GenerateForm
An alternative approach, particularly for a large number of host properties, would be to replace the Panel and its contents with a CheckedListBox.

Load Function on start of Form

I would like to know how I can load a function when form is started?
In this example I would like to launch the function test() which adds a line to the RichTextBox. I don't want a button and when I try $form1.Show the form doesn't work.
$ErrorActionPreference = 'Continue'
Function test {
$richtextbox1.AppendText("testttt `n")
}
function CreateForm {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form1 = New-Object System.Windows.Forms.Form
#Form Parameter
$form1.Text = ""
$form1.Name = ""
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 600
$System_Drawing_Size.Height = 500
$form1.ClientSize = $System_Drawing_Size
$Form1.MinimizeBox = $false
$Form1.MaximizeBox = $true
$form1.ControlBox = $true
$form1.Topmost = $true
$Form1.AutoSize = $true
$Form1.ShowInTaskbar = $false
$form1.StartPosition = "CenterScreen"
$label1 = New-Object System.Windows.Forms.Label
$label1.Location = New-Object System.Drawing.Point(200, 40)
$label1.Size = New-Object System.Drawing.Size(400, 40)
$label1.Text = ""
$label1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 18, [System.Drawing.FontStyle]::Bold)
$form1.Controls.Add($label1)
$label2 = New-Object System.Windows.Forms.Label
$label2.Location = New-Object System.Drawing.Point(50, 125)
$label2.Size = New-Object System.Drawing.Size(400, 40)
$label2.Text = "Step : "
$label2.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 18, [System.Drawing.FontStyle]::Bold)
$form1.Controls.Add($label2)
$label3 = New-Object System.Windows.Forms.Label
$label3.Location = New-Object System.Drawing.Point(50, 175)
$label3.Size = New-Object System.Drawing.Size(400, 40)
$label3.Text = " in Progress"
$label3.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 18, [System.Drawing.FontStyle]::Bold)
$form1.Controls.Add($label3)
$richTextBox1 = New-Object System.Windows.Forms.RichTextBox
$richTextBox1.Location = New-Object System.Drawing.Point(50, 250)
$richTextBox1.Size = New-Object System.Drawing.Size(500, 200)
$richTextBox1.Text = " : `n"
$richTextBox1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 18, [System.Drawing.FontStyle]::Bold)
$form1.Controls.Add($richTextBox1)
$InitialFormWindowState = $form1.WindowState
#Show the Form
$form1.ShowDialog()
test
}
CreateForm
The CreateForm-function will freeze on $form1.ShowDialog() until the form is closed, so test will never run. What you can do is add test as an eventhandler to the Shown-event that is trigged on the first launch of a form.
Replace:
$form1.ShowDialog()
test
with:
$form1.add_Shown({ test } )
$form1.ShowDialog()
You can also run the function before showing the dialog since it only modifies the form anyways (or just do the modifications directly in the form-code):
test
$form1.ShowDialog()

Creating a progress bar for a search function

I am trying to make a progress bar in a powershell generated GUI that will show the progress of a search as the system caches all the groups in AD (there are about 12,000 so this just otherwise causes the system to hang for a short while)
I managed to build the bar etc but I cannot get it to fill the bar as the system adds the groups. Here is what I have so far:
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
$Form = New-Object System.Windows.Forms.Form
$Form.width = 345
$Form.height = 345
$Form.StartPosition = "CenterScreen"
$Form.ShowInTaskbar = $True
$Form.FormBorderStyle = 'FixedToolWindow'
$ExitButt = new-object System.Windows.Forms.Button
$ExitButt.Location = new-object System.Drawing.Size(235,5)
$ExitButt.Size = new-object System.Drawing.Size(100,20)
$ExitButt.Text = "Exit"
$Form.Controls.Add($ExitButt)
$ExitButt.Add_Click({$Form.Close()})
$Prog = New-Object System.Windows.Forms.ProgressBar
$Prog.Maximum = 10000
$Prog.Minimum = 0
$Prog.Location = new-object System.Drawing.Size(50,50)
$Prog.size = new-object System.Drawing.Size(100,50)
$Form.Controls.Add($Prog)
$Button = new-object System.Windows.Forms.Button
$Button.Location = new-object System.Drawing.Size(120,100)
$Button.Size = new-object System.Drawing.Size(100,30)
$Button.Text = "Start Progress"
$Form.Controls.Add($Button)
$Button.add_click(
{
$GroupsList = Get-ADGroup -Server "server" -Filter *
$Count = ($GroupsList | Measure-Object).Count
$prog.Value = $Count
}
)
$form.ShowDialog() | Out-Null
To update a WinForms ProgressBar just set its Value property.
Eg.
# Initialisation...
$myProgBar.Minimum = 1;
$myProgBar.Maximum = 100;
# When something happens...
$myProgBar.Value = 50;
will set it to half way.

Start-Job\Receive-Job is hanging\freezing while getting results - PrimalForm CE GUI

I can start the job but how can I continue using my program while its getting the information, if I do a 'while' loop it just freezes the program until the results have completed.
Here is the script generated by PrimalForms CE edition, and my code is in button1_OnClick.
End result I want to have the script running to check for locked out AD users (but that can really be anything) then while that is running I want to review the previous results and unlock a user if needed...
#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0
# Generated On: 7/09/2015 2:24 PM
# Generated By: stojanp2
########################################################################
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$button3 = New-Object System.Windows.Forms.Button
$button2 = New-Object System.Windows.Forms.Button
$listView1 = New-Object System.Windows.Forms.ListView
$button1 = New-Object System.Windows.Forms.Button
$Users = New-Object System.Windows.Forms.ColumnHeader
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$button3_OnClick =
{
#TODO: Place custom script here
}
$button1_OnClick =
{
Start-Job -Name FindUsers -ScriptBlock { Search-ADAccount -LockedOut | Select-Object * }#end Start-Job
Do {
Start-Sleep -Seconds 1
write-host "waiting" # so i can see its doing something in the console
} Until (#(Get-Job -Name FindUsers).State -eq "Completed")
Write-Host "done"
$us = Receive-Job -Name FindUsers
ForEach ($u IN $us){
$listView1.Items.Add($u.sAMAccountName)
}
Get-Job -Name FindUsers | Remove-Job -Force
}
$button2_OnClick =
{
#TODO: Place custom script here
}
$handler_listView1_SelectedIndexChanged =
{
#TODO: Place custom script here
}
$OnLoadForm_StateCorrection =
{ #Correct the initial state of the form to prevent the .Net maximized form issue
$form1.WindowState = $InitialFormWindowState
}
#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 469
$System_Drawing_Size.Width = 271
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"
$form1.Text = "Primal Form"
$button3.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 142
$System_Drawing_Point.Y = 418
$button3.Location = $System_Drawing_Point
$button3.Name = "button3"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 117
$button3.Size = $System_Drawing_Size
$button3.TabIndex = 3
$button3.Text = "button3"
$button3.UseVisualStyleBackColor = $True
$button3.add_Click($button3_OnClick)
$form1.Controls.Add($button3)
$button2.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 418
$button2.Location = $System_Drawing_Point
$button2.Name
= "button2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 117
$button2.Size = $System_Drawing_Size
$button2.TabIndex = 2
$button2.Text = "button2"
$button2.UseVisualStyleBackColor = $True
$button2.add_Click($button2_OnClick)
$form1.Controls.Add($button2)
$listView1.Columns.Add($Users)|Out-Null
$listView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 73
$listView1.Location = $System_Drawing_Point
$listView1.Name = "listView1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 339
$System_Drawing_Size.Width = 247
$listView1.Size = $System_Drawing_Size
$listView1.TabIndex = 1
$listView1.UseCompatibleStateImageBehavior = $False
$listView1.View = 1
$listView1.add_SelectedIndexChanged($handler_listView1_SelectedIndexChanged)
$form1.Controls.Add($listView1)
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$button1.Location = $System_Drawing_Point
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 55
$System_Drawing_Size.Width = 247
$button1.Size = $System_Drawing_Size
$button1.TabIndex = 0
$button1.Text = "button1"
$button1.UseVisualStyleBackColor = $True
$button1.add_Click($button1_OnClick)
$form1.Controls.Add($button1)
$Users.Name = "Users"
$Users.Text = "User Names"
$Users.Width = 116
#endregion Generated Form Code
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog() | Out-Null
} #End Function
#Call the Function
GenerateForm
I can't speak about PrimalForm but in PowerShell Studio there is a seperate button called Button - Start Job in the section Toolbox > Control Sets:
When using this type of button an extra function is provided called Add-JobTracker that keeps track of the job progress and makes sure that the job is ran in the background in its own PowerShell session. So it doesn't freeze the interface and even updates a progress bar if you will.
More info on the SAPIEN page PowerShell Studio: Creating responsive forms.
The fact that your are doing a loop to check every time the status of the job is why the interface freezes. It will stop every time at that point and only frees up again when the job is completely done.
Maybe if you update PrimalForms to the latest version you'll have this function to.

How to merge cells in DataGridView using Powershell

Dear Powershell savants,
I recently discovered that using WinForms with PowerShell is a great way to create small yet really useful GUIs. I'm currently working with DataGridView and am trying to get fancy with visual properties - specifically, I was wondering if there was a way to merge cells so that I could make 'sub-headers' reflecting which parent node from my tree is associated with selected children. If that doesn't make much sense, what I'm trying to accomplish is depicted in the following:
Is there a way to merge and center cells or at least a way to remove grid lines on certain cells to achieve the depicted salmon colored row effect?
This person and this other person asked similar questions although a PowerShell solution isn't readily translated.
Base code without tree functionality follows (adapted from technet post):
#The following is adapted from https://gallery.technet.microsoft.com/ScriptCenter/3dcf0354-e7a7-482c-86f1-2e75809a502d/
function Get-ProcessInfo {
$array = New-Object System.Collections.ArrayList
$Script:procInfo = Get-Process | Select Id,Name,Path,Description | sort -Property Name
$array.AddRange($procInfo)
$dataGridView1.DataSource = $array
$form1.refresh()
}
#Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.8.0
# Generated On: 2/24/2010 11:38 AM
# Generated By: Ravikanth Chaganti (http://www.ravichaganti.com/blog)
########################################################################
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$label1 = New-Object System.Windows.Forms.Label
$button3 = New-Object System.Windows.Forms.Button
$button2 = New-Object System.Windows.Forms.Button
$button1 = New-Object System.Windows.Forms.Button
$dataGridView1 = New-Object System.Windows.Forms.DataGridView
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$button3_OnClick=
{
#$Form1.Close()
#$dataGridView1.SelectedRows | Foreach {$dataGridView1.Rows[$_.Index].DefaultCellStyle.BackColor = "Red"}
# $System_Windows_Forms_DataGridViewCellStyle_1.BackColor = 'White'
# $dataGridView1.DefaultCellStyle = $System_Windows_Forms_DataGridViewCellStyle_1
#Wipe Highlights without refreshing form
for($i=0; $i -le $dataGridView1.RowCount-1; $i++) {$dataGridView1.Rows[$i].DefaultCellStyle.BackColor = "White"}
}
$button1_OnClick=
{
#Get-ProcessInfo
}
$button2_OnClick=
{
$dataGridView1.SelectedRows | Foreach {$dataGridView1.Rows[$_.Index].DefaultCellStyle.BackColor = "Red"}
# $selectedRow = $dataGridView1.SelectedRows[0].Index
# if (($procid=$Script:procInfo[$selectedRow].Id)) {
#Stop-Process -Id $procid -Confirm
# $dataGridView1.Rows.Item($selectedRow).DefaultCellStyle.BackColor = "Red"
#}
}
$OnLoadForm_UpdateGrid=
{
Get-ProcessInfo
}
#----------------------------------------------
#region Generated Form Code
$form1.Text = "Primal Form"
$form1.Name = "form1"
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 517
$System_Drawing_Size.Height = 414
$form1.ClientSize = $System_Drawing_Size
$label1.TabIndex = 4
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 155
$System_Drawing_Size.Height = 23
$label1.Size = $System_Drawing_Size
$label1.Text = "Process Manager"
$label1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",9.75,2,3,0)
$label1.ForeColor = [System.Drawing.Color]::FromArgb(255,0,102,204)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 13
$label1.Location = $System_Drawing_Point
$label1.DataBindings.DefaultDataSourceUpdateMode = 0
$label1.Name = "label1"
$form1.Controls.Add($label1)
$button3.TabIndex = 3
$button3.Name = "button3"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$button3.Size = $System_Drawing_Size
$button3.UseVisualStyleBackColor = $True
$button3.Text = "Clear Highlights"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 429
$System_Drawing_Point.Y = 378
$button3.Location = $System_Drawing_Point
$button3.DataBindings.DefaultDataSourceUpdateMode = 0
$button3.add_Click($button3_OnClick)
$form1.Controls.Add($button3)
$button2.TabIndex = 2
$button2.Name = "button2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$button2.Size = $System_Drawing_Size
$button2.UseVisualStyleBackColor = $True
$button2.Text = "Highlight"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 230
$System_Drawing_Point.Y = 378
$button2.Location = $System_Drawing_Point
$button2.DataBindings.DefaultDataSourceUpdateMode = 0
$button2.add_Click($button2_OnClick)
$form1.Controls.Add($button2)
$button1.TabIndex = 1
$button1.Name = "button1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 75
$System_Drawing_Size.Height = 23
$button1.Size = $System_Drawing_Size
$button1.UseVisualStyleBackColor = $True
$button1.Text = "Refresh"
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 379
$button1.Location = $System_Drawing_Point
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$button1.add_Click($button1_OnClick)
$form1.Controls.Add($button1)
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 492
$System_Drawing_Size.Height = 308
$dataGridView1.Size = $System_Drawing_Size
$dataGridView1.DataBindings.DefaultDataSourceUpdateMode = 0
$dataGridView1.Name = "dataGridView1"
$dataGridView1.DataMember = ""
$dataGridView1.TabIndex = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 48
$dataGridView1.Location = $System_Drawing_Point
$form1.Controls.Add($dataGridView1)
#endregion Generated Form Code
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Add Form event
$form1.add_Load($OnLoadForm_UpdateGrid)
#Show the Form
$form1.ShowDialog()| Out-Null
} #End Function
#Call the Function
GenerateForm
Is this possible?
This describes how to implement "handlers for both events in order to provide a gradient selection background and some custom foreground content that spans multiple columns."
To answer this question I browsed through the doc here. Microsoft documentation doesn't always go into depth on how to use APIs, but when it does, it's worth reading, as is the case in this instance.

Resources