Iterating over several GUI elements - powershell

I have a GUI based form with a series of fields on it and want to update the corresponding label when text is entered into one field. I've been able to get it to work using the following code
$objTextBoxRD1.add_keyup({$objLabelLU1.Text = Get-Date})
$objTextBoxRD2.add_keyup({$objLabelLU2.Text = Get-Date})
$objTextBoxRD3.add_keyup({$objLabelLU3.Text = Get-Date})
$objTextBoxRD4.add_keyup({$objLabelLU4.Text = Get-Date})
Is there a more elegant way to achieve the same result?
I tried the following but when I enter text into any $objTextBoxRD fields it only updates $objLabelU4.
$Count = 1
foreach ($User in $ISDept) {
$objTextBoxRD = Get-Variable -Name ('objTextBoxRD' + ([string]$Count)) | Select -Expand Value
$objLabelLU = Get-Variable -Name ('objLabelLU' + ([string]$Count)) | Select -Expand Value
$objTextBoxRD.add_keyup({$objLabelLU.Text = Get-Date})
$Count++
}
The $objTextBoxRD and $objLabelLU variables have been generated from arrays and would like to automate this section as the number of variables that get created can vary.

Collect your textbox elements in an array instead of using individual variables, so you can iterate over them with a for loop. Since you want to use corresponding variables in a scriptblock you probably need to generate that scriptblock, though. Try this:
for ($i=0; $i -lt $objTextBoxRD.Count; $i++) {
$sb = [scriptblock]::Create("`$objLabelLU$($i+1).Text = Get-Date")
$objTextBoxRD[$i].Add_Keyup($sb)
}

Related

Powershell Forms - retrieve both values and column names from selected ListView item

I have a working script using Powershell forms and and for convenience I'm retrieving the value from the currently selected item in a listview and copying them to clipboard as follows:
$UIDlist.Add_SelectedIndexChanged({
# Legacy Winforms behaviour can cause an error unless a null check is made
If($UIDlist.SelectedItems -ne $null) {
[string]$ClipText = $this.SelectedItems.SubItems.Text | ForEach-Object{$_ + "`r`n"}
$ClipText | Set-Clipboard
})
Obviously this only outputs the text values of the subitems e.g.
johnsmith01
johnsmith#company.com
\\myserver\johnsmith01
GPO Main Office
Is there an easy way to also get the column names for those values? e.g.
SamAccountName johnsmith01
EmailAddress johnsmith#company.com
HomeDrive \\myserver\johnsmith01
DepoartmentGPO GPO Main Office
There seems to be a Name property of ListView subiteems but I couldnt find the method to populate that when constructing the ListView:
BackColor : Color [Window]
Bounds : {X=0,Y=0,Width=0,Height=0}
Font : [Font: Name=Microsoft Sans Serif, Size=8.25, Units=3, GdiCharSet=0, GdiVerticalFont=False]
ForeColor : Color [WindowText]
Tag :
Text : johnsmith01
Name :
So is there an easy way to retrieve values and the column names for those values when selecting a ListView item?
The name of the listview item is not the column name. It is there in case you want to differentiate what you present to the user (text) and the actual value you will work it behind the scene.
To get the column name, you need to make your own solution.
Here is something that would work.
To be declared somewhere before the Add_SelectedIndexChangedMethod so it doesn't get called every time for nothing.
$ColumnsName = $ListView.Columns.Text
# Used for padded formatting
$LongestColLength = ($ColumnsName | % { $_.length } | Measure-Object -Maximum ).Maximum + 1
$ListView.Items[0].SubItems.text
And the actual $ClipText section
$ClipText = for ($i = 0; $i -lt $ColumnsName.Count ;$i++) {
"{0}: {1} `r`n" -f $ColumnsName[$i].PadRight($LongestColLength, ' '), $this.SelectedItems.SubItems[$i].Text
}
Output
Based on your code, I assumed you wanted to send it to the clipboard immediately with a pretty format but if that is not necessarily the case, I would instead produce a PSObject of what you want so that you can do additional manipulation with ease.
$ClipText = for ($i = 0; $i -lt $ColumnsName.Count ;$i++) {
[PSCustomObject]#{
ColumnName = $ColumnsName[$i]
Text = $this.SelectedItems.SubItems[$i].Text
}
}
Whenever ready, you can still convert your newly formed PSObject to its final format.
User friendly (making use of the longest column length for padding)
$ClipText | % { '{0}: {1}' -f $_.ColumnName.PadRight($LongestColLength,' '),$_.Text}
Machine friendly
$ClipText | ConvertTo-Json
Answer as in Sage's post. In my case I needed the add the following to get the clipboard formatting and output correct:
[string]$ClipText = for ($i = 0; $i -lt $ColumnsName.Count ;$i++) {
'{0}: {1}' -f $ColumnsName[$i].PadRight($LongestColLength, ' '), $this.SelectedItems.SubItems[$i].Text + "`r`n"
}
Without [string] only the last object was in the clipboard and the carriage return/newline was also required
I have PSCX module installed, which modifies the Set-Clipboard command, so YMMV

