Recently, I came across an interesting bug in PowerShell. Let’s create a repro.
First, we create a string “a” and generate an xml based representation of it using the Export-Clixml cmdlet. Since we need to have the class id, we pipe the string to format-table as shown in the example below.
PS> "a" | format-table -auto | Export-Clixml a.xml
Here is the content of the xml file.
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData</T>
<T>Microsoft.PowerShell.Commands.Internal.Format.PacketInfoData</T>
<T>Microsoft.PowerShell.Commands.Internal.Format.FormatInfoData</T>
<T>System.Object</T>
</TN>
<ToString>Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData</ToString>
<Props>
<S N="ClassId2e4f51ef21dd47e99d3c952918aff9cd">27c87ef9bbda4f709f6b4002fa4af63c</S>
<Obj N="formatEntryInfo" RefId="1">
<TN RefId="1">
<T>Microsoft.PowerShell.Commands.Internal.Format.RawTextFormatEntry</T>
<T>Microsoft.PowerShell.Commands.Internal.Format.FormatEntryInfo</T>
<T>Microsoft.PowerShell.Commands.Internal.Format.FormatInfoData</T>
<T>System.Object</T>
</TN>
<ToString>Microsoft.PowerShell.Commands.Internal.Format.RawTextFormatEntry</ToString>
<Props>
<S N="ClassId2e4f51ef21dd47e99d3c952918aff9cd">29ED81BA914544d4BC430F027EE053E9</S>
<S N="text">a</S>
</Props>
</Obj>
<B N="outOfBand">true</B>
<B N="writeErrorStream">false</B>
</Props>
</Obj>
</Objs>
Then, we remove the class id (in blue) and save the xml file. Next, we recreate an object using the import-cliXml cmdlet and we assign it to a variable, i.e. $a. We should get an exception because the class id is missing but, we do not.
PS> $a = Import-Clixml .\a.xml
On the other hand, if we execute the same command without assigning it to a variable, the exception is thrown.
PS> Import-Clixml .\a.xml
Unknown class Id .
+ CategoryInfo : InvalidData: (Microsoft.Power…FormatEntryData:PS
Object) [out-lineoutput], PSArgumentException
+ FullyQualifiedErrorId : FormatObjectDeserializerDeserializeInvalidClassId,
Microsoft.PowerShell.Commands.OutLineOutputCommand
Why is this happening?
In the first instance, the object gets assigned to the variable and it never goes to the F&O system. Thus the terminating error is never generated.
The workaround
The fix is fairly simple, Out-String will send the object to the host through the F&O system.
PS> $a = Import-Clixml .\a.xml | Out-String
out-lineoutput : Unknown class Id .
+ CategoryInfo : InvalidData: (Microsoft.Power…FormatEntryData:PSObject
) [out-lineoutput], PSArgumentException
+ FullyQualifiedErrorId : FormatObjectDeserializerDeserializeInvalidClassId,Micros
oft.PowerShell.Commands.OutLineOutputCommand
To make sure our script ends nicely, we catch the terminating error.
$e = $null try{ Import-Clixml .\a.xml | Out-String } catch{ $e = $_ } If($e –ne $null) { $e.FullyQualifiedErrorId }
FormatObjectDeserializerDeserializeInvalidClassId,Microsoft.PowerShell.Commands.OutLineOut
putCommand
Cheers,
Francisco Gomez Gamino [MSFT]
0 comments