Powershell: ConvertTo-Xml fails with nested custom objects: omits closing </Objects> tag

Created on 18 Nov 2018  路  10Comments  路  Source: PowerShell/PowerShell

See repro below.

As an aside (that will probably become a docs issue): What is the purpose of ConvertTo-Xml? The docs suggest that it is the in-memory counterpart to Export-Clixml, however:

  • It produces _different_ XML representations,
  • which, if saved to a file, cannot be re-imported with Import-Clixml

Steps to reproduce

[pscustomobject] @{ a = [pscustomobject] @{ aa=11; bb=22 } } | ConvertTo-Xml

Expected behavior

Should output an [xml] instance that is the serialization of the custom object.

Actual behavior

The following error occurs:

ConvertTo-Xml : Unexpected end of file has occurred. The following elements are not closed: Objects.
  • If you use -As String, you don't get an error, but the XML string output too is missing the closing </Objects> tag.

  • Removing the 2nd property (bb) from the nested custom object makes the problem go away.

  • Using [hashtable] instances instead of [pscustomobject]s makes the problem go away.

  • Export-Clixml does _not_ exhibit the problem.

Environment data

PowerShell Core 6.2.0-preview.1 on macOS 10.14.1
PowerShell Core 6.2.0-preview.1 on Ubuntu 16.04.5 LTS
PowerShell Core 6.2.0-preview.1 on Microsoft Windows 10 Pro (64-bit; Version 1803, OS Build: 17134.345)
Windows PowerShell v5.1.17134.228 on Microsoft Windows 10 Pro (64-bit; Version 1803, OS Build: 17134.345)
Area-Cmdlets-Utility Issue-Bug Resolution-Fixed Up-for-Grabs

All 10 comments

Fails with Windows PowerShell 5.1 so not a regression. Seems specific to nested [PSCustomObject]. Other cases work

get-process | select -first 1 | convertto-xml

Thanks, @SteveL-MSFT. Generally, I only include a Windows PowerShell version in the _Environment data_ section if it _isn't_ a regression (and, conversely, point out if it is). Can you briefly explain the purpose of ConvertTo-Xml with respect to my comments at the top, so I can open doc issues, if/as needed?

@mklement0 I don't know the history of it, but I can make an educated guess. ConvertTo-Xml uses a simplified format that makes it easier to use with other systems that accept XML although it's probably still a bit more abstract than a simple property bag format... Export-CliXml is the same serialization format PowerShell uses for remoting so it's more complete to enable deserialization. Ideally, it seems like we should have had ConvertTo-Xml take a -Format parameter that supported CliXml and other xml formats rather than having this confusion between ExportTo-CliXml and ConvertTo-Xml having incompatible xml formats.

Thanks, @SteveL-MSFT.

other systems that accept XML

So I can suggest improvements to the docs: can you give examples of such other systems?
Are there common real-world scenarios?

@mklement0 @SteveL-MSFT this does seem specific to pscustomobject. The following works:

[psobject] @{ a = [psobject] @{ aa=11; bb=22 } } | ConvertTo-Xml

@sdwheeler: Yes, but do note that casting to [psobject] is a virtual no-op, because only the [pscustombject] cast provides the custom-object construction syntactic sugar:

PS> ([psobject] @{ a = [psobject] @{ aa=11; bb=22 } }).GetType().Name
Hashtable # !! [psobject] was effectively ignored.

As an aside: I say _virtual_ no-op, because you do get an extra [psobject] wrapper, though that is _mostly_ invisible - except when it isn't.

In other words: your command is the same as the following, and therefore operates on a hashtable:

@{ a = @{ aa=11; bb=22 } } | ConvertTo-Xml

@mklement0 the "other systems" was purely hypothetical :) In this day and age, it's probably safe to say it's very uncommon to use XML vs JSON. Other than some demos, I've never had to use ConvertTo-Xml myself for any real world scenarios.

Looks like the serializer erroneously decreases the serialization depth when writing PSObject properties:
https://github.com/PowerShell/PowerShell/blob/5d03e1653a7d518715fa3f00587cad6b5c78cc89/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CustomSerialization.cs#L735

This results in nested properties whenever there's more than one.

Removing --depth; seems to solve the problem completely

@IISResetMe perhaps you could submit a PR with tests :)

Was this page helpful?
0 / 5 - 0 ratings