I hope there i can get an answer for this quick. Im populating a list box based on radio button being selected. I want the list box to highlight the row automatically so that when i click the button the relevant action can happen based on the selection. In this case it will be a sql server instance. See extract of code for adding it to ListBox1.
ForEach ($Server in $Servers)
{
#$NL = "`r`n"
[void] $ListBox1.Items.Add($Server)
#$ListBox1.Items.selectedItem
}
Example:
$form = New-Object System.Windows.Forms.Form
$listbox = New-Object System.Windows.Forms.ListBox
$listbox.SelectionMode = "MultiSimple"
$listbox.Items.Add("item1") | Out-Null
$listbox.Items.Add("item2") | Out-Null
$listbox.Items.Add("item3") | Out-Null
$listbox.Items.Add("item4") | Out-Null
for($i = 0; $i -lt $listbox.Items.Count; $i++) {
$listbox.SetSelected($i, $true)
}
$form.Controls.Add($listbox)
$form.ShowDialog()
Related
maybe one of you experts can help a complete newbie (I don't know if what I want is even feasible).
Let's assume I have a CSV file with various data. (see csv_screenshot)csv_screenshot
I import this data via Powershell into a small GUI . How can I make it so that when I search for "Paris", I really only get the output for Paris in the GUI as a list view like this (see powershell_screenshot)
powershell_screenshot
Currently the output in the GUI looks like this (see current_result.png). How do I get it nicely formatted as a list in there. I really want to insert it like this (via Out Grid View it is no problem)
current_result.png
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles();
function search_csv {
$Input = $textbox_Search.text
$Input = "*$Input*"
$Input_Result = import-csv -path C:\Users\check.csv -Header "Location", "Client", "Mobile Device"
$output_TextBox.text = $Input_Result -like $Input
}
$search_csvtool = New-Object System.Windows.Forms.Form
$search_csvtool.Text = "CSV Search"
$search_csvtool.Size = New-Object System.Drawing.Size(674,500)
$search_csvtool.FormBorderStyle ="FixedDialog"
$search_csvtool.TopMost = $true
$search_csvtool.MaximizeBox = $false
$search_csvtool.MinimizeBox = $true
$search_csvtool.ControlBox = $true
$search_csvtool.StartPosition = "CenterScreen"
$search_csvtool.Font = "Courier New"
$label_Search = New-Object System.Windows.Forms.Label
$label_Search.Location = New-Object System.Drawing.Size(195,18)
$label_Search.Size = New-Object System.Drawing.Size(265,32)
$label_Search.TextAlign ="MiddleCenter"
$label_Search.Text = "Please enter "
$search_csvtool.Controls.Add($label_Search)
$textbox_Search = New-Object System.Windows.Forms.TextBox
$textbox_Search.Location = New-Object System.Drawing.Size(195,50)
$textbox_Search.Size = New-Object System.Drawing.Size(266,37)
$search_csvtool.Controls.Add($textbox_Search)
$button_Search = New-Object System.Windows.Forms.Button
$button_Search.Location = New-Object System.Drawing.Size(195,80)
$button_Search.Size = New-Object System.Drawing.Size(266,24)
$button_Search.TextAlign = "MiddleCenter"
$button_Search.Text = "Search"
$button_Search.Add_Click({search_csv})
$search_csvtool.Controls.Add($button_Search)
$output_TextBox = New-Object System.Windows.Forms.TextBox
$output_TextBox.Multiline = $true;
$output_TextBox.Location = New-Object System.Drawing.Size(16,130)
$output_TextBox.Size = New-Object System.Drawing.Size(627,314)
$output_TextBox.ScrollBars = "Vertical"
$output_TextBox.ReadOnly = $true;
$search_csvtool.Controls.Add($output_TextBox)
$search_csvtool.Add_Shown({$search_csvtool.Activate()})
[void] $search_csvtool.ShowDialog()
Ok, so here's what I meant in my comment:
Start the code with
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$csvData = Import-Csv -path 'C:\Users\check.csv' -Header "Location", "Client", "Mobile Device"
function search_csv {
$searchThis = $textbox_Search.Text.Trim()
# use $script: scoping here to reference the $csvData variable
$data = $script:csvData | Where-Object {$_.Location -like "*$searchThis*"}
if ($data) {
$output_TextBox.Text = ($data | Format-List | Out-String).Trim()
}
else {
$output_TextBox.Text = "Not found.."
}
}
Then create the rest of the form as you did.
Important: Destroy the form when done with a last new code line:
$search_csvtool.Dispose()
You should then have this result:
As per your comment to empty the textbox when nothing (or just whitespace) has been entered, you could change the function to:
function search_csv {
$searchThis = $textbox_Search.Text.Trim()
# use $script: scoping here to reference the $csvData variable
$data = $script:csvData | Where-Object {$_.Location -like "*$searchThis*"}
if ([string]::IsNullOrWhiteSpace($searchThis)) {
$output_TextBox.Clear()
}
elseif ($data) {
$output_TextBox.Text = ($data | Format-List | Out-String).Trim()
}
else {
$output_TextBox.Text = "Not found.."
}
}
However, as postanote already commented, it would be much better to simply disable the search button and only enable it when something other that whitespace has been entered.
To do that, you need to add an eventhandler to the textbox:
$textbox_Search = New-Object System.Windows.Forms.TextBox
$textbox_Search.Location = New-Object System.Drawing.Size(195,50)
$textbox_Search.Size = New-Object System.Drawing.Size(266,37)
$textbox_Search.Add_TextChanged({
# enable the button when there is at least one non-whitespace character present
$button_Search.Enabled = $this.Text -match '\S'
# or use
# $button_Search.Enabled = (-not [string]::IsNullOrWhiteSpace($this.Text))
})
$search_csvtool.Controls.Add($textbox_Search)
And initialize the button to be disabled at startup:
$button_Search = New-Object System.Windows.Forms.Button
$button_Search.Location = New-Object System.Drawing.Size(195,80)
$button_Search.Size = New-Object System.Drawing.Size(266,24)
$button_Search.TextAlign = "MiddleCenter"
$button_Search.Text = "Search"
# initialize to Disabled; will be enabled as soon as there is text entered in the $textbox_Search
$button_Search.Enabled = $false
$button_Search.Add_Click({search_csv})
$search_csvtool.Controls.Add($button_Search)
Inside an event handler, you can refer to the object itself using automatic variable $this
You should be able to go thru your string output line by line and change this.
That stated, you probably won't like how it looks. Normalized colons will probably look better.
This code should do the trick. I'll let you be the judge of if it looks "better"
$dataLines = ($data | Format-List | Out-String).Trim() -split '(?>\r\n|\n)'
$dataText = #(
foreach ($dataLine in $dataLines) {
$dataLine -replace '\s{1,}\:', ':'
}
) -join [Environment]::Newline
$output_TextBox.Text = $dataText
I am tring to create a script that will output the name of .txt files via for loop that counts the number of files and creates an option to open .txt file from just one click.
$s = (Get-ChildItem -Path C:\*.txt -Name | Measure-Object -Line).Lines
for($i=0; $1 -gt 5 ;$i++)
{
$c = [string[]](Get-ChildItem -Path C:\*.txt -Name)
[void] $objListBox.Items.Add('$i')
Write-Output $c
}
I am stuck with Get-childitem like in $c to get the list of file names into a variable so i can split or get the line for user option.
Thanks in advance
i am not sure what exactly you want from the script,
but here is my approach to set the items in $objListBox
$txtFiles=Get-ChildItem -Path C:\stackoverflow -Recurse -Filter *.txt
#Option 1 FullPath to Items
$txtFiles.fullname | ForEach-Object { $objListBox.Items.Add($_) }
#Option 2 Just the Name to Items
$txtFiles.name | ForEach-Object { $objListBox.Items.Add($_) }
#Option 3 Just the Name without Extentension to Items
$txtFiles.basename | ForEach-Object { $objListBox.Items.Add($_) }
#Count for All Files
$txtFiles.Count
You can use the .ToString
method to convert any given object to a string. If you want $c to be a string, the code you are looking for would look something like this:
$c = (Get-ChildItem -Path C:\*.txt -Name).ToString
Made a form for you that is created with a dynamic size and additionally a scrollbar if there is no space left. buttons that start the txt file and close the form. More comments in the code.
$basePath = "C:\"
$SearchString = Join-Path $basePath "*.txt"
$filenames = #(Get-ChildItem -Path $SearchString -Name | Sort)
$count = $filenames.count
#All you need for System.Windows.Forms to work
Add-Type -AssemblyName System.Windows.Forms
# Variables for generating size
$ButtonHeight = 35
$ButtonWidth = 450
$WindowTitle = "Choose a file"
$BottomSpace = $StartHeight = 10
$LeftSpace = $RightSpace = 30
$CurrentHeight = $Startheight
$FormHeight = 60 + $BottomSpace + $StartHeight + $ButtonHeight * $count
$FormWidth = 20 + $LeftSpace + $RightSpace + $ButtonWidth
# Create the form
$form = New-Object System.Windows.Forms.Form
$form.Text = $WindowTitle
$form.Size = New-Object System.Drawing.Size($FormWidth,$FormHeight)
$form.FormBorderStyle = "Fixed3d" # Sizeable: User may change size - Fixed3d: User may not change size
$form.StartPosition = "CenterScreen"
$Form.AutoScroll = $True # Scrollbars when you need it
$form.Topmost = $true #always on top
$form.MaximizeBox = $false #Allows to maximize window
# Generate the buttons in a foreach and arrange them
foreach ($filename in $filenames) {
$GeneratedButton = New-Object System.Windows.Forms.Button
$GeneratedButton.Location = New-Object System.Drawing.Size($LeftSpace,$CurrentHeight)
$GeneratedButton.Size = New-Object System.Drawing.Size($ButtonWidth,$ButtonHeight)
$GeneratedButton.Text = $filename
# Action to take when button is clicked -- Open file and close form
$GeneratedButton.Add_Click({ Start-Process (Join-Path $BasePath $this.text) ; $form.Close() })
$form.Controls.Add($GeneratedButton)
$CurrentHeight += $ButtonHeight
}
# Activate the Form when loaded
$form.Add_Load({
$form.Activate()
})
# Show the form when loaded, but hide any results
$form.ShowDialog() > $null # Trash any output
I hope someone can help me understand what I am doing wrong.
The script works, if I enter multiple computers or multiple lines, but if I only enter 1 line (1 value). Lets say: Computer 201... the result will be 1
I have disabled the PING feature for now until I can figure out why it does not work with 1 line.
I added the whole code so you can test it yourself.
Thank you
# Load required assemblies
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
# Drawing form and controls
$Harvester = New-Object System.Windows.Forms.Form
$Harvester.Text = "Ping Computers"
$Harvester.Size = New-Object System.Drawing.Size(490,300)
$Harvester.FormBorderStyle = "FixedDialog"
$Harvester.TopMost = $true
$Harvester.MaximizeBox = $false
$Harvester.MinimizeBox = $false
$Harvester.ControlBox = $true
$Harvester.StartPosition = "CenterScreen"
$Harvester.Font = "Segoe UI"
#======================== INPUTBOX - Computers ========================#
$label_message2 = New-Object System.Windows.Forms.Label
$label_message2.Location = New-Object System.Drawing.Size(20,10)
$label_message2.Size = New-Object System.Drawing.Size(100,15)
$label_message2.Text = "Computers"
$Harvester.Controls.Add($label_message2)
# Inputbox
$Inputbox = New-Object System.Windows.Forms.TextBox
$Inputbox.Multiline = $True;
$Inputbox.Location = New-Object System.Drawing.Size(20,30)
$Inputbox.Size = New-Object System.Drawing.Size(200,150)
$Inputbox.ScrollBars = "Vertical"
$Harvester.Controls.Add($Inputbox)
#======================== INPUTBOX - Completed ========================#
$label_message_success = New-Object System.Windows.Forms.Label
$label_message_success.Location = New-Object System.Drawing.Size(250,10)
$label_message_success.Size = New-Object System.Drawing.Size(100,15)
$label_message_success.Text = "Successful"
$Harvester.Controls.Add($label_message_success)
# Inputbox
$Inputbox_success = New-Object System.Windows.Forms.TextBox
$Inputbox_success.Multiline = $True;
$Inputbox_success.Location = New-Object System.Drawing.Size(250,30)
$Inputbox_success.Size = New-Object System.Drawing.Size(200,150)
$Inputbox_success.ScrollBars = "Vertical"
$Harvester.Controls.Add($Inputbox_success)
#======================== Ping ========================#
$button_Ping = New-Object System.Windows.Forms.Button
$button_Ping.Location = New-Object System.Drawing.Size(120,200)
$button_Ping.Size = New-Object System.Drawing.Size(80,32)
$button_Ping.TextAlign = "MiddleCenter"
$button_Ping.Text = "Ping"
$button_Ping.Add_Click({
If ($Inputbox.TextLength -eq 0){
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show('Please enter at 1 computer to perform this action')
Return
}
[collections.arraylist] $ref = #(($Inputbox.Text -split '\r?\n').Trim() -ne '')
if(-not $ref) { return } # if the textbox is empty, don't do anything
$i = 0
1..$ref.Count | ForEach-Object {
#if(Test-Connection $ref[$i] -Quiet) {
$Inputbox_success.Text += $ref[$i] + [environment]::NewLine
$ref.RemoveAt($i)
#}
$Inputbox.Text = $ref | Out-String
$Inputbox, $Inputbox_success | ForEach-Object Refresh
}
})
$Harvester.Controls.Add($button_Ping)
# show form
$Harvester.Add_Shown({$Harvester.Activate()})
[void] $Harvester.ShowDialog()
On a single object you get a value of 1 because of this line:
[collections.arraylist] $ref = #(($Inputbox.Text -split '\r?\n').Trim() -ne '')
More specifically because when a string is evaluated against -ne '' it will return $true or $false, but when you pass an array to that it will instead output all results where that evaluated as true. The way to fix this is to force it to be an array every time. That can be done like this:
[collections.arraylist] $ref = [string[]]($Inputbox.Text -split '\r?\n') -ne ''
That fixes that, but it still leaves other issues, or, at least one other issue I see. You set $i to 0, then loop through things starting at 1, but always reference $i, which will always evaluate to 0, and effectively manipulate item 0 in the $ref array for each thing you evaluate against. So if your If statement succeeds on 3 out of 6 things it will always move the first 3 things over, regardless of what succeeds. To resolve that I changed your code as little as I could, but ended up with this:
0..($ref.Count -1) | ForEach-Object {
# if(Test-Connection $ref[$i] -Quiet) {
if($ref[$_][-1]%2){
$Inputbox_success.Text += $ref[$_] + [environment]::NewLine
}
}
$Inputbox.Text = $ref |Where{$Inputbox_success.Text -notmatch ([regex]::Escape($_))}| Out-String
$Inputbox, $Inputbox_success | ForEach-Object Refresh
So rather than remove things from the array, I rather copy the successes to the $Inputbox_success box, and then rebuild $Inputbox based on the items that are not present in $Inputbox_success at the end. Now, I just set $Inputbox.text to be this:
$Inputbox.Text = #'
Computer201
Computer202
Computer203
Computer204
Computer206
Computer207
'#
And evaluated which name ended in an odd number, but you can comment out my If statement, and re-implement your own to make it actually ping things and go off that.
I've managed to get all attachment from a mail and save it to a location.
Now i am trying to to drag and drop it to a listbox.
Now it gets all the attachements, but i want only the selecte on in the outlook message.
$outlook = New-Object -comobject outlook.application
$sel=$outlook.ActiveExplorer().selection
foreach ($s in $sel) {
foreach ($at in $s.Attachments)
{if ($at.FileName -match 'SCAN_*')
{$newname=[io.path]::ChangeExtension($Filesgo_listbox.SelectedItem,"PDF")
if ($newname -NOTmatch "20*") {$newname= $DATUM + " " + $newname}
$name= join-path $curfil $newname }
else {$name=join-path $curfil $at.FileName}
Continuing from my comment.
'PowerShell Drag & Drop files' winform
# Example 1
Function DragDropSample()
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$form.text = "Drag&Drop sample"
$listBox = New-Object Windows.Forms.ListBox
$listBox.Dock = [System.Windows.Forms.DockStyle]::Fill
$handler = {
if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) {
foreach ($filename in $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)) {
$listBox.Items.Add($filename)
}
}
}
$form.AllowDrop = $true
$form.Add_DragEnter($handler)
$form.Controls.Add($listBox)
$form.ShowDialog()
}
DragDropSample | Out-Null
Similar Q&A right here on SP:
PowerShell - DataGridView Windows Form Drag and Drop Issue
I have a full script which works just fine. The issue is, I have a system of GUI's set up which are all used for varying roles and what I need is a select all function on one of these GUI's. For example;
###############################MONTH SELECTER############################################################
[array]$DropDownArrayItems = "","01","02","03","04","05","06","07","08","09","10","11","12", 'Select all months'
[array]$DropDownArray = $DropDownArrayItems | sort
function Return-DropDown {
if ($DropDown.SelectedItem -eq $null){
$DropDown.SelectedItem = $DropDown.Items[0]
$script:Choice = $DropDown.SelectedItem.ToString()
$Form.Close()
}
else{
$script:Choice = $DropDown.SelectedItem.ToString()
$Form.Close()
}
}
function SelectGroup{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$Form = New-Object System.Windows.Forms.Form
$Form.width = 300
$Form.height = 150
$Form.Text = ”Select Filter Month”
$DropDown = new-object System.Windows.Forms.ComboBox
$DropDown.Location = new-object System.Drawing.Size(100,10)
$DropDown.Size = new-object System.Drawing.Size(130,30)
ForEach ($Item in $DropDownArray) {
[void] $DropDown.Items.Add($Item)
}
$Form.Controls.Add($DropDown)
$DropDownLabel = new-object System.Windows.Forms.Label
$DropDownLabel.Location = new-object System.Drawing.Size(10,10)
$DropDownLabel.size = new-object System.Drawing.Size(100,40)
$DropDownLabel.Text = "Select Month:"
$Form.Controls.Add($DropDownLabel)
$Button = new-object System.Windows.Forms.Button
$Button.Location = new-object System.Drawing.Size(100,50)
$Button.Size = new-object System.Drawing.Size(100,20)
$Button.Text = "OK"
$Button.Add_Click({Return-DropDown})
$form.Controls.Add($Button)
$form.ControlBox = $false
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
return $script:choice
}
$Group = $null
$Group = SelectGroup
while ($Group -like ""){
$Group = SelectGroup
}
###################################################################################
This selects a month and is used in things like file paths and filters the problem is, if someone wants data from every month, they have to manually repeat the script 12 times and answer all the GUI'S again.
I've tried;
if ($Group -eq 'Select all') {
1..12 | ForEach-Object { '{0:00}' -f $_ }
}
But the file path gets confused and things break so including a select all function and taking numbers 1-12 doesn't quite work.
So is there a way to loop the entire script such that with each pass through it selects a different month whilst keeping all other variables in the script the same if the 'select all months option is selected'
I don't think the problem that you're having is in the code you posted.
The easiest thing to do would be to take all the code past the Select Group, and move it into it's own function.
function DoWork { params ([int]$Month)
$Month = '{0:00}' -f $Month
Echo $Month
#Do your work- this is where you code past the UI goes
}
#This is where your drop down labels, etc goes.
if ($Group -eq 'Select All') {
1..12 | ForEach-Object {DoWork($_)}
} else {
DoWork($Group)
}
This will call your DoWork (or whatever you name it) function 12 times, each with a different $Month, if Select All is used.
Depending on variable scope- if your first run through changes a variable, your second run through might start with that changed variable. I'm worried that might be where "they file path gets confused" might be coming from.
If so, look at how you change the $Path variable- or whatever it is.