Dialog for browsing and select folders - powershell

In order to render more user-friendly my script I would like to load a dialog in which a complete folder tree (from the C:\ root) is browsable and where I could select multiple (sub)folders through check boxes. How can I accomplish such task?
P.S.: the best solution should also include hidden folders
Edit: after the evaluation of the comments and the early reply I will clarify what I am looking for. I would like to create a dialog in which the folder tree is showed, where I can expand or collapse the branches and where I can select parent folders and/or some of the children/leaves (subfolders and/or files) at the same time.

By using New-object System.Windows.Forms.OpenFileDialog and change
$FormOpenFileDialog.Multiselect = $False to True you have a File-browser that can select several folders.
$FormOpenFileDialog = New-object System.Windows.Forms.OpenFileDialog
$FormOpenFileDialog.initialDirectory = ""
$FormOpenFileDialog.Title = ""
$FormOpenFileDialog.Filter = ""
$FormOpenFileDialog.Multiselect = $True
$FormOpenFileDialog.showHelp = $true
$FormOpenFileDialog.ShowDialog()
$ApplicationForm.Controls.Add($FormOpenFileDialog)
By Adding this to a Form, binded to a button maby is the best solution ?
$ApplicationForm = New-Object System.Windows.Forms.Form
$BtnOpenFileDialog = New-object System.Windows.Forms.Button
$BtnOpenFileDialog.text= "Open Folder"
$BtnOpenFileDialog.location = "50,50"
$BtnOpenFileDialog.size = "80,20"
$BtnOpenFileDialog.Add_Click({ GenerateFormOpenFileDialog })
$ApplicationForm.Controls.Add($BtnOpenFileDialog)
function GenerateFormOpenFileDialog { # Start GenerateFormOpenFileDialog
$FormOpenFileDialog = New-object System.Windows.Forms.OpenFileDialog
$FormOpenFileDialog.InitialDirectory = ""
$FormOpenFileDialog.Title = ""
$FormOpenFileDialog.Filter = ""
$FormOpenFileDialog.Multiselect = $True
$FormOpenFileDialog.ShowHelp = $true
$FormOpenFileDialog.ShowDialog()
} # End GenerateFormOpenFileDialog
# Initlize the form
$ApplicationForm.Add_Shown({$ApplicationForm.Activate()})
[void] $ApplicationForm.ShowDialog()
Why Filebrowser and not folderbrowserdialog ?
folderbrowserdialog has more limitations.
FileBrowser
FolderBrowser
If you want to create a form, Sapians has a great forum for this.
https://www.sapien.com/
https://www.sapien.com/forums/

Related

How do I indicate that a combo box has been populated with a selection?

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#?

Check item into List box by Radio Button

