0

I tried to use XAML in PowerShell and encountered a strange issue. If I write the xmlns: lines below in one line like this

$inputXML = @"
<Window x:Class="WpfApplication2.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:WpfApplication2" mc:Ignorable="d" Title="test" Height="416.794" Width="598.474" Topmost="True">
    <Grid Margin="0,0,45,0">
        <Image x:Name="image" HorizontalAlignment="Left" Height="100" Margin="24,28,0,0" VerticalAlignment="Top" Width="100" Source="C:\Users\123.png"/>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Height="100" Margin="174,28,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="282" FontSize="16"><Run Text="Use this tool to find out all sorts of useful disk information, and also to get rich input from your scripts and tools"/><InlineUIContainer>
                <TextBlock x:Name="textBlock1" TextWrapping="Wrap" Text="TextBlock"/>
            </InlineUIContainer></TextBlock>
        <Button x:Name="button" Content="get-DiskInfo" HorizontalAlignment="Left" Height="35" Margin="393,144,0,0" VerticalAlignment="Top" Width="121" FontSize="18.667"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="35" Margin="186,144,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="168" FontSize="16"/>
        <Label x:Name="label" Content="ComputerName" HorizontalAlignment="Left" Height="46" Margin="24,144,0,0" VerticalAlignment="Top" Width="138" FontSize="16"/>
        <ListView x:Name="listView" HorizontalAlignment="Left" Height="156" Margin="24,195,0,0" VerticalAlignment="Top" Width="511" FontSize="16">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Drive Letter" DisplayMemberBinding ="{Binding 'Drive Letter'}" Width="120"/>
                    <GridViewColumn Header="Drive Label" DisplayMemberBinding ="{Binding 'Drive Label'}" Width="120"/>
                    <GridViewColumn Header="Size(MB)" DisplayMemberBinding ="{Binding Size(MB)}" Width="120"/>
                    <GridViewColumn Header="FreeSpace%" DisplayMemberBinding ="{Binding FreeSpace%}" Width="120"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>
"@

it throws an error

Exception calling "Load" with "1" argument(s): "Cannot create unknown type
'Window'."
At line:36 char:5
+ try{$Form=[Windows.Markup.XamlReader]::Load( $reader )}
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : XamlParseException

If I write each of them in one line like below it works fine. Is this due the batch processing?

$inputXML = @"
<Window x:Class="WpfApplication2.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:WpfApplication2" mc:Ignorable="d" 
Title="test" Height="416.794" Width="598.474" Topmost="True">
    <Grid Margin="0,0,45,0">
        <Image x:Name="image" HorizontalAlignment="Left" Height="100" Margin="24,28,0,0" VerticalAlignment="Top" Width="100" Source="C:\Users\Stephen\Dropbox\Docs\blog\foxdeploy favicon.png"/>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Height="100" Margin="174,28,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="282" FontSize="16"><Run Text="Use this tool to find disk information"/><InlineUIContainer>
                <TextBlock x:Name="textBlock1" TextWrapping="Wrap" Text="TextBlock"/>
            </InlineUIContainer></TextBlock>
        <Button x:Name="button" Content="get-DiskInfo" HorizontalAlignment="Left" Height="35" Margin="393,144,0,0" VerticalAlignment="Top" Width="121" FontSize="18.667"/>
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="35" Margin="186,144,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="168" FontSize="16"/>
        <Label x:Name="label" Content="ComputerName" HorizontalAlignment="Left" Height="46" Margin="24,144,0,0" VerticalAlignment="Top" Width="138" FontSize="16"/>
        <ListView x:Name="listView" HorizontalAlignment="Left" Height="156" Margin="24,195,0,0" VerticalAlignment="Top" Width="511" FontSize="16">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Drive Letter" DisplayMemberBinding ="{Binding 'Drive Letter'}" Width="120"/>
                    <GridViewColumn Header="Drive Label" DisplayMemberBinding ="{Binding 'Drive Label'}" Width="120"/>
                    <GridViewColumn Header="Size(MB)" DisplayMemberBinding ="{Binding Size(MB)}" Width="120"/>
                    <GridViewColumn Header="FreeSpace%" DisplayMemberBinding ="{Binding FreeSpace%}" Width="120"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>
"@

I took the code from a blog in order to test the compatibility:

$inputXML = @"
...
"@        

$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}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Vizchris
  • 1
  • 1
  • Please edit your question and add the missing closing tags of the here-string(`"@`). – gdir Feb 08 '18 at 08:28
  • Please show the actual code throwing the error and the complete error message. Also, your first data snippet is still incomplete. – Ansgar Wiechers Feb 08 '18 at 13:31

1 Answers1

2

The code you used is broken. The person who wrote that blog post apparently neglected to actually test what they posted, because that code should have thrown the same error you observed. The statement

$inputXML = $inputXML ... -replace '^<Win.*', '<Window'

will change the line

<Window x:Class="WpfApplication2.MainWindow" ... Topmost="True">

into

<Window

without a closing angular bracket, thus rendering the XML invalid.

Your second XML sample is not affected because its <Window> tag is wrapped across multiple lines, so that the closing angular bracket is on a different line and thus not affected by the replacement operation.

<Window x:Class="WpfApplication2.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
...
Title="test" Height="416.794" Width="598.474" Topmost="True">

turns into

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
...
Title="test" Height="416.794" Width="598.474" Topmost="True">

which remains valid XML.

Adjust the pattern <Win.* to something more specific and the problem will disappear. Assuming that you want to remove the x:Class attribute from the tag (because replacing <Window with <Window wouldn't make much sense) you could do something like this:

$inputXML = $inputXML ... -replace '(?<=<Window) x:Class=".*?"',''

By the way, this is a prime example for why you shouldn't manipulate XML with string operations in the first place (related). A significantly better solution to your problem (again, assuming you want to remove the x:Class attribute from the <Window> node) would be to remove the attribute after the XML parser provided you with the proper tools for doing that:

$inputXML = @"
...
"@

[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML

$XAML.Window.RemoveAttribute('x:Class')
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328