I'm fairly new to Powershell and wrote this form for some colleagues. I just wanted to get some advice and guidance on how it's written, what could be better or if it's fine the way it is. Thanks.
enter image description here
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
function _Search {
if ($UernameSearch) {Clear-Variable -Name UernameSearch}
$OutputBox1.Clear()
$TextSearch = $SearchBox1.Text
$UernameSearch = gwmi win32_computersystem -comp $TextSearch | select USername
if ($UernameSearch) {
if ($UernameSearch.USername) {$OutputBox1.Text = $UernameSearch.USername}
else {$OutputBox1.Text = "No user currently logged on."}}
else {$OutputBox1.Text = "Is $TextSearch offline?"}
$OutputBox1.Enabled = $true
}
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Who's Logged In"
$Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell.exe")
$objForm.Icon = $Icon
$objForm.Size = New-Object System.Drawing.Size(250,200)
$objForm.StartPosition = "CenterScreen"
$objForm.MaximizeBox = $false
$objForm.FormBorderStyle = 'Fixed3D'
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") {$objForm.Close()}})
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(30,5)
$objLabel.AutoSize = $true
$objLabel.TextAlign = "TopCenter"
$objLabel.Text = "Use this tool to find who is currently
logged onto a remote machine."
$objForm.Controls.Add($objLabel)
$objLabe2 = New-Object System.Windows.Forms.Label
$objLabe2.Location = New-Object System.Drawing.Size(60,50)
$objLabe2.Size = New-Object System.Drawing.Size(150,15)
$objLabe2.Text = "Enter Computer Name"
$objForm.Controls.Add($objLabe2)
$SearchBox1 = New-Object System.Windows.Forms.TextBox
$SearchBox1.Location = New-Object System.Drawing.Size(15,70)
$SearchBox1.Height = 25
$SearchBox1.Width = 210
$SearchBox1.Multiline = $false
$SearchBox1.Add_KeyDown({if ($_.KeyCode -eq "Enter") {_Search}})
$objForm.Controls.Add($SearchBox1)
$SearchButton = New-Object System.Windows.Forms.Button
$SearchButton.Location = New-Object System.Drawing.Size(15,95)
$SearchButton.Height = 25
$SearchButton.Width = 210
$SearchButton.Text = "GO!"
$SearchButton.Add_Click({_Search})
$objForm.Controls.Add($SearchButton)
$OutputBox1 = New-Object System.Windows.Forms.TextBox
$OutputBox1.Location = New-Object System.Drawing.Size(15,125)
$OutputBox1.Multiline = $false
$OutputBox1.Height = 25
$OutputBox1.Width = 210
$OutputBox1.Multiline = $false
$OutputBox1.Enabled = $false
$objForm.Controls.Add($OutputBox1)
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
Windows.Forms vs WPF
Windows Presentation Foundation is the more advanced alternative. It's nice, but there's a learning curve.
A lot of the display code you have would vanish off into a XAML file (a blob of XML) meaning you can get on with the wiring behind.
Variable naming
Hungarian notation (the "obj" prefix) is a bit pointless. Especially considering that you don't apply it consistently.
Pascal case or camel case are popular conventions these days. e.g.
Pascal: MyVariable
Camel: myVariable
I have my own, most people do. Pick something you're comfortable with and use it consistently.
function _Search
It's not easy to discover nor is it reusable. Why the underscore?
Consider making a generalised function that returns this information as a collection of objects. Your GUI can consume the output from that function and display it.
Assembly.LoadWithPartialName
Obsolete. It's ambiguous at best. Besides, there are neater PowerShell alternatives:
Add-Type -Assembly System.Windows.Forms
Aliases
gwmi, select, truncated parameter names: None of these have a place in production code.
Aliaes saves you a few keystrokes and that's fine when you're tapping away at the console. When you're developing something to share they increase obscurity.
Anyone reviewing or updating your code in the future must be familiar with both the command, which at least is descriptive, and the alias.
Consistent formatting
Style is always personal, but there are a small number of very popular ways of writing branching statements like this snippet:
if ($UernameSearch) {
if ($UernameSearch.USername) {$OutputBox1.Text = $UernameSearch.USername}
else {$OutputBox1.Text = "No user currently logged on."}}
else {$OutputBox1.Text = "Is $TextSearch offline?"}
Consider the style I prefer:
if ($UsernameSearch) {
if ($UsernameSearch.Username) {
$OutputBox1.Text = $UsernameSearch.Username
} else {
$OutputBox1.Text = "No user currently logged on."
}
} else {
$OutputBox1.Text = "Is $TextSearch offline?"
}
Related
I am attempting to create a form in Powershell. It contains a ComboBox dropdown option that I am using as a required field. Until an option is selected, the continue button will be disabled. This is the code for the ComboBox and the button enabling:
$TSTypeBox.Name = "TSType"
$TSTypeBox.Location = New-Object System.Drawing.Point(116,100)
$TSTypeBox.Size = New-Object System.Drawing.Size(145,20)
$TSTypeBox.add_MouseHover($ShowHelp)
$TSTypeBox.DropDownStyle = "DropDownList"
Foreach ($item in ("1","2","3","4","5")) {
$TSTypeBox.Items.Add($item) | Out-Null
}
$TSTypeBox.SelectedItem = $TSLocation
$handler_TSTypeBox_SelectedIndexChanged= {
If (($TSTypeBox.Text) -and ($ComputerNameBox.Text))
{
$OKButton.Enabled = 1
}
Else
{
$OKButton.Enabled = 0
}
}
$TSTypeBox.add_SelectedIndexChanged($handler_TSTypeBox_SelectedIndexChanged)
This code in particular works as intended so I'm not worried about that. I am here about the $TSTypeBox.SelectedItem = $TSLocation line that I included. I have code elsewhere that pulls the IP address of the computer the program is being run on, which is then matched against an if/elseif/else statement to determine if the computer belongs to 1 or to 2, which are options that you can see were added to the ComboBox in the code above.
That if/else statement updated the $TSLocation variable which I then use to force the selection of one of the dropdown options in the ComboBox. This works as well, but unfortunately it does not enable the continue button as I would like. I had a hard time looking up issues about this because its super particular and I am probably doing this incorrectly (I have very little experience with Powershell scripting). If you have any additional questions about this please let me know. Thanks!
Ok, this might illustrate your problem.
Just because you set the SelectedItem value to something, doesn't mean the SelectedIndex changes
#
Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
#
$TSLocation = '2'
#
$form = New-Object System.Windows.Forms.Form
$form.Text = "Test"
$form.MinimumSize = '430,495'
$form.MaximumSize = '430,545'
$form.StartPosition = 'CenterScreen'
#
# Add form objects
#
$TSTypeBox = New-Object System.Windows.Forms.ComboBox
$TSTypeBox.Name = "TSType"
$TSTypeBox.Location = '116,100'
$TSTypeBox.Size = '145,20'
$TSTypeBox.add_MouseHover($ShowHelp)
$TSTypeBox.DropDownStyle = "DropDownList"
Foreach ($item in ("1","2","3","4","5")) {
$TSTypeBox.Items.Add($item) | Out-Null
}
$ComputerNameBox = New-Object System.Windows.Forms.TextBox
$ComputerNameBox.Location = '120,20'
$ComputerNameBox.Size = '120,17'
$ComputerNameBox.Text = 'test'
$OutputBox = New-Object System.Windows.Forms.TextBox
$OutputBox.Location = '120,240'
$OutputBox.Size = '120,17'
$OkButton = New-Object System.Windows.Forms.Button
$OkButton.Location = '120,200'
$OkButton.Size = '54,24'
$OkButton.Text = 'OK'
$form.controls.AddRange(#($TSTypeBox,$OkButton,$ComputerNameBox,$OutputBox))
#
# Main Script goes here
#
$handler_TSTypeBox_SelectedIndexChanged= {
$OutputBox.Text = "SelectedIndex is " + $TSTypeBox.SelectedIndex
If (($TSTypeBox.Text) -and ($ComputerNameBox.Text))
{
$OKButton.Enabled = 1
}
Else
{
$OKButton.Enabled = 0
}
}
$TSTypeBox.add_SelectedIndexChanged($handler_TSTypeBox_SelectedIndexChanged)
#
$TSTypeBox.SelectedIndex = $TSTypeBox.FindStringExact($TSLocation)
#
# Show form
$form.ShowDialog() | Out-Null
$form.Dispose()
# End
If in doubt, always best to simplify your script and add debug ,logging or output that shows what values are changing
Now that the problem is clear - this article points you in the right direction:
How do I set the selected item in a comboBox to match my string using C#?
I have a PS script that implements System.Windows.Forms in order to query technicians for some data.
I create the forms and set both .Topmost and .TopLevel to true in an attempt to have them show up over the Powershell window, but they continue to (for some reason inconsistently) appear behind the Powershell window. This slows down the process and is confusing in its inconsistency.
If anyone knows how to ensure these windows stay top without a mountain of code larger than the script itself that would be incredibly useful. I'll include the code I use to build one of the basic forms below.
Any simple solution that will allow these Forms to appear over the Powershell window is appreciated. It could even just minimize the PS window, but I don't want to launch without the window as we need it open. Thanks.
$form.Text = 'Computer Name Entry'
$form.Size = New-Object System.Drawing.Size(550,400)
$form.StartPosition = 'CenterScreen'
$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(75,300)
$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(400,40)
$label.Text = 'Text is here:'
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,70)
$textBox.Size = New-Object System.Drawing.Size(400,20)
$form.Controls.Add($textBox)
$form.Topmost = $true
$form.TopLevel = $true
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
Do-Stuff
}
The easiest way I know of forcing the form to be topmost is to open it with a new temporary form that is TopMost as parameter for ShowDialog().
First, from your code remove the lines $form.Topmost = $true and $form.TopLevel = $true
Next, show your form like this:
# force the dialog TopMost by creating a temporary parent window for this form
$result = $form.ShowDialog((New-Object System.Windows.Forms.Form -Property #{TopMost = $true }))
Another way of doing this is to use a piece of C# to return a windowhandle which implements the IWin32Window interface.
Then use this handle as the owner window for this form in the .ShowDialog() method of the form.
For this method, also remove the lines $form.Topmost = $true and $form.TopLevel = $true from your original code.
$iWin32Code = #"
using System;
using System.Windows.Forms;
public class Win32Window : IWin32Window {
public Win32Window(IntPtr handle) {
Handle = handle;
}
public IntPtr Handle { get; private set; }
}
"#
if (-not ([System.Management.Automation.PSTypeName]'Win32Window').Type) {
Add-Type -TypeDefinition $iWin32Code -ReferencedAssemblies System.Windows.Forms.dll
}
Now, using that code, create a handle for the currently running PowerShell process
# get the owner handle from this PowerShell process
$ownerHandle = New-Object Win32Window -ArgumentList ([System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle)
# and use that in the ShowDialog method as argument
$result = $form.ShowDialog($ownerHandle)
P.S. do not forget to clear your form from memory after you are done with it by calling
$form.Dispose()
I'm trying to build a little app to help admins swap powerapps ownership around in PowerShell. I'm sure this is me misunderstanding how scopes work in PowerShell but I'm stumped and need a little help.
The app is pretty simple, it queries the PowerApp environment for a list of apps, their owners, and their GUIDs and presents them in a datagridview. Users select the app they're going to change, click a button, put an email address in, and then click another button. On that click, the app grabs the user's GUID from AAD and then runs a command to flip ownership of the app to that user's GUID.
But for some reason, the second function keeps reporting that the GUID and App Name I collected in the first screen are empty strings.
Here's the whole thing (minus credential info, natch):
#Get Apps on environment
$apps = Get-AdminPowerApp -EnvironmentName $powerAppEnv
#Form Details
$ChangePowerAppOwnership = New-Object system.Windows.Forms.Form
$ChangePowerAppOwnership.ClientSize = New-Object System.Drawing.Point(500,300)
$ChangePowerAppOwnership.text = "Change PowerApp Ownership"
$ChangePowerAppOwnership.TopMost = $false
$appsLabel = New-Object system.Windows.Forms.Label
$appsLabel.text = "Available Apps"
$appsLabel.AutoSize = $true
$appsLabel.width = 25
$appsLabel.height = 10
$appsLabel.location = New-Object System.Drawing.Point(15,20)
$appsLabel.Font = New-Object System.Drawing.Font('Segoe UI',10)
$availableApps = New-Object system.Windows.Forms.DataGridView
$availableApps.width = 470
$availableApps.height = 200
$availableApps.location = New-Object System.Drawing.Point(15,40)
$availableApps.MultiSelect = $false
$availableApps.SelectionMode = "FullRowSelect"
$availableApps.ColumnCount = 3
$availableApps.ColumnHeadersVisible = $true
$availableApps.Columns[0].Name = "App Name"
$availableApps.Columns[1].Name = "Current Owner"
$availableApps.Columns[2].Name = "GUID"
foreach($app in $apps){
$availableApps.Rows.Add(#($app.DisplayName,($app.Owner | Select-Object -Expand displayName),$app.AppName))
}
$promptForAdmin = New-Object system.Windows.Forms.Button
$promptForAdmin.text = "Next"
$promptForAdmin.width = 60
$promptForAdmin.height = 30
$promptForAdmin.location = New-Object System.Drawing.Point(424,260)
$promptForAdmin.Font = New-Object System.Drawing.Font('Segoe UI',10)
$promptForAdmin.Add_Click({ GetNewAdmin $availableApps.SelectedRows})
$adminLabel = New-Object system.Windows.Forms.Label
$adminLabel.text = "New Administrator"
$adminLabel.AutoSize = $true
$adminLabel.width = 25
$adminLabel.height = 10
$adminLabel.location = New-Object System.Drawing.Point(14,13)
$adminLabel.Font = New-Object System.Drawing.Font('Segoe UI',10)
$adminEmailField = New-Object system.Windows.Forms.TextBox
$adminEmailField.multiline = $false
$adminEmailField.width = 200
$adminEmailField.height = 20
$adminEmailField.location = New-Object System.Drawing.Point(135,12)
$adminEmailField.Font = New-Object System.Drawing.Font('Segoe UI',10)
$changeAppAdmin = New-Object system.Windows.Forms.Button
$changeAppAdmin.text = "Go"
$changeAppAdmin.width = 60
$changeAppAdmin.height = 30
$changeAppAdmin.location = New-Object System.Drawing.Point(424,260)
$changeAppAdmin.Font = New-Object System.Drawing.Font('Segoe UI',10)
$ChangePowerAppOwnership.controls.AddRange(#($appsLabel,$availableApps,$promptForAdmin))
$ChangePowerAppOwnership.ShowDialog()
function GetNewAdmin {
param($selectedRows)
$selectedAppGuid = $selectedRows | ForEach-Object{ $_.Cells[2].Value }
$selectedAppName = $selectedRows | ForEach-Object{ $_.Cells[0].Value }
Write-Host "Selected App GUID: $selectedAppGuid" #this and the following command show values
Write-Host "Selected App Name: $selectedAppName"
$appsLabel.Visible = $false
$availableApps.Visible = $false
$promptForAdmin.Visible = $false
$changeAppAdmin.Add_Click( { AssignNewAdmin $selectedAppGuid $selectedAppName $adminEmailField.Text} )
$ChangePowerAppOwnership.controls.AddRange(#($adminLabel,$adminEmailField,$changeAppAdmin))
}
function AssignNewAdmin {
param(
$selectedAppGuid,
$selectedAppName,
$newAdminEmail
)
Write-Host "AppID: $selectedAppGuid" #this is always empty
Connect-AzureAD -Credential $credentials
$user = Get-AzureADUser -ObjectId $newAdminEmail
$newAppOwnerGuid = $user | select ObjectId
$newAppOwnerName = $user | select DisplayName
$msgBoxMessage = "Are you sure you want to grant ownership of $selectedAppName to $newAppOwnerName`?"
$msgBoxInput = [System.Windows.Forms.MessageBox]::Show($msgBoxMessage,"Confirm","YesNo","Error")
switch ($msgBoxInput){
'Yes'{
Set-AdminPowerAppOwner -AppName $selectedAppGuid -EnvironmentName $powerAppEnv -AppOwner $newAppOwnerGuid
# try{
# $ChangePowerAppOwnership.Close()
# }
# catch{
# Write-Host "Could not update this app's administrator role."
# }
}
'No' {
$ChangePowerAppOwnership.Close()
}
}
}
Move the functions to the top or at least higher than $ChangePowerAppOwnership.ShowDialog() or the script wont find them(the execution stops till you close the Form...).
The same goes for the function AssignNewAdmin as it is used in GetNewAdmin but defined later.
Courtesy of Jeroen Mostert's comment, adding GetNewClosure to my second Add_Click function did the trick.
I'm trying to work around a script Under Windows.Form and I'm a little bit stuck.
I'd like to be able a specific list appears depending on the choice made from the first list, which means that at the start of the script, only one list has to appears and many other available depending of the choice made.
Here's the full script for reference
#Open a Window.
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$form.text = "Contrôles"
$form.Size = New-Object System.Drawing.Size(1000,700)
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,150)
$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)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,150)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
#Create the Data table (DataTable).
$table1 = New-Object system.Data.DataTable
$table2 = New-Object system.Data.DataTable
#Define the 2 column (Name, Type).
$colonne1 = New-Object system.Data.DataColumn Choice,([string])
$colonne2 = New-Object system.Data.DataColumn Choice,([string])
#Create columns in the data table.
$table1.columns.add($colonne1)
$table2.columns.add($colonne2)
#Add the data line by line in the data table.
$ligne = $table1.NewRow() #Creation of the new row.
$ligne.Choice = "Service" #In the column Choice we put the value we want.
$table1.Rows.Add($ligne) #Add a line in the data table.
$ligne = $table1.NewRow()
$ligne.Choice = "Software"
$table1.Rows.Add($ligne)
$ligne = $table1.NewRow()
$ligne.Choice = "Other"
$table1.Rows.Add($ligne)
#Add the data line by line in the data table.
$ligne = $table2.NewRow() #Creation of the new row.
$ligne.Choice = "Service Enable" #In the column Choice we put the value we want.
$table2.Rows.Add($ligne) #Add a line in the data table.
$ligne = $table2.NewRow()
$ligne.Choice = "Service Disable"
$table2.Rows.Add($ligne)
$ligne = $table2.NewRow()
$ligne.Choice = "Other"
$table2.Rows.Add($ligne)
#Create the View.
$vu1 = New-Object System.Data.DataView($table1)
$vu1.Sort="Choice ASC" #Tri la colonne "Extension" par ordre croissant.
$vu2 = New-Object System.Data.DataView($table2)
$vu2.Sort="Choice ASC"
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(650,50)
$label.Size = New-Object System.Drawing.Size(280,35)
$label.Text = 'Please enter the information in the space below:'
$form.Controls.Add($label)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(650,100)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
#Create the Drop-down list (ComboBox).
$liste1 = New-Object System.Windows.Forms.Combobox
$liste1.Location = New-Object Drawing.Point 20,50
$liste1.Size = New-Object System.Drawing.Size(150, 50)
$liste1.DropDownStyle = "DropDownList"
$liste2 = New-Object System.Windows.Forms.Combobox
$liste2.Location = New-Object Drawing.Point 350,50
$liste2.Size = New-Object System.Drawing.Size(150, 50)
$liste2.DropDownStyle = "DropDownList"
#Associate the Data to the Drop-down list
#To do so, we create a "Binding Context".
$liste1.BindingContext = New-Object System.Windows.Forms.BindingContext
$liste1.DataSource = $vu1 #Assigne the view that contains the sorted Data.
$liste1.DisplayMember = "Choice" #Column that will be displayed (Choice).
$liste2.BindingContext = New-Object System.Windows.Forms.BindingContext
$liste2.DataSource = $vu2 #Assigne the view that contains the sorted Data.
$liste2.DisplayMember = "Choice" #Column that will be displayed (Choice).
#Attach the control to the window.
$form.controls.add($liste1)
$form.controls.add($liste2)
#Show everything.
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
#Work the code arround.
if ($liste1.DisplayMember= "Service Enable")
{set-service -name RemoteRegistry -ComputerName $textBox.Text -StartupType Automatic}
if ($liste1.DisplayMember = "Service Disable")
{set-service -name RemoteRegistry -ComputerName $textBox.Text -StartupType Automatic}
Write-Host "ComboBox = " $liste1.DisplayMember
Write-Host "ComboBox = " $liste2.selectedvalue
#Fin.
If anybody have an idea where I could look, it would be great.
Thanks you
Nad
1. You have no form / trigger events in your code.
2. You don't have the correct GUI objects in your code to hold a list /
record result.
A form is just a container to hold elements until you add the code behind to make it do something. You have to have a proper GUI object to send that result to.
I am not sure if you are doing this all by hand in the ISE or VSCode or Notepad or whatever, but this is a good first effort. However, what you show, seems to indicate you are not really up to speed on GUI development / general app dev work, as what you are doing is not really unique to PowerShell, but something required for any app development client or web.
So, really, spend some time studying / reviewing general WPF/Winforms development and that form event stuff will be covered.
As for your use case, you need:
Define the list GUI object (multiline, ListBox, ListView, datagrid) to hold the results (synch'ing combox boxes mean adding and removing elements on event actions)
Define what that list is (text files, db read etc)
On the click, change or other form event, read from that list and populate
the GUI list object
There are many examples of this on this site and all over the web.
Here a good video on GUI development with PowerShell:
powershell populate combobox basing on the selected item on another combobox
From the above discussion (not something to just add to your code without understanding the what's and the why's):
Use a ComboBox.SelectionChangeCommitted Event:
"Occurs when the user changes the selected item and that change is displayed in the ComboBox"
$combobox2_SelectionChangeCommitted={
$Mailboxes = Get-Mailbox -OrganizationalUnit $ClientSelected
foreach ($mailbox in $Mailboxes)
{
$CurrentMailbox = "{0} ({1})" -f $mailbox.Name, $mailbox.Alias
Load-ComboBox $combobox2 $CurrentMailbox -Append
}
}
Use a button:
$button1_Click={
$Mailboxes = Get-Mailbox -OrganizationalUnit $ClientSelected
foreach ($mailbox in $Mailboxes)
{
$CurrentMailbox = "{0} ({1})" -f $mailbox.Name, $mailbox.Alias
Load-ComboBox $combobox2 $CurrentMailbox -Append
}
}
Lastly, using this …
Write-Host "ComboBox = " $liste1.DisplayMember
Write-Host "ComboBox = " $liste2.selectedvalue
… is not something one would do, because the console is not opened to see these results and Write-Host should be avoided except for when using console only text colorizations of other console only formatting scenarios, it also empties the display buffer, so it cannot be sent to anything else. Also, you don't have a GUI object called 'ComboBox' anywhere on the form, so it's not serving any purpose for your use case.
After some times and research, I managed to find what I needed exactly.
This might help people who stumble upon the post so here a small part of what I found
function Service()
{if ($ListBox1.SelectedItem -eq 'Enable Services')
{
$form.Controls.Add($Label3)
$form.Controls.add($ListBox2)
$form.Controls.Add($Label4)
$form.Controls.Add($textBox)
$form.Controls.Add($Button2)
$form.Controls.Add($Button3)
}
I create firstly a Function with a name, in which will countain the condition of what I'd like to happen when a choice is made in my listbox "ComboBox"
$button1.add_Click({ Service })
Then I call that function from a button I Added, in which other Boxes will appear upon click on that button.
It is not very different from #Postanote's answer but that was the solution I'm more at ease with.
As part of looking into creating a GUI for handling certain repetitive tasks i made for for a eight ball function. As part of this function i use an background image and an icon that is embedded in the script and written to $env:tmp.
Upon exit from the GUI i have a cleanup to remove the temporary files. However the script is unable to delete the background image while PowerShell is running even when the form has been terminated.¨
Remove-Item : Cannot remove item C:\Users\USERNAME\AppData\Local\Temp\11a8093b2817a3e1ff135fec4fe01320.jpg: The process cannot access the file 'C:\Users\USERNAME\AppData\Local\Temp\1
1a8093b2817a3e1ff135fec4fe01320.jpg' because it is being used by another process.
At C:\Users\USERNAME\Desktop\8ball.ps1:89 char:1
+ Remove-Item "$env:temp\11a8093b2817a3e1ff135fec4fe01320.jpg"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\Users\USERN~...fec4fe01320.jpg:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Is there any "simple" way i can get around this?
$MagicEightBallPicture = ""
$ContentPicture = [System.Convert]::FromBase64String($MagicEightBallPicture)
(Set-Content -Path $env:temp\11a8093b2817a3e1ff135fec4fe01320.jpg -Value $ContentPicture -Encoding Byte)
$MagicEightBallIcon = ""
$ContentIcon = [System.Convert]::FromBase64String($MagicEightBallIcon)
(Set-Content -Path $env:temp\11a8093b2817a3e1ff135fec4fe01320.ico -Value $ContentIcon -Encoding Byte)
$PossibleAnswers = #("It is certain",`
"It is decidedly so",`
"Without a doubt",`
"Yes, definitely",`
"You may rely on it",`
"As I see it, yes",`
"Most likely",`
"Outlook good",`
"Yes",`
"Signs point to yes",`
"Reply hazy try again",`
"Ask again later",`
"Better not tell you now",`
"Cannot predict now",`
"Concentrate and ask again",`
"Dont count on it",`
"My reply is no",`
"My sources say no",`
"Outlook not so good",`
"Very doubtful")
Function RollTheBall {
$TheAnswer = Get-Random -Count 1 -InputObject $PossibleAnswers
$TheAnswerBox.Text = $TheAnswer
}
Try {
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Image = [System.Drawing.Image]::Fromfile("$($env:temp)\11a8093b2817a3e1ff135fec4fe01320.jpg")
$Icon = New-Object System.Drawing.Icon ("$($env:temp)\11a8093b2817a3e1ff135fec4fe01320.ico")
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "Magic Eight Ball"
$Form.MinimizeBox = $False
$Form.MaximizeBox = $False
$Form.FormBorderStyle = 'Fixed3D'
$Form.SizeGripStyle = "Hide"
$Form.ShowInTaskbar = $False
$Form.StartPosition = "CenterScreen"
$Form.Icon = $Icon
$Form.BackgroundImage = $Image
$Form.BackgroundImageLayout = "None"
$Form.Width = $Image.Width
$Form.Height = $Image.Hight
$Form.Size = New-Object System.Drawing.Size(300,200)
$TheAnswerBox = New-Object System.Windows.Forms.TextBox
$TheAnswerBox.Location = New-Object System.Drawing.Size(10,10)
$TheAnswerBox.Size = New-Object System.Drawing.Size(270,20)
$TheAnswerBox.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Center
$TheAnswerBox.add_GotFocus({[System.Windows.Forms.SendKeys]::Send("{tab}")})
$Form.Controls.Add($TheAnswerBox)
$ButtonRollTheBall = New-Object System.Windows.Forms.Button
$ButtonRollTheBall.Location = New-Object System.Drawing.Size(10,40)
$ButtonRollTheBall.Size = New-Object System.Drawing.Size(130,20)
$ButtonRollTheBall.Text = "Help?!"
$ButtonRollTheBall.Add_Click({RollTheBall})
$Form.Controls.Add($ButtonRollTheBall)
$ButtonExit = New-Object System.Windows.Forms.Button
$ButtonExit.Location = New-Object System.Drawing.Size(150,40)
$ButtonExit.Size = New-Object System.Drawing.Size(130,20)
$ButtonExit.Text = "Exit"
$ButtonExit.Add_Click({$Form.Close()})
$Form.Controls.Add($ButtonExit)
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
} Finally {
Remove-Item "$env:temp\11a8093b2817a3e1ff135fec4fe01320.jpg"
Remove-Item "$env:temp\11a8093b2817a3e1ff135fec4fe01320.ico"
}
I've removed the embedded pictures due to possible copyright and shear size.
Since the Image returned from [System.Drawing.Image]::Fromfile is disposable, you have to Dispose it to clean up the ressources before you delete it:
$Image.Dispose()