I'm trying to check an item into a ListBox after clicking a Radio Button, but no success.
Specifically, I'm trying to check a Active Directory Group already listed.
I made this piece of script:
$Action = foreach ($SecurityGroup in $ADSecurityGroup)
{
$SecurityGroup.Name -eq "AD Example"
{
[void] $ADGroups.Items.Add($SecurityGroup.Name, $True)
}
}
And after added to Add_Click of Raddio Button:
$RadioButton.Add_Click($Action)
Someone could help me?
Here is an example I provide to another OP, though it's using a list box, and a comboxbox, the premise for doing this via a button in the same.
Populate ComboBox2 depending on ComboBox1 selection
Another example of Comboxbox to a list
(You could just change the combobox to whatever form element you choose) :
Add-Type -AssemblyName System.Drawing
$ComboBox = New-Object System.Windows.Forms.ComboBox
$ComboBox.Location = New-Object System.Drawing.Point(10,10)
$ComboBox.Items.AddRange(#("One","Two"))
$RichTextBox = New-Object System.Windows.Forms.RichTextBox
$RichTextBox.Location = New-Object System.Drawing.Point(10,40)
$Form = New-Object System.Windows.Forms.Form
$Form.Controls.Add($ComboBox)
$Form.Controls.Add($RichTextBox)
$ComboBox.Add_TextChanged({
# Code here
switch($ComboBox.Text){
"One" {$RichTextBox.Text = "This is one"}
"Two" {$RichTextBox.Text = "This is two"}
}
})
$Form.ShowDialog()
As for this...
Specifically, I'm trying to check an Active Directory Group already
listed.
... you just do validation before your add another item.
I achieved what I was looking for with this:
$RadioButton.Add_Click({
for ($i = 0; $i -lt $ADGroups.Items.Count; $i++)
{
If ($ADGroups.Items[$i] -match 'AD Group that I wanted to change status')
{
$ADGroups.SetItemChecked($i, $true)
}
}
})
I publish it in case it is useful to someone.
Thanks a lot!

Powershell popup to list of usernames

I wish to have a powershell script that provides a popup message to a specific list of users. I need to use a list of relevant users in a spreadsheet with their network username and not use Active Directory. I have the powershell script to display a suitable message with a Warning icon and found to format the popup in a certain way I had to use a "FORM" and not a default popup messagebox. Although the following two lines for the Warning icon would not work in the form so had to use a picture box
$WarningIcon = New-Object ([System.Windows.MessageBoxImage]::Warning)
$Form.Controls.Add($WarningIcon)
The script for the form is as follows. There is probably a cleaner way of creating a form like this but I am quite new to Powershell!
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object system.Windows.Forms.Form
$Form.Width = 700
$Form.Height = 400
$Form.BackColor = "#DCDCDC"
$Form.Text = "System Restart Alert"
$Font = New-Object System.Drawing.Font("Ariel",30,
[System.Drawing.FontStyle]::Bold::Underline)
$FontB = New-Object System.Drawing.Font("Ariel",14,
[System.Drawing.FontStyle]::Bold)
$Picture = (get-item ("C:\FA_Files\Windows_Warning_Exclamation9.jpg"))
$img = [System.Drawing.Image]::Fromfile($Picture)
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Location = New-object System.Drawing.Size(160,30)
$pictureBox.Height = "100"
$pictureBox.Image = $img
$Form.controls.add($pictureBox)
$Label = New-Object System.Windows.Forms.Label
$Label.Location = "260,30"
$Label.Font = $Font
$Label.ForeColor = "Red"
$Label.Text = "WARNING!"
$Label.AutoSize = $True
$Form.Controls.Add($Label)
$LabelB = New-Object System.Windows.Forms.Label
$LabelB.Location = "100,130"
$LabelB.Font = $FontB
$LabelB.Text = "Due to essential maintenance system requires rebooting"
$LabelB.AutoSize = $True
$Form.Controls.Add($LabelB)
$LabelC = New-Object System.Windows.Forms.Label
$LabelC.Location = "100,160"
$LabelC.Font = $FontB
$LabelC.Text = "Please save all work immediately"
$LabelC.AutoSize = $True
$Form.Controls.Add($LabelC)
$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = "300,280"
$okButton.Font = "$FontB"
$okButton.Size = "85,28"
$okButton.Text = "Okay"
$Form.Controls.Add($okButton)
$okButton.Add_Click = ({$Form.Close()})
$Form.ShowDialog()
I can retrieve a list of network usernames from the spreadsheet okay. Below is an image of the csv content
But I have googled a lot and cannot find a way of sending the popup to the list of usernames retrieved from the spreadsheet. So far I have tried the following where I have the form above set to the $msg varaiable and also tried having the form in another file and referencing that file in the $msg variable but it doesn't work
$csv = Import-csv "C:\FA_Files\NetNames.csv"
foreach($line in $csv)
{
$name = $line.("Name")
$netName = $line.("NetworkName")
#Echo "Name is $name and Network Name is $netName"
msg $netName $msg
}
It also has to be on the username and not the machine name.
How do I correct this please?
FWIW, msg.exe has replaced net /send in Windows, and is meant for sending messages to users, so I would begin by looking at the syntax for message.exe here. .
It has a /server: switch you can use to send a message to a remote host. So, take your user and computer name list and put them in a CSV file like this:
//MyInputFile.csv
ComputerName,UserName
Laptop01,BillG
Laptop02,StephenO
PC03,WayneH
Desktop04,JimA
You could use a short script like this to achieve your goal (or get you mostly there, at least 😁)
$Msg = "Put your message here"
$SpreadSheet = Import-CSV .\PathTo\MyInputFile.csv
ForEach ($row in $SpreadSheet){
"Sending message to \\$($row.ComputerName)\$($row.UserName) : $msg"
msg /server:$($row.ComputerName) $($row.UserName) $msg
}
You'll see an output like this in the console:
Sending message to \\Laptop01\BillG : Put your message here
Sending message to \\Laptop02\StephenO : Put your message here
Sending message to \\PC03\WayneH : Put your message here
Sending message to \\Desktop04\JimA : Put your message here
Sending message to \\localhost\* : Put your message here
Then your lucky user will see the following on their workstation.
If a computer can't be reached, the process will time out after five seconds or so and move on to the next one in the list.
All users that are a member of Active Directory by default receive read rights, this is by design as Active Directory is exactly the kind of system that should be relied on for the kind of functionality you desire... not sure why your ICT manager is so against the idea.
You cannot send a message to a user (with only the username), you must know the machine the user is logged into as well.
The only way I can think to achieve this is to iterate through every computer and query who is logged on and if the user matches your list then send a message to that computer. This would require reading a list of computers from AD or iterating through every available IP address on your local network(s).

Show a list when a choice is made

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.

Tray Icon Context Menu without hidden Form

I've been experimenting with tray icons & context menus in PowerShell for some time. However, i can only get the context menu to work correctly when a Form is called in the same script.
Here is a small example:
Add-Type -AssemblyName "System.Windows.Forms"
$objForm = New-Object System.Windows.Forms.Form
$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objContextMenu = New-Object System.Windows.Forms.ContextMenu
$objExitMenuItem = New-Object System.Windows.Forms.MenuItem
$objExitMenuItem.Index = 1
$objExitMenuItem.Text = "Exit"
$objExitMenuItem.add_Click({
$objForm.Close()
$objNotifyIcon.visible = $false
})
$objContextMenu.MenuItems.Add($objExitMenuItem) | Out-Null
$objNotifyIcon.Icon = "$PSScriptRoot\win.ico"
$objNotifyIcon.Text = "Context Menu"
$objNotifyIcon.ContextMenu = $objContextMenu
$objForm.ContextMenu = $objContextMenu
#Enabling Icon in Taskbar
$objNotifyIcon.Visible = $true
#Hiding Form as best as possible
$objForm.Visible = $false
$objForm.WindowState = "minimized"
$objForm.ShowInTaskbar = $false
$objForm.add_Closing({ $objForm.ShowInTaskBar = $False })
$objForm.ShowDialog()
As soon as the Form componets are removed, the Context menu wont work correctly.
Does anyone know why you need this Form to be loaded and is there a way around it?
System.Windows.Forms.ApplicationContext is what you need to use to acheive that.