PowerShell and XAML data binding - wpf

I'm trying to get a list of users searching by a surname property and list them in the ListView.
Here's XAML code:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="Find users with SamAccountName"
Width="525"
Background="#FF262626"
ResizeMode="NoResize"
SizeToContent="Height">
<StackPanel Margin="5,5,5,5" Orientation="Vertical">
<Grid
Name="Grid"
Width="400"
Height="200"
Background="#313130">
<Label
Name="Label"
Content="Select employee"
FontSize="12"
Foreground="White" />
<ListView
Name="ListView"
Margin="0,25,0,0"
Background="Transparent"
BorderBrush="Transparent"
Foreground="White"
IsHitTestVisible="False"
SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn
Width="100"
DisplayMemberBinding="{Binding Path=Logon}"
Header="Logon" />
<GridViewColumn
Width="150"
DisplayMemberBinding="{Binding Path=FirstName}"
Header="First name" />
<GridViewColumn
Width="150"
DisplayMemberBinding="{Binding Path=LastName}"
Header="Last name" />
</GridView>
</ListView.View>
</ListView>
</Grid>
<StackPanel HorizontalAlignment="Right">
<Button Width="50" Content="SAVE" />
</StackPanel>
</StackPanel>
And it looks like this:
XAML look
I believe I cannot do it without data-binding and I saw a lot of posts about them but I couldn't understand it completely.
For now in powershell I have:
Add-Type -AssemblyName PresentationFramework
$employees = Get-ADUser -Filter {Surname -like "surname"}
$itemSource = #()
ForEach ($employee in ($employees | Sort-Object SamAccountName)) {
$itemSource += [PSCustomObject]# {
Logon = $employee.Name
FirstName = $employee.GivenName
LastName = $employee.Surname
}
$columnOrder = 'Logon', 'FirstName', 'LastName'
[XML]$Form = Get-Content "xmlPath"
$NR = (New-Object System.Xml.XmlNodeReader $Form)
$Win = [Windows.Markup.XamlReader]::Load($NR)
$Win.ShowDialog()
Now, the ForEach is working perfectly fine and returning exactly what I need but cannot find any way to put it into ViewList.
Then I'll need to save the selected user into a variable that I'll display later in the textbox.
Sorry if it's a stupid/easy question but I just started learning PowerShell to help me automate my work.

In the loaded form, you have to specify the ListView's ItemsSource
in PowerShell, you can do it like this
Add-Type -AssemblyName PresentationFramework
$employees = Get-ADUser -Filter {Surname -like "surname"}
$itemSource = #()
ForEach ($employee in $($employees | Sort-Object SamAccountName)) {
$itemSource += [PSCustomObject]#{
Logon = $employee.Name
FirstName = $employee.GivenName
LastName = $employee.Surname
}
}
[XML]$Form = (Get-Content "C:\temp\test.xaml")
$NR = (New-Object System.Xml.XmlNodeReader $Form)
$Win = [Windows.Markup.XamlReader]::Load($NR)
# this part
($win.FindName("ListView")).ItemsSource = $itemSource
$Win.ShowDialog()

Related

WPF/PowerShell, copy single cell from a datagrid without header