for loop through 5 textboxes

I have created a GUI with 5 Textboxes. I call them $textboxHost1 - 5.
Now I have an array in which I'm gonna save up to 5 values and then write each value according to the order into the textboxes. The first value in the array should be written into the first $textboxHost1 box.
To do that, I would like to make a for loop and have written this code
#$hostnameneingabe: Array, in which the values are saved.
$hostnameneingabeCount = $hostnameneingabe.Count
for($i = 0; $i -le $hostnameneingabeCount; $i++) {
#code here
}
Now, I'm looking for a way to go down the order, so that the first $textboxHost1 comes firstly and so on.
To be accurate, the variable $textboxHost should be incrementally increased in the loop and the values at the position $i in the array should be written into that textbox.
sth like
for($i = 0; $i -le $hostnameneingabeCount; $i++) {
$textboxHost$i =
}
I suppose you would be liking something like this?
$textboxHosts = Get-Variable | ? {$_.Name -match "textBoxHost[0-9]" -and $_.Value -ne $null} | sort Name
After this you can process that var with eg. a foreach:
foreach ($textboxHost in $textboxHosts) {<# Do some stuff #>}
You have to use an array, because otherwise you can't loop through them:
$textboxHost = #(0..4)
#Textbox 0
$textboxHost[0] = New-Object System.Windows.Forms.TextBox
$textboxHost[0].Text = "test"
#Textbox 1
$textboxHost[1] = New-Object System.Windows.Forms.TextBox
$textboxHost[1].Text = "test"
foreach ($textbox in $textboxHost){
#Do whatever you want with the textbox
$textbox =
}

Dynamic Variable & Objects

Trying to create a script that will read the contents of a directory containing a number of "paired" datasets containing customer data, for each customer there will be 2 datasets with the naming convention appearing consistently in the form: CustomerNo_DataType.csv where CustomerNo will always be numerical string value.
I've already written a crude version of this script with the customer numbers hard-coded so now I'm trying to improve on that - here's what I've got so far:
$files = Get-ChildItem "Path-to-data-files"
$files = $files.FullName
for ($i=0; $i -le $files.Count; $i++){
$thisFile = $files[$i].Split("\")
This leaves me with an array with the full pathname broken down into components so I grab the filename from the last position in the array
$thisFile = $thisFile[$thisFile.Count - 1]
...
}
I want to use the customer no to create a hashtable, so if the customer no in the filename was 12345 then I want to create a hashtable named $12345 - I'm not having any issues accessing the value, just not sure how to use it to name something.
Use Split-Path to get the file element of a path:
$file = Split-Path 'C:\path\to\some\file.txt' -Leaf
Use New-Variable if for some reason you need to define a variable name from a variable.
$customerNo = '12345'
New-Variable -Name $customerNo -Value #{}
However, I wouldn't recommend creating a bunch of dynamically named variables. It's usually a lot easier to handle if you create a "parent" hashtable for the dynamic names. You can have nested hashtables inside it if you need that:
$customerNo = '12345'
$customers = #{}
$customers[$customerNo] = #{}

Powershell array of arrays loop process

I need help with loop processing an array of arrays. I have finally figured out how to do it, and I am doing it as such...
$serverList = $1Servers,$2Servers,$3Servers,$4Servers,$5Servers
$serverList | % {
% {
Write-Host $_
}
}
I can't get it to process correctly. What I'd like to do is create a CSV from each array, and title the lists accordingly. So 1Servers.csv, 2Servers.csv, etc... The thing I can not figure out is how to get the original array name into the filename. Is there a variable that holds the list object name that can be accessed within the loop? Do I need to just do a separate single loop for each list?
You can try :
$1Servers = "Mach1","Mach2"
$2Servers = "Mach3","Mach4"
$serverList = $1Servers,$2Servers
$serverList | % {$i=0}{$i+=1;$_ | % {New-Object -Property #{"Name"=$_} -TypeName PsCustomObject} |Export-Csv "c:\temp\$($i)Servers.csv" -NoTypeInformation }
I take each list, and create new objects that I export in a CSV file. The way I create the file name is not so nice, I don't take the var name I just recreate it, so if your list is not sorted it will not work.
It would perhaps be more efficient if you store your servers in a hash table :
$1Servers = #{Name="1Servers"; Computers="Mach1","Mach2"}
$2Servers = #{Name="2Servers"; Computers="Mach3","Mach4"}
$serverList = $1Servers,$2Servers
$serverList | % {$name=$_.name;$_.computers | % {New-Object -Property #{"Name"=$_} -TypeName PsCustomObject} |Export-Csv "c:\temp\$($name).csv" -NoTypeInformation }
Much like JPBlanc's answer, I kinda have to kludge the filename... (FWIW, I can't see how you can get that out of the array itself).
I did this example w/ foreach instead of foreach-object (%). Since you have actual variable names you can address w/ foreach, it seems a little cleaner, if nothing else, and hopefully a little easier to read/maintain:
$1Servers = "apple.contoso.com","orange.contoso.com"
$2Servers = "peach.contoso.com","cherry.contoso.com"
$serverList = $1Servers,$2Servers
$counter = 1
foreach ( $list in $serverList ) {
$fileName = "{0}Servers.csv" -f $counter++
"FileName: $fileName"
foreach ( $server in $list ) {
"-- ServerName: $server"
}
}
I was able to resolve this issue myself. Because I wasn't able to get the object name through, I just changed the nature of the object. So now my server lists consist of two columns, one of which is the name of the list itself.
So...
$1Servers = += [pscustomobject] #{
Servername = $entry.Servername
Domain = $entry.Domain
}
Then...
$serverList = $usaServers,$devsubServers,$wtencServers,$wtenclvServers,$pcidevServers
Then I am able to use that second column to name the lists within my foreach loop.

Creating dynamic variable array names and then adding object to them

What I'm trying to do is create array variable names dynamically, and then with a loop, add the object to its relevant array based on the hash table value being equal to the counter variable.
$hshSite = #{} # Values like this CO,1 NE,2 IA,3
$counter = $hshSite.count
For($i = $counter; $i -gt 0; $i--) {
New-Variable -Name "arr$i" -Value #()
}
If $counter = 3, I would create arrays $arr1, $arr2, $arr3
$csv = Import-CSV....
ForEach ($x in $csv) {
#if $hshSite.Name = $x.location (ie CO), look up hash value (1),
and add the object to $arr1. If $hshSite.Name = NE, add to $arr2
I tried creating the dynamic arrays with New-Variable, but having issues trying to add to those arrays. Is it possible to concatenate 2 variables names into a single variable name? So taking $arr + $i to form $arr1 and $arr2 and $arr3, and then I can essentially just do $arr0 += $_
The end goal is to group things based on CO, NE, IA for further sorting/grouping/processing. And I'm open to other ideas of getting this accomplished. Thanks for your help!
Just make your hash table values the arrays, and accumulate the values to them directly:
$Sites = 'CO','NE','IA'
$hshSite = #{}
Foreach ($Site in $Sites){$hshSite[$Site] = #()}
ForEach ($x in $csv)
{
$hshSite[$x.location] += <whatever it is your adding>
}
If there's a lot of entries in the csv, you might consider creating those values as arraylists instead of arrays.
$Sites = 'CO','NE','IA'
$hshSite = #{}
Foreach ($Site in $Sites){ $hshSite[$Site] = New-Object Collections.Arraylist }
ForEach ($x in $csv)
{
$hshSite[$x.location].add('<whatever it is your adding>') > $nul
}
You could quite easily do add items to a dynamically named array variable using the Get-Variable cmdlet. Similar to the following:
$MyArrayVariable123 = #()
$VariableNamePrefix = "MyArrayVariable"
$VariableNameNumber = "123"
$DynamicallyRetrievedVariable = Get-Variable -Name ($VariableNamePrefix + $VariableNameNumber)
$DynamicallyRetrievedVariable.Value += "added item"
After running the above code the $MyArrayVariable123 variable would be an array holding the single string added item.