I am currently stuck on a particular code in PowerShell. What I want to accomplish is when a user selects an item inside the combobox and toggle the button, this will navigate to a webpage or application based on the item the user selected in the combobox.
Here is my sample code. I tried two procedures if statement and switch. I used switch here.
here is the if statement
if ($ComboBox.SelectedItem -eq "vdi"){
$button2.Add_Click
$ie = new-object -Com "InternetExplorer.Application"
$ie.navigate2("website")
}
this is switch
$Form.ShowDialog() | out-null
$Form.FindName('autool_cmbx')
switch($ComboBox.Text) {
"vdi" {
$button2 = $Form.FindName('go_au')
$button2.Add_Click
$IE= new-object -Com "InternetExplorer.Application"
$IE.navigate2("website")
}
}
You need to tell your Add_Click function what it needs to do. In your case, it'd probably be something like:
$button2.AddClick {
$IE = New-Object -Com 'InternetExplorer.Application'
$IE.Navigate2("website")
$IE.Visible = $true
}
If that doesn't work, then more detail would be good. How are you building the GUI? What is happening when you click the button? What doesn't happen? What error messages are coming up?
EDIT: Here's an example script that does what you're asking for. You should be able to copy and paste it into a script file and run it, and it should work. Let me know how you go.
[reflection.assembly]::LoadWithPartialName("System.Drawing") | Out-Null
[reflection.assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
function Button_OnClick() {
"`$combo.SelectedItem = $($combo.SelectedItem)" | Out-GridView
if ($combo.SelectedItem -eq 'Google') {
Start-Process -FilePath 'C:\Program Files\Internet Explorer\iexplore.exe' -ArgumentList 'http://www.google.com'
} elseif ($combo.SelectedItem -eq 'Microsoft') {
$IE = New-Object -ComObject 'InternetExplorer.Application'
$IE.Navigate2('http://www.microsoft.com')
$IE.Visible = $true
}
}
$combo = New-Object -TypeName System.Windows.Forms.ComboBox
$combo.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 5, 5
$combo.Size = New-Object -TypeName System.Drawing.Point -ArgumentList 100, 25
$combo.Items.Add('Google') | Out-Null
$combo.Items.Add('Microsoft') | Out-Null
$combo.SelectedIndex = 0
$button = New-Object -TypeName System.Windows.Forms.Button
$button.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 5, 35
$button.Size = New-Object -TypeName System.Drawing.Point -ArgumentList 100, 25
$button.Text = 'Launch in IE'
$button.Add_Click({ Button_OnClick })
$form = New-Object -TypeName System.Windows.Forms.Form
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$form.Size = New-Object -TypeName System.Drawing.Point -ArgumentList 60, 105
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$form.Controls.Add($combo)
$form.Controls.Add($button)
$form.ShowDialog() | Out-Null
I made it working using Selecteditem.content which is combobox property!
$button.Add_Click({
if($ComboBox.SelectedItem.Content -eq "vpsx"){
$IE = new-object -Com "InternetExplorer.Application"
$IE.Visible = $true
$IE.navigate2("https://ctxau001mel0006.global.anz.com/Director/?
locale=en_US#HOME",0x1000)}
})
Related
How can one save and load the properties of GUI objects from a CliXml file? Saving mwe is below, with failed attempt to load commented out. directly importing changes object type from System.Windows.Forms.Button to System.Management.Automation.PSObject. Attempts to loop over the saved properties failed.
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
Remove-Variable * -ErrorAction SilentlyContinue
$form = New-Object system.Windows.Forms.Form
$form.ClientSize = New-Object System.Drawing.Point(100,100)
$form.text = "Form"
$form.TopMost = $false
$form.FormBorderStyle = "FixedSingle"
$form.MaximizeBox = $false
$TestButton = New-Object system.Windows.Forms.Button
$TestButton.text = "Test"
$TestButton.width = 85
$TestButton.height = 30
$TestButton.location = New-Object System.Drawing.Point(0,0)
$TestButton.Font = New-Object System.Drawing.Font('Microsoft Sans Serif',12)
$TestButton.Enabled = $true
$path = "./vars/test.xml"
$TestButton | Export-CliXml $path
$TestButton.Enabled = $false
#$TestButton.GetType().FullName #For comp below
#$TestButton = Import-CliXml $path #Import the saved properties - intention is that this enables button again
#$TestButton.GetType() #The import changes the type. How to load saved properties and avoid this?
$form.Controls.Add($TestButton)
[void]$form.ShowDialog()
Why not "serialize" and save it as a PowerShell expression:
{
New-Object system.Windows.Forms.Button -Property #{
text = "Test"
width = 85
height = 30
location = New-Object System.Drawing.Point(0,0)
Font = New-Object System.Drawing.Font('Microsoft Sans Serif',12)
Enabled = $true
}
} | Out-File .\Vars\Test.ps1
Note: using the outer curly brackets will validate the expression, but you might also just use (here) quotes
And then load it using dot-sourcing:
$TestButton = . .\Vars\Test.ps1
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"
I'm getting an intermittent error with this method of changing a forms text label according to the selected item in a Listview box.
Example code as below, changing the entry will intermittently give:
Cannot index into a null array.
At C:\temp\test.ps1:62 char:5
+ $SelectedPath.Text = $VMsListBox.SelectedItems.SubItems[1].Text
# Import namespaces
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Demo'
$form.Size = '580,545'
$form.StartPosition = 'CenterScreen'
$form.FormBorderStyle = 'FixedSingle'
$form.MaximizeBox = $false
# Listview box to display found open files
$VMsListBox = New-Object System.Windows.Forms.ListView
$VMsListBox.View = [System.Windows.Forms.View]::Details
$VMsListBox.Location = '15,120'
$VMsListBox.size = '435,10'
$VMsListBox.Height = 250
$VMsListBox.Columns.Add('Name') | Out-Null
$VMsListBox.Columns.Add('Path') | Out-Null
$VMsListBox.FullRowSelect = $true
$VMsListBox.MultiSelect = $false
# Selected file label
$SelectedFnameLbl = New-Object System.Windows.Forms.Label
$SelectedFnameLbl.Location = '10,25'
$SelectedFnameLbl.Size = '80,19'
$SelectedFnameLbl.Text = 'File Name:'
# Selected file name
$SelectedFname = New-Object System.Windows.Forms.Label
$SelectedFname.Location = '100,25'
$SelectedFname.Size = '300,19'
$SelectedFname.Text = 'n/a'
$SelectedFname.AutoEllipsis = $true
# Path Label
$SelectedFileLbl = New-Object System.Windows.Forms.Label
$SelectedFileLbl.Location = '10,45'
$SelectedFileLbl.Size = '80,19'
$SelectedFileLbl.Text = 'File Path:'
# Selected filepath
$SelectedPath = New-Object System.Windows.Forms.Label
$SelectedPath.Location = '100,45'
$SelectedPath.Size = '300,19'
$SelectedPath.Text = 'n/a'
$SelectedPath.AutoEllipsis = $true
$form.Controls.AddRange(#($VMsListBox,$SelectedFileLbl,$SelectedPath,$SelectedFnameLbl,$SelectedFname))
# Populate ListView
$Files = Get-ChildItem -Path 'c:\temp' -File
$Files | ForEach-Object {
$Entry = New-Object System.Windows.Forms.ListViewItem($_.Name) -ErrorAction Stop
$Entry.SubItems.Add($_.FullName) | Out-Null
$VMsListBox.Items.Add($Entry) | Out-Null
}
$VMsListBox_SelectedIndexChanged={
$SelectedFname.Text = $VMsListBox.SelectedItems.Text
$SelectedPath.Text = $VMsListBox.SelectedItems.SubItems[1].Text
Write-Host "Entry changed"
}
$VMsListBox.Add_SelectedIndexChanged($VMsListBox_SelectedIndexChanged)
# Show form
$form.ShowDialog() | Out-Null
$form.Dispose()
Can anyone point me where I'm going wrong please? Or is there a better way of doing this
Ok, I found this
Apparently retained legacy behaviour and the fix is to check for null:
$VMsListBox_SelectedIndexChanged={
If($VMsListbox.SelectedItems -ne $Null){
$SelectedFname.Text = $VMsListBox.SelectedItems.Text
$SelectedPath.Text = $VMsListBox.SelectedItems.SubItems[1].Text
Write-Host "Entry changed"
}
}
I currently have a script that queries our AD for the users' AD attribute "Department".
Right now, the script will run "successfully" but all output for Textbox2 goes to the console instead of TextBox2.
If I change my function Get-CCUsers to be a query without variables, like Get-ADUser -Filter "Department -eq 19330" (we use numbers for our departments) then the output shows in TextBox2 as I want it to.
How can I get my function to populate TextBox2?
BTW, this script was cobbled together with my limited understanding, and there may well be superfluous or nonsense lines in here.
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Howard Center Profile Migration'
$form.Size = New-Object System.Drawing.Size(800,650)
$form.StartPosition = 'CenterScreen'
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$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)
$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 enter the Cost Center # in the space below:'
$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(100,20)
$form.Controls.Add($textBox)
$RunButton = New-Object System.Windows.Forms.Button
$RunButton.Location = New-Object System.Drawing.Point(75,120)
$RunButton.Size = New-Object System.Drawing.Size(75,23)
$RunButton.Text = 'RUN'
#$RunButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
<#$RunButton.Add_Click({
#add here code triggered by the event
$TextBox2.Text = Get-Process | Format-Table -Property ProcessName, Id, CPU -AutoSize | Out-String
})
#>
$form.AcceptButton = $RunButton
$form.Controls.Add($RunButton)
$label2 = New-Object System.Windows.Forms.Label
$label2.Location = New-Object System.Drawing.Point(10,70)
$label2.Size = New-Object System.Drawing.Size(280,20)
$label2.Text = 'When you are ready click the Run button below'
$form.Controls.Add($label2)
$TextBox2 = New-Object system.windows.Forms.TextBox
$TextBox2.Text = ""
$TextBox2.Multiline = $true
$TextBox2.BackColor = "#013686"
$TextBox2.ScrollBars = "Both"
$TextBox2.Width = 750
$TextBox2.Height = 450
$TextBox2.location = new-object system.drawing.point(10,150)
$TextBox2.Font = "Microsoft Sans Serif,10"
$TextBox2.ForeColor = "#ffffff"
$Form.controls.Add($TextBox2)
$form.Topmost = $true
function Get-CCUsers {
Write-Host "The textbox text is $textbox.Text"
$dept = $textBox.Text
$deptUsers = Get-ADUser -Filter "Department -eq $dept"
ForEach ($user in $deptUsers) {
IF ( ((get-aduser $user).enabled) -eq $True ) {
$UHomeDir = (Get-ADUser $user -Properties HomeDirectory).HomeDirectory
$UProfPath = (Get-ADUser $user -Properties ProfilePath).ProfilePath
Write-Host "$user, $UHomeDir, $UProfPath"
}
}
}
$RunButton.Add_Click({
$TextBox2.Text = Get-CCUsers
})
$TextBox2.Add_TextChanged({
$TextBox2.SelectionStart = $TextBox2.Text.Length
$TextBox2.ScrollToCaret()
})
$form.Add_Shown({$Form.Update()})
$result = $form.ShowDialog()
$global:x = $textBox.Text
# $x
# if ($result -eq [System.Windows.Forms.DialogResult]::OK)
#{
#}
I have made your script working changing the 'Get-CCUSers' function
function Get-CCUsers {
Write-Host "The textbox text is $textbox.Text"
$dept = $textBox.Text
$deptUsers = Get-ADUser -Filter "Department -eq '$dept'"
$res = #()
ForEach ($user in $deptUsers) {
IF ( ((get-aduser $user).enabled) -eq $True ) {
$UHomeDir = (Get-ADUser $user -Properties HomeDirectory).HomeDirectory
$UProfPath = (Get-ADUser $user -Properties ProfilePath).ProfilePath
$res += "$user, $UHomeDir, $UProfPath"
}
}
return $res
}
In short:
I removed the Write-Host (the output was actually redirected to stdout)
I added a $res in the function initialized as array
In the ForEach loop, results are added as items in the array
The $res is returned by the function, and then used $RunButton
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