In a WPF DataGrid via PowerShell, I would like the user to be able to copy the cells as follows: 1) if multiple cells and rows are selected selected then copy it with header. 2) If only a single cell is selected copy the cell content without the header. In the sample shown below, I've set ClipboardCopyMode="IncludeHeader" which enables to copy the selected cells/rows with header which satisfies first requirement indicated above. However, I'm looking for some ideas or quick samples for the second requirement shown above, that is to copy the content without header if only single cell is selected (from context menu or shortcut). I had tried mouse events but couldn't get it to work. Thanks in advance.
[xml]$xaml=#"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
Title="MainWindow" Height="425" Width="550">
<Grid>
<TextBox x:Name="tb_Search" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="149"/>
<Button x:Name="bt_Search" Content="Search" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" IsDefault="True" Height="22" Margin="165,10,0,0" />
<DataGrid x:Name="dg" Margin="10,45,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="100" Height="Auto" Width="Auto" ColumnWidth="Auto" AlternationCount="1" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell" Background="White" ClipboardCopyMode="IncludeHeader">
<DataGrid.ContextMenu>
<ContextMenu >
<MenuItem Command="{x:Static ApplicationCommands.Copy}" Header="Copy With Header"/>
<MenuItem Command="{x:Static ApplicationCommands.Save}" Header="Save"/>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($reader)
#Turn XAML into PowerShell objects
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'x:Name')]]") | ForEach-Object{
Set-Variable -Name ($_.Name) -Value $Window.FindName($_.Name)
}
#sample data
$DataSet = New-Object System.Data.DataSet
$Table = $DataSet.Tables.Add("Table")
$Properties = #("Country","Capital","Population")
$Properties | foreach {
$Column = New-Object System.Data.DataColumn($_)
$Table.Columns.Add($Column)
}
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
#populate datagrid
$DataView = New-Object System.Data.DataView($Table)
$array = New-Object System.Collections.ArrayList
[void] $array.AddRange($DataView)
$dg.clear()
$dg.ItemsSource = $array
$dg.IsReadOnly = $true
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
for ($i = 0; $i -lt $dg.Items.Count; $i++)
{
if ($dg.Items[$i].Row[$dg.Columns.DisplayIndex] -eq "$SearchValue")
{
[System.Windows.Forms.MessageBox]::Show("Keyword Found")
$dg.ScrollIntoView($dg.Items[$i]) #scroll to the row that contains the keyword searched
}
}
})
#Display Form
$Window.ShowDialog() | Out-Null
You could dynamically set the ClipboardCopyMode in the CanExcecute method of the ApplicationCommands.Copy command. This is how you would do this in C#:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
DataGrid dataGrid = (DataGrid)sender;
dataGrid.ClipboardCopyMode = dataGrid.SelectedCells.Count == 1 ?
DataGridClipboardCopyMode.ExcludeHeader : DataGridClipboardCopyMode.IncludeHeader;
}
XAML:
<DataGrid ... SelectionMode="Extended" SelectionUnit="Cell" ClipboardCopyMode="IncludeHeader">
<DataGrid.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.Copy}" CanExecute="CommandBinding_CanExecute"/>
</DataGrid.CommandBindings>
</DataGrid>

PowerShell WPF - Binding DataGrid ComboBox to Column In ItemsSource

