Workaround to Catch Exceptions from Import-CliXml

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]