I have been building GUI's for a while in powershell with XAML. Everything has worked fine until I attempted to bring in ComboBox. Then powershell no longer accepts it.
I have built the XAML in Visual Studio and it works in Design view. Every website I go to tells me this is the right XAML code. The error occurs with the code
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$DiagForm=[Windows.Markup.XamlReader]::Load( $reader )}
Here is the sample I am working with. If you take out the ComboBox segment, it works perfectly fine.
function Diag {
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tool" Height="500" Width="300" WindowStartupLocation="CenterScreen" WindowStyle='SingleBorderWindow' ResizeMode='CanMinimize'>
<Grid>
<TextBox HorizontalAlignment="Center" Height="23" TextWrapping="Wrap" Text="Diagnostics" VerticalAlignment="Top" Width="300" Margin="0,-1,-0.2,0" TextAlignment="Center" Foreground="White" Background="#21C500"/>
<Label Content="Report" HorizontalContentAlignment="Center" HorizontalAlignment="Left" Margin="90,27,0,0" VerticalAlignment="Top" Width="120"/>
<ComboBox HorizontalAlignment="Left" Margin="90,60,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem MouseMove="OnHover" Name="Period1" IsSelected="True">Last 24hr</ComboBoxItem>
<ComboBoxItem MouseMove="OnHover" Name="Period2" IsSelected="False">Last Week</ComboBoxItem>
<ComboBoxItem MouseMove="OnHover" Name="Period3" IsSelected="False">Last Month</ComboBoxItem>
</ComboBox>
<Label Content="Critical" HorizontalAlignment="Left" Margin="46,115,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="124,115,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<Label Content="Warnings" HorizontalAlignment="Left" Margin="46,143,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="124,143,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
</Grid>
</Window>
'#
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$DiagForm=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit}
$xaml.SelectNodes("//*[#Name]") | %{Set-Variable -Name ($_.Name) -Value $DiagForm.FindName($_.Name)}
$DiagForm.ShowDialog() | out-null
}
Diag
If you examine the exception that is being caught, you'll see the following error message:
Failed to create a 'MouseMove' from the text 'OnHover'.
Indeed, if you remove the MouseMove="OnHover" attributes from your XAML, the problem goes away.
Related
Please can you help me?
The code makes this output error:
Unable to load Windows.Markup.XamlReader
This code is made by Microsoft Visual Studio - Project WPF APP
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[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:WpfApp2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Label Name="label1" Content="Label" HorizontalAlignment="Left" Margin="222,102,0,0" VerticalAlignment="Top" Width="92"/>
<Label Name="label2" Content="Label" HorizontalAlignment="Left" Margin="222,177,0,0" VerticalAlignment="Top" Width="92"/>
<Label Name="label3" Content="Label" HorizontalAlignment="Left" Margin="222,246,0,0" VerticalAlignment="Top" Width="92"/>
<TextBox Name="text1" HorizontalAlignment="Left" Margin="369,110,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" TextChanged="text1_TextChanged_1"/>
<TextBox Name="text2" HorizontalAlignment="Left" Margin="369,185,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.483,4.29"/>
<TextBox Name="text3" HorizontalAlignment="Left" Margin="369,254,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.483,4.29"/>
<Button Name="button1" Content="Button" HorizontalAlignment="Left" Margin="572,168,0,0" VerticalAlignment="Top" Width="131" Height="46"/>
</Grid>
</Window>
"#
#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
catch{Write-Host "Unable to load Windows.Markup.XamlReader"; exit}
# Store Form Objects In PowerShell
$xaml.SelectNodes("//*[#Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
#Show Form
$Form.ShowDialog() | out-null
I create a GUI with Visual Studio and import the XAML code in Powershell and i have a problem to display in textbox a value from one of 5 combobox selected item.
I learn by myself and i really love it but i dont have the good method for debbug my code alone,
anybody can have a time and a knowledge for help me please ?
I want to display in textbox ($TxtBox) the selected item (or value) from CboPL or CboTG or CboSB....
with powershell.
This is my XAML code beetwen here string in powershell :
<Window x:Name="Main" x:Class="Printers_Ordi.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:Printers_Ordi"
mc:Ignorable="d"
Title="Printers-Ordi" Height="450" Width="728.471">
<Grid x:Name="Wall">
<Grid.Background>
<ImageBrush ImageSource="C:/Users/admsb160365/Desktop/scripts Shell/Imprimantes GHT/Wall.png"/>
</Grid.Background>
<Label x:Name="LabelTitre" Content="Printers-Ordi" HorizontalAlignment="Left" Margin="74,25,0,0" VerticalAlignment="Top" FontFamily="Yu Gothic UI Semibold" FontSize="24" RenderTransformOrigin="0.503,0.76" Height="42" Width="164" Foreground="#FF1346CD"/>
<ComboBox x:Name="CboComputer" HorizontalAlignment="Left" Margin="74,82,0,0" VerticalAlignment="Top" Width="164" FontSize="16" Height="31" IsEditable="True" IsReadOnly="True" Text="Ordinateur"/>
<ComboBox x:Name="CboSites" HorizontalAlignment="Left" Margin="74,118,0,0" VerticalAlignment="Top" Width="164" Height="31" FontSize="16" IsEditable="True" IsReadOnly="True" Text="Sites">
<ComboBox x:Name="CboPL" HorizontalAlignment="Left" VerticalAlignment="Top" Width="154" FontSize="16" IsEditable="True" IsReadOnly="True" Text="Paimpol"/>
<ComboBox x:Name="CboGP" HorizontalAlignment="Left" VerticalAlignment="Top" Width="154" FontSize="16" IsEditable="True" IsReadOnly="True" Text="Guingamp"/>
<ComboBox x:Name="CboSB" HorizontalAlignment="Left" VerticalAlignment="Top" Width="154" FontSize="16" IsEditable="True" IsReadOnly="True" Text="SaintBrieuc"/>
<ComboBox x:Name="CboLN" HorizontalAlignment="Left" VerticalAlignment="Top" Width="154" FontSize="16" IsEditable="True" IsReadOnly="True" Text="Lannion"/>
<ComboBox x:Name="CboTG" HorizontalAlignment="Left" VerticalAlignment="Top" Width="154" FontSize="16" IsEditable="True" IsReadOnly="True" Text="Treguier"/>
</ComboBox>
Thanks by advance for your patience and support ;-)
Continuing from my comments. There are a few ways to deal with your use case. Here is a simple example using Winform. Ultimately, it's still collecting/assigning text from one element(s)/or code results to another.
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({
switch($ComboBox.Text){
'One' {$RichTextBox.Text = 'This is one'}
'Two' {$RichTextBox.Text = 'This is two'}
}
})
$Form.ShowDialog()
An example using WPF
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[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="PowerShell Form" Height="310" Width="350" ResizeMode="NoResize">
<Grid Margin="0,0,0,0">
<GroupBox Header="General" HorizontalAlignment="Left" Height="225" Margin="10,10,0,0" VerticalAlignment="Top" Width="320">
<Grid HorizontalAlignment="Left" Height="206" Margin="0,0,0,0" VerticalAlignment="Top" Width="320">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*"/>
<ColumnDefinition Width="250*"/>
</Grid.ColumnDefinitions>
<Label Content="Field #1:" HorizontalAlignment="Left" Margin="0,7,0,0" VerticalAlignment="Top" Height="26" Width="93"/>
<Label Content="Field #2:" HorizontalAlignment="Left" Margin="0,35,0,0" VerticalAlignment="Top" Height="26" Width="93"/>
<Label Content="Field #3:" HorizontalAlignment="Left" Margin="0,65,0,0" VerticalAlignment="Top" Height="26" Width="93"/>
<TextBox Name="f1" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="229" Grid.Column="1"/>
<ComboBox Name="f2" HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" VerticalAlignment="Top" Width="229" Grid.Column="1">
<ListBoxItem>Test 1</ListBoxItem>
<ListBoxItem>Test 2</ListBoxItem>
<ListBoxItem>Test 3</ListBoxItem>
</ComboBox>
<TextBox Name="f3" HorizontalAlignment="Left" Height="23" Margin="10,66,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="229" Grid.Column="1"/>
</Grid>
</GroupBox>
<Button Name="Clear" Content="Clear Form" HorizontalAlignment="Left" Margin="10,240,0,0" VerticalAlignment="Top" Width="90" Height="30" RenderTransformOrigin="0.522,0.733"/>
<Button Name="Submit" Content="Submit" Margin="234,240,12,0" VerticalAlignment="Top" Height="30"/>
</Grid>
</Window>
'#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try{$Form = [Windows.Markup.XamlReader]::Load( $reader )}
catch
{
Write-Host 'Unable to load Windows.Markup.XamlReader.'
break
}
$xaml.SelectNodes('//*[#Name]') |
ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}
$Form.Add_Loaded({
if (Test-Path -Path '.\ComboBox.selection')
{
$cbSelection = Get-Content '.\ComboBox.selection'
[int]$cbSelectionInt = -1
[void][int]::TryParse($cbSelection,[ref]$cbSelectionInt)
if ($cbSelectionInt -ge 0)
{$f2.SelectedIndex = $cbSelectionInt}
}
})
$Clear.Add_Click({
$fields = #('f1','f2','f3')
foreach ($field in $fields)
{
$control = $Form.FindName($field)
switch ($control.GetType()) {
'System.Windows.Controls.TextBox' {$control.Clear()}
'System.Windows.Controls.ComboBox' {$control.SelectedIndex = -1}
DEFAULT {'unknown control'}
}
}
})
$f2.add_SelectionChanged({
param($sender,$args)
$f3.Text = ($($sender.SelectedValue) -replace '.*:\s+')
})
$Form.ShowDialog()
Im trying to make a powershellscript using XAML Objects, that can be used to configure AD-Users.
My goal right now is to add a live search for a specific textbox. The script uses the input from the textbox, compares it to AD-Users and displays the output in a listbox. What I need is an eventhandler, that activates when I click any Item in the listbox
The last part is the relevant piece.
I'm grateful for any help.
$inputXML = #"
<Window x:Class="WpfApplication3.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:WpfApplication3"
mc:Ignorable="d"
Title="HHI Helpdesk Helper" Height="350" Width="654.604" Icon="C:\Users\hoesl\Pictures\logo.png" WindowStartupLocation="CenterScreen">
<Grid Background="#FFA0A0A0">
<TabControl x:Name="tabControl" HorizontalAlignment="Left" Height="301" Margin="10,10,0,0" VerticalAlignment="Top" Width="628">
<TabItem Header="Enable Admin Account">
<Grid Background="#FFE5E5E5">
<Label x:Name="label" Content="User : " HorizontalAlignment="Left" Margin="47,10,0,0" VerticalAlignment="Top"/>
<Label x:Name="label1" Content="Service-Tag : " HorizontalAlignment="Left" Margin="10,53,0,0" VerticalAlignment="Top"/>
<Label x:Name="label2" Content="Set Password : " HorizontalAlignment="Left" Margin="2,95,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="95,57,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="95,99,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Calendar HorizontalAlignment="Left" Margin="434,10,0,0" VerticalAlignment="Top"/>
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="10,127,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Height="116" Width="410">
<TextBlock.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FFA3A3A3"/>
</LinearGradientBrush>
</TextBlock.Background>
</TextBlock>
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="434,182,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" RenderTransformOrigin="0.482,0.542" Height="27" Width="178" OpacityMask="White">
<TextBlock.Background>
<RadialGradientBrush>
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FFE0DFDF"/>
</RadialGradientBrush>
</TextBlock.Background>
</TextBlock>
<Label x:Name="label3" Content="Valid Until : " HorizontalAlignment="Left" Margin="346,11,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="checkBox" Content="Keep old password" HorizontalAlignment="Left" Margin="220,108,0,0" VerticalAlignment="Top"/>
<Button x:Name="button" Content="Apply" HorizontalAlignment="Left" Margin="435,215,0,0" VerticalAlignment="Top" Width="178" Height="29" BorderBrush="White" Background="#FFA6A5A5"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="125" Margin="95,32,0,-0.2" VerticalAlignment="Top" Width="120" Visibility="Hidden" IsSynchronizedWithCurrentItem="True"/>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="95,14,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
</Grid>
</TabItem>
<TabItem Header="Re-Activate Admin Account">
<Grid Background="#FFE5E5E5">
<Label x:Name="label4" Content="User : " HorizontalAlignment="Left" Margin="85,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBox3" HorizontalAlignment="Left" Height="23" Margin="133,13,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Calendar HorizontalAlignment="Left" Margin="420,10,0,0" VerticalAlignment="Top" Height="168" Width="188"/>
<Button x:Name="button1" Content="Button" HorizontalAlignment="Left" Margin="420,214,0,0" VerticalAlignment="Top" Width="193" Height="29"/>
</Grid>
</TabItem>
<TabItem Content="New User" Header="New User"/>
<TabItem Header="Unlock User"/>
<TabItem Header="New Extern User">
<Grid Background="#FFE5E5E5">
<TextBox x:Name="textBox4" HorizontalAlignment="Left" Height="23" Margin="111,14,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox5" HorizontalAlignment="Left" Height="23" Margin="111,49,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox6" HorizontalAlignment="Left" Height="23" Margin="111,88,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox7" HorizontalAlignment="Left" Height="23" Margin="111,127,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="textBox8" HorizontalAlignment="Left" Height="23" Margin="111,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Label x:Name="label5" Content="Firstname :" HorizontalAlignment="Left" Margin="36,10,0,0" VerticalAlignment="Top"/>
<Label x:Name="label6" Content="Lastname :" HorizontalAlignment="Left" Margin="36,45,0,0" VerticalAlignment="Top"/>
<Label x:Name="label7" Content="E-Mail-Address :" HorizontalAlignment="Left" Margin="6,85,0,0" VerticalAlignment="Top"/>
<Label x:Name="label8" Content="Manager :" HorizontalAlignment="Left" Margin="39,124,0,0" VerticalAlignment="Top"/>
<Label x:Name="label9" Content="Ticketnumber :" HorizontalAlignment="Left" Margin="15,163,0,0" VerticalAlignment="Top"/>
<TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="295,14,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="175" Width="318" Background="#FF323131" Foreground="White" Cursor="Wait"/>
<Button x:Name="button2" Content="Button" HorizontalAlignment="Left" Margin="503,212,0,0" VerticalAlignment="Top" Width="110" Height="31"/>
</Grid>
</TabItem>
</TabControl>
</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 or TextChanged properties in your textboxes (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
#===========================================================================
# Use this space to add code to the various form elements in your GUI
#===========================================================================
#setzt die Variablen auf bestimmte Objekte, wodurch das Verändern der Objekte sehr flexibel ist
$OutputBox = $Form.FindName('textBlock')
$InputBox = $Form.FindName('textBox')
$ListBox = $Form.FindName('listBox')
#Eventhandler
$InputBox.Add_TextChanged({
$input = $InputBox.Text
if($input.length -gt 3){
$ListBox.Visibility ="Visible"
$input = "*" + $input + "*"
$user = #(Get-ADUser -Filter ' Name -like $input ' | Select -ExpandProperty Name)
#debug $OutputBox.Text = ($user | ForEach {"{0}`r" -f $_})
$ListBox.itemsSource = $user
---> Here should be the eventhandler for clicking an item in the listbox <---
# $listuser = Get-ADUser -Filter ' Name -like $ListBox.SelectedItem '
# $OutputBox.Text = $ListBox.SelectedItem
}
})
$Form.ShowDialog()
The answer:
$ListBox.add_SelectionChanged({$OutputBox.Text = $ListBox.SelectedItem})
Personally I prefer creating special function with events and call it before $Form.ShowDialog(). Add as much events as you need. Example:
function event_handler
{
$textbox_name.add_TextChanged({$textbox_Login.Text = Construct-Login $textbox_name.Text $textbox_LastName.Text})
}
In this example when you type something to the textbox textbox_name, function Construct-Login is invoked and result is written to another textbox.
By the way, you don't need extra
$OutputBox = $Form.FindName('textBlock')
$ListBox = $Form.FindName('listBox')
since $xaml.SelectNodes does the thing for you. Just make sure you have unique names for all controls at your form.
Im a beginner and is needing help running an XAML into powershell.
Im trying to follow some format from the net but cant seem to convert my xaml GUI to powershell.
Any help will do. Heres my code:
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="Strike Email" Height="137" Width="274" Background="White">
<Grid Background="#FF005D80">
<Button Content="1st Strike" HorizontalAlignment="Left" Height="50" Margin="10,30,0,0" VerticalAlignment="Top" Width="70" Background="White" Click="Button_Click"/>
<Button Content="3rd Strike" HorizontalAlignment="Left" Height="50" Margin="180,30,0,0" VerticalAlignment="Top" Width="70" Background="White"/>
<Button Content="2nd Strike" HorizontalAlignment="Left" Height="50" Margin="95,30,0,0" VerticalAlignment="Top" Width="70" Background="White"/>
</Grid>
For that, you will need to:
Cast your xaml string as a xml
Load presentationframework assembly
Load the XAML into a xmlNodeReader
Load the form
Powershell must be running in STA (Single threaded) mode for this to work
(Powershell ISE launch in STA mode by default.)
[xml]$xaml = 'ValidXAMLStringHere'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$Form.ShowDialog() | out-null
Something like the snippet would be the end result.
I even added a button click event for fun.
[xml]$xaml = #'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Strike Email" Height="137" Width="274" Background="White">
<Grid Background="#FF005D80">
<Button Content="1st Strike" HorizontalAlignment="Left" Height="50" Margin="10,30,0,0" VerticalAlignment="Top" Width="70" Background="White" x:Name="FirstStrike" />
<Button Content="3rd Strike" HorizontalAlignment="Left" Height="50" Margin="180,30,0,0" VerticalAlignment="Top" Width="70" Background="White"/>
<Button Content="2nd Strike" HorizontalAlignment="Left" Height="50" Margin="95,30,0,0" VerticalAlignment="Top" Width="70" Background="White"/>
</Grid>
</Window>
'#
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
try
{
$Form=[Windows.Markup.XamlReader]::Load( $reader )
}
catch
{
Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."t
}
cls
$Button = $Form.FindName('FirstStrike')
$Button.Add_Click({ Write-Host "First Strike Button Clicked" -ForegroundColor Cyan})
$Form.ShowDialog() | out-null
References:
Technet - Integrating XAML into PowerShell
Learn Powershell - PowerShell and WPF: Buttons
I'm trying to convert my PowerShell project to an executable program (.exe). After some research I found PowerGUI. After converting my .ps1 file into an exe I ran into some problems:
Firstly it takes ages to start the program (about 15 seconds), is this normal or is there something I can do to improve this?
Secondly, if i exit the program I get a windows error message saying the program stopped working unexpectedly. Is there a way to hide this message?
Here is my ps1 code, I got a part of it from a blog and it is my first PowerShell code so don't be to harsh on me ;)
$inputXML = #"
<Window x:Class="BlogPostIII.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:BlogPostIII"
mc:Ignorable="d"
Title="Organizer" Height="540" Width="540" FontSize="18.667">
<Grid x:Name="background">
<Button x:Name="OK" Content="OK" HorizontalAlignment="Left" Height="41" Margin="420,458,0,0" VerticalAlignment="Top" Width="100" FontSize="18.667"/>
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Left" Height="41" Margin="315,458,0,0" VerticalAlignment="Top" Width="100" FontSize="18.667"/>
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="30" Margin="108,216,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBlock x:Name="TextBlock1" HorizontalAlignment="Left" Height="30" Margin="108,36,0,0" TextWrapping="Wrap" Text="Soort bewerking:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBox x:Name="TextBox2" HorizontalAlignment="Left" Height="30" Margin="108,291,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBlock x:Name="TextBlock2" HorizontalAlignment="Left" Height="30" Margin="108,111,0,0" TextWrapping="Wrap" Text="Naam Machine:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBox x:Name="TextBox3" HorizontalAlignment="Left" Height="30" Margin="108,366,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBlock x:Name="TextBlock3" HorizontalAlignment="Left" Height="30" Margin="108,185,0,0" TextWrapping="Wrap" Text="Naam van opdrachtgevend bedrijf:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBlock x:Name="TextBlock4" HorizontalAlignment="Left" Height="30" Margin="108,261,0,0" TextWrapping="Wrap" Text="Naam product:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<TextBlock x:Name="TextBlock5" HorizontalAlignment="Left" Height="30" Margin="108,336,0,0" TextWrapping="Wrap" Text="Product ID:" VerticalAlignment="Top" Width="300" FontSize="18.667"/>
<ComboBox x:Name="combobox1" HorizontalAlignment="Left" Margin="108,66,0,0" VerticalAlignment="Top" Width="300"/>
<ComboBox x:Name="combobox2" HorizontalAlignment="Left" Margin="108,140,0,0" VerticalAlignment="Top" Width="300"/>
</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-Host "Unable to load Windows.Markup.XamlReader. Double-check syntax and ensure .net is installed."}
#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
$xaml.SelectNodes("//*[#Name]") | %{Set-Variable -Name "WPF$($_.Name)" -Value $Form.FindName($_.Name)}
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
#===========================================================================
# List the Comboboxes
#===========================================================================
$WPFcombobox1.AddText('Draaien')
$WPFcombobox1.AddText('Frezen')
$WPFcombobox1.AddText('Slijpen')
$WPFcombobox2.AddText('Doosan 3100LM')
$WPFcombobox2.AddText('Doosan 123')
$WPFcombobox2.AddText('machine 3')
$WPFcombobox2.AddText('machine 4')
$WPFcombobox2.AddText('machine 5')
#===========================================================================
# Actually make the objects work
#===========================================================================
#$WPFMakeUserbutton.Add_Click({(Get-FormFields)})
$WPFOK.Add_Click({
$1 = $WPFcomboBox1.Text
$2 = $WPFcomboBox2.Text
$3 = $WPFtextBox1.Text
$4 = $WPFtextBox2.Text
$5 = $WPFtextBox3.Text + " Werkblad"
New-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\ -Force -type directory
Copy-Item C:\Users\Bjorn\Documents\Powershell\Test_werkblad.docx C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\
Rename-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\Test_werkblad.docx C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\$5.docx
Invoke-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4
Invoke-Item C:\Users\Bjorn\Documents\Powershell\$1\$2\$3\$4\$5.docx
$Form.Close()})
$WPFCancel.Add_Click({
$Form.Close()})
#===========================================================================
# Shows the form
#===========================================================================
write-host "To show the form, run the following" -ForegroundColor Cyan
function Show-Form{
$Form.ShowDialog() | out-null
}
Show-Form
About the 15 seconds I am not sure why. Could you give more details? You should add logging and put time stamp in every message... This way you should be able to locate slow part.
About avoiding the error message, you should surround your code with try/catch. For example:
[...]
write-host "To show the form, run the following" -ForegroundColor Cyan
function Show-Form
{
$Form.ShowDialog() | out-null
}
try
{
Show-Form
}
catch
{
$ErrorMessage = $_.Exception.Message
# Show friendly message with error and/or log the error)
}
After reading your code here is some extra advice that could be useful:
Do not hardcode paths. (Like "C:\Users\Bjorn\Documents\Powershell\")
Do you really need PowerShell? Sounds like C# WinForms would be better for this task.
Store XML in a file and read it rather having it in code in $inputXML variable.
The 15 second pause is PowerShell initializing in the background. This is especially noticeable on Windows 7
CAVEAT: "compiling" PowerShell to EXE in most cases (PowerGUI included) is stuffing your original PS1 file inside a Self-extracting EXE. You could do the same with 7-Zip or WinZip.
A PowerGUI "compiled" EXE locks your script execution to whatever version or PowerShell + .Net you had on your DEV box. IOW: If you compile on a PC with PowerShell v4 but only use Write-host in your script (for example), the target PCs will need PowerShell v4+ for it to run!