I am trying to populate a ComboBox within a DataGrid with unique values from a given column, however I'm getting unexpected results in that it splits the value from that row into individual characters and populates each ComboBox with said characters.
Here's a simple example script of my issue;
$csv = "ID,Fruit,Owner`r`n"
$csv += "1,Apple,Andrew`r`n"
$csv += "2,Banana,Bill`r`n"
$csv += "3,Cherry,Charles`r`n"
$csv += "4,Date,Daniel`r`n"
$csv += "5,Elderberry,Ethan`r`n"
$data = ConvertFrom-Csv $csv
$inputXML = #"
<Window x:Name="DataGridComboTest" x:Class="DataGridComboTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataGridComboTest" Width="640" Height="480" WindowStartupLocation="CenterScreen">
<Grid>
<DataGrid x:Name="DataGrid" Margin="10,10,10,10" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding Fruit}" Header="Fruit"/>
<DataGridTextColumn Binding="{Binding Owner}" Header="Owner"/>
<DataGridTemplateColumn Header="Owner Combo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
SelectedItem="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Owner}"
Text="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
"#
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[#Name]") | %{ Set-Variable -Name "$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop }
$DataGrid.ItemsSource = $data
$Form.ShowDialog() | Out-Null
What I'd like to be able to do is select a different owner for each fruit from the existing owners in the table, however instead I'm given a choice of each letter in the adjacent owner's name;
You should bind the ItemsSource to an IEnumerable<string> rather than a scalar string (which is an IEnumerable<char>).
Try something like this:
...
ItemsSource="{DynamicResource owners}"
...
$owners = $data | Select-Object -ExpandProperty Owner -Unique
$Form.Resources.Add("owners", $owners)
With mm8's help I was able to come up with a working script;
$csv = "ID,Fruit,Owner`r`n"
$csv += "1,Apple,Andrew`r`n"
$csv += "2,Banana,Bill`r`n"
$csv += "3,Cherry,Charles`r`n"
$csv += "4,Date,Daniel`r`n"
$csv += "5,Elderberry,Ethan`r`n"
$csv += "6,Fig,Bill`r`n"
$csv += "7,Grape,Daniel`r`n"
$data = ConvertFrom-Csv $csv
$inputXML = #"
<Window x:Name="DataGridComboTest" x:Class="DataGridComboTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataGridComboTest" Width="640" Height="480" WindowStartupLocation="CenterScreen">
<Grid>
<DataGrid x:Name="DataGrid" Margin="10,10,10,10" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding Fruit}" Header="Fruit"/>
<DataGridTextColumn Binding="{Binding Owner}" Header="Owner"/>
<DataGridTemplateColumn Header="Owner Combo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
SelectedItem="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{DynamicResource owners}"
Text="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
"#
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[#Name]") | %{ Set-Variable -Name "$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop }
$DataGrid.ItemsSource = $data
#$owners = [Linq.Enumerable]::ToArray($data | Select-Object -ExpandProperty Owner)
$owners = $data | Select-Object -ExpandProperty Owner -Unique
$Form.Resources.Add("owners", $owners)
$Form.ShowDialog() | Out-Null
The DynamicResource binding was key, but the [Linq.Enumerable] line from mm8's answer threw an error. However simplifying it to select unique owners from $data resolved this. I also added a couple of duplicate owners to the source data to more accurately simulate a real-world scenario, hence "-Unique".

WPF and Powershell: Mirroring/Syncing text boxes

I have two text boxes. I would like to mirror the first text box to the second text box, but if you manually update the second box after the text has been mirrored, it should stay as that regardless of if you update the first text box again.
<TextBox x:Name="TextBoxUserLogonNameUPN" HorizontalAlignment="Left" Height="23" Margin="10,41,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="300"/>
<TextBox x:Name="TextBoxUserLogonNameSamAccountName" HorizontalAlignment="Left" Height="23" Margin="326,100,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="310" Text="{Binding Path=Text, ElementName=TextBoxUserLogonNameUPN, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
I have tried the above but with Mode=OneWay in the Binding. If I update the first text box a second time, after manually updating the second, it wipes what was in the second and mirrors again.
I am using WPF with PowerShell. I am happy to manage this by the Powershell if it can't be done in Xaml.
Assuming that textbox1 losing focus is the event that should copy textbox1 text to textbox2, this code should work for you. All the action is in the function textBox1_LostFocus. The first time through, simply set the textbox2Tagproperty to a value that you test for second and subsequent times through
Note: The form has two labels and two text boxes
WpfWindow1.xaml.ps1 is the entry point for this program
WpfWindow1.xaml.ps1
function Add-ControlVariables {
New-Variable -Name 'textBox1' -Value $window.FindName('textBox1') -Scope 1 -Force
New-Variable -Name 'textBox2' -Value $window.FindName('textBox2') -Scope 1 -Force
}
function Load-Xaml {
[xml]$xaml = Get-Content -Path $PSScriptRoot\WpfWindow1.xaml
$manager = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xaml.NameTable
$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
$xaml.SelectNodes("//*[#x:Name='textBox1']", $manager)[0].RemoveAttribute('TextChanged')
$xaml.SelectNodes("//*[#x:Name='textBox2']", $manager)[0].RemoveAttribute('TextChanged')
$xaml.SelectNodes("//*[#x:Name='textBox1']", $manager)[0].RemoveAttribute('LostFocus')
$xamlReader = New-Object System.Xml.XmlNodeReader $xaml
[Windows.Markup.XamlReader]::Load($xamlReader)
}
function Set-EventHandlers {
$textBox1.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox1_TextChanged($sender,$e)
})
$textBox2.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
$textBox1.add_LostFocus({
param([System.Object]$sender,[System.Windows.RoutedEventArgs]$e)
textBox1_LostFocus($sender,$e)
})
}
$window = Load-Xaml
Add-ControlVariables
Set-EventHandlers
function textBox1_TextChanged
{
param($sender, $e)
#do stuff you want to do when textBox1.Text changes
}
function textBox2_TextChanged
{
param($sender, $e)
#do stuff you want to do when textBox2.Text changes
}
function textBox1_LostFocus
{
param($sender, $e)
if ($textBox2.Tag -ne "mirrored")
{
#turn off textBox2 TextChanged event so that code in textBox2_TextChanged is not executed
$textBox2.remove_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
$textBox2.Text = $sender.Text
$textBox2.Tag = "mirrored"
#turn textBox2 TextChanged event back on
$textBox2.add_TextChanged({
param([System.Object]$sender,[System.Windows.Controls.TextChangedEventArgs]$e)
textBox2_TextChanged($sender,$e)
})
}
}
$window.ShowDialog()
WpfWindow1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="29" Margin="79,45,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="132" TextChanged="textBox1_TextChanged" LostFocus="textBox1_LostFocus"/>
<TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="29" Margin="298,45,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="105" TextChanged="textBox2_TextChanged"/>
<Label Content="Text1:" HorizontalAlignment="Left" Height="25" Margin="32,45,0,0" VerticalAlignment="Top" Width="63"/>
<Label Content="Text2:" HorizontalAlignment="Left" Height="25" Margin="242,45,0,0" VerticalAlignment="Top" Width="56"/>
</Grid>
</Window>

Powershell ListView using WPF - Items not showing properly

Im trying to output into two columns the result of the following query:
get-mailbox -identity *#$SearchDomain | where ismailboxenabled -eq true
Here is what i've done right now:
$mailboxes = get-mailbox -identity *#$SearchDomain | where ismailboxenabled -eq true
foreach($line in $mailboxes){
$new = new-object System.Windows.Forms.ListViewItem($line.Name)
$new.SubItems.Add($line.Alias + "#" + $SearchDomain)
$WPFLstActiveMailboxes.Items.Add($new)
}
My problem is that things are showing up like this in my GUI:
Behind the black boxes is the data that I want
EDIT 1:
$inputXML = #"
<Window x:Name="TMS_MailboxToolkit" x:Class="TMS_MailboxToolki.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TMS"
mc:Ignorable="d"
Title="TMS - Mailbox Toolkit" Height="354.303" Width="527.152">
<Grid Margin="0,0,-8,-5">
<Button x:Name="BtnCalculate" Content="Calculate" HorizontalAlignment="Left" Margin="432,289,0,0" VerticalAlignment="Top" Width="75"/>
<Label x:Name="LblSearchDomain" Content="Search domain" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold"/>
<TextBox x:Name="TxtSearchDomain" HorizontalAlignment="Left" Height="23" Margin="10,42,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="malicis.com"/>
<Label x:Name="LblActiveMailboxes" Content="Active mailboxes" HorizontalAlignment="Left" Margin="10,74,0,0" VerticalAlignment="Top" FontWeight="Bold"/>
<Label x:Name="LblCurrentCount" Content="Current count:" HorizontalAlignment="Left" Margin="10,286,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="TxtCurrentCount" HorizontalAlignment="Left" Height="23" Margin="101,290,0,0" TextWrapping="Wrap" Text="00000" VerticalAlignment="Top" Width="45" IsEnabled="False" FontWeight="Bold"/>
<ProgressBar x:Name="PrgStatus" HorizontalAlignment="Left" Height="10" Margin="345,70,0,0" VerticalAlignment="Top" Width="162"/>
<TextBox x:Name="TxtStatus" HorizontalAlignment="Left" Height="23" Margin="345,42,0,0" TextWrapping="Wrap" IsEnabled="False" Text="idle" VerticalAlignment="Top" Width="162" FontStyle="Italic"/>
<Label x:Name="LblStatus" Content="Status" HorizontalAlignment="Left" Margin="345,10,0,0" VerticalAlignment="Top" FontWeight="Bold"/>
<ListView x:Name="LstActiveMailboxes" HorizontalAlignment="Left" Height="181" Margin="10,100,0,0" VerticalAlignment="Top" Width="497">
<ListView.View>
<GridView>
<GridViewColumn Header="Disable">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Margin="5, 0" IsChecked="False"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn >
<GridViewColumn Header="Name"/>
<GridViewColumn Header="Alias"/>
<GridViewColumn Header="Mailbox"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
"#
$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Warning "Unable to parse XML, with error: $($Error[0])`n Ensure that there are NO SelectionChanged properties (PowerShell cannot process them)"
throw}
#===========================================================================
# Load XAML Objects In PowerShell
#===========================================================================
$xaml.SelectNodes("//*[#Name]") | %{"trying item $($_.Name)";
try {Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop}
catch{throw}
}
Function Get-FormVariables{
if ($global:ReadmeDisplay -ne $true){Write-host "If you need to reference this display again, run Get-FormVariables" -ForegroundColor Yellow;$global:ReadmeDisplay=$true}
write-host "Found the following interactable elements from our form" -ForegroundColor Cyan
get-variable WPF*
}
Get-FormVariables
#===========================================================================
# Shows the form
#===========================================================================
Add-Type -AssemblyName System.Windows.Forms
Set-Variable -Name credsalreadyprovided -Value $false -Scope global
Set-Variable -Name CONFIG_SERVER -Value "exchpd01" -Scope global
$WPFBtnCalculate.Add_Click({
if ($credsalreadyprovided -eq $true){
calculate
}
else{
initiatesession
calculate
}
})
function initiatesession{
$WPFPrgStatus.Value = 0
Set-Variable -Name cred -Value (get-credential) -Scope global
$credsalreadyprovided = $true
$WPFPrgStatus.Value = 25
$WPFTxtStatus.Text = "Establishing session with " + $CONFIG_SERVER + "..."
Set-Variable -Name session -Value (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://$CONFIG_SERVER/PowerShell/ -credential $cred) -Scope global
$WPFPrgStatus.Value = 50
$WPFTxtStatus.Text = "Importing session..."
Import-PSSession $session -AllowClobber
}
function calculate{
$WPFPrgStatus.Value = 100
$WPFTxtStatus.Text = "Querying " + $CONFIG_SERVER + "..."
$SearchDomain=$WPFTxtSearchDomain.Text
$WPFTxtCurrentCount.Text = (get-Mailbox -identity *#$SearchDomain | where ismailboxenabled -eq true).count
#$mailboxes = get-mailbox -identity *#$SearchDomain | where ismailboxenabled -eq true
get-mailbox -identity *#$SearchDomain | where ismailboxenabled -eq true | ForEach-Object{
$name = $_.Name
$entry = New-Object System.Windows.Controls.ListViewItem($name)
$alias = $_.Alias
$entry.SubItems.Add($alias)
$mailbox = $_.Alias + "#" + $SearchDomain
$entry.SubItems.Add($mailbox)
$WPFLstActiveMailboxes.Items.Add($entry)
}
}
$Form.ShowDialog() | out-null
What I have always done is use databinding in WPF so that it is bound to the property that I want and then just create a psobject with those properties that I have bindings for in WPF, and then just add them to the ListView.Items collection.
Here is a reference of the wpf setup, and then just make sure to have your psobject properties the exact same as the binding properties in the wpf
DataGridView Column binding in WPF

DataGrid AddChild in Runspace

I've created a PowerShell Runspace and wanted to populate a DataGrid from a CSV file. The code works fine without a Runspace, but not in it.
I think the error must be in this two lines, but I can't get it:
$csv = Import-Csv "C:\name.csv" -Delimiter ";" -Encoding UTF8 |
Select-Object #{Name='USER';Expression={$_.USER}},`#{Name='ID';Expression={$_.ID}}
$csv | % { $syncHash.dgusers.AddChild($_) }
With this two lines in the code. The GUI won't show up.
The full code:
Add-Type -AssemblyName PresentationFramework
$syncHash = [hashtable]::Synchronized(#{})
$Runspace =[runspacefactory]::CreateRunspace()
$Runspace.ApartmentState = "STA"
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("syncHash", $syncHash)
$code = {
#Build the GUI
[xml]$xaml = #"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="UserList" Height="368" Width="525" WindowStyle="ToolWindow" Topmost="True" ResizeMode="NoResize">
<Grid>
<TabControl Name="tabControl" HorizontalAlignment="Left" Height="308" Margin="18,10,0,0" VerticalAlignment="Top" Width="481">
<TabItem Header="Lieferanten">
<Grid Background="#ffffff">
<DataGrid Name="dgusers" AutoGenerateColumns="False" Margin="19,27,158,20">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" Width="40" />
<DataGridTextColumn Header="USER" Binding="{Binding USER}" Width="233"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
"#
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$syncHash.Window=[Windows.Markup.XamlReader]::Load($reader)
$syncHash.Error = $Error
# XAML objects
$syncHash.dgusers = $syncHash.window.FindName("dgusers")
$csv = Import-Csv "C:\name.csv" -Delimiter ";" -Encoding UTF8 |
Select-Object #{Name='USER';Expression={$_.USER}},`#{Name='ID';Expression={$_.ID}}
$csv | % { $syncHash.dgusers.AddChild($_) }
$syncHash.Window.ShowDialog()
$Runspace.Close()
$Runspace.Dispose()
}
$PSinstance1 = [powershell]::Create().AddScript($Code)
$PSinstance1.Runspace = $Runspace
$job = $PSinstance1.BeginInvoke()

Resources