3

I have a very simple script that grabs the content from an XML file and returns it but is not working:

$DataFile = Get-ChildItem \\$Server\C$\ *.data -Name
[xml]$DataFileContent = Get-Content Microsoft.PowerShell.Core\FileSystem::\\$Server\C$\$DataFile
Write-Host $DataFileContent

This script is not returning any data on the Write-Host, but the following is returning the correct data:

$DataFile = Get-ChildItem \\$Server\C$\ *.data -Name
Get-Content Microsoft.PowerShell.Core\FileSystem::\\$Server\C$\$DataFile

Yes, the file is an xml file and the file exists. I'm sure I am missing something, but not sure what it is. Any help will be appreciated

rjbogz
  • 860
  • 1
  • 15
  • 36
  • 1
    If there are more than one files in the folder then $DataFile will be an array. I'm not positive exaclty how Get-Content will handle that but based on what you say works, it just gets the content of all the files and passes that down the line. In which case it would not be valid XML at that point. Is there more than 1 file in the folder? – EBGreen May 24 '18 at 16:46

2 Answers2

4

You cannot use Write-Host here since you're trying to display an [xml] object. Try write-output instead.

If you require Write-Host, you would need to represent the object as a string beforehand or use a property that outputs a string. For example:

[xml]$x = Get-Content y.xml
Write-Host $x.InnerXml

This may be a good idea to use with write-output, as well.

Jacob Colvin
  • 2,625
  • 1
  • 17
  • 36
  • 2
    Yet another reason to avoid `Write-Host`. You do not need to use `Write-Output` however. You can just leave it on its own line and it achieves the same thing: `$x.InnerXml` – Maximilian Burszley May 24 '18 at 16:53
  • I simply wrote that to increase verbosity as I believe they accomplish the same thing – Jacob Colvin May 24 '18 at 16:54
  • 1
    There is no `I believe` here, they *do* do the same thing. – Maximilian Burszley May 24 '18 at 16:55
  • It's not a good idea to present `Write-Output` as an alternative to `Write-Host` without mentioning that they serve very different purposes. There is no strict need to convert objects to strings before passing them to `Write-Host`, but the use with non-strings can indeed result in near-useless or even downright confusing output, as in this case (empty or blank), because `Write-Host` performs `.ToString()` formatting combined with (potentially recursive) enumeration. However, note that even [implied] `Write-Output` produces only marginally more helpful output for `[xml]` instances. – mklement0 May 25 '18 at 04:25
  • Hm - i was using `InnterText` instead of `InnerXml` – sommmen Nov 12 '20 at 13:38
0

First things first: Write-Host has few legitimate uses in general - do not use it to output data: Write-Host's output goes straight to the console and can therefore neither be sent through the pipeline, nor captured, nor redirected (loosely speaking; for the full story, see the last section of this answer of mine).

If your intent is to print a friendly representation of an object for display only, use Out-Host rather than Write-Host, because the latter does not apply PowerShell's usual, friendly output formatting.

$DataFileContent | Out-Host # print object *for display only*

If your intent is to output data, you can rely on PowerShell's implicit output behavior, which sends any output that is not explicitly captured or redirected to the success output stream, which by default prints to the console using friendly formatting:

$DataFileContent # same as: Write-Output $DataFileContent

Explicit use of Write-Output is rarely needed. A notable exception is if you want to output a collection as a single object, using -NoEnumerate.

Note: Instances of [xml] happen to have only semi-friendly default output formatting that provides no insight into the document structure; to see the latter, access the .OuterXml property, though you may additionally want to apply pretty-printing, which requires more work.


Write-Host output differs from Out-Host and implicit / Write-Output output that prints to the console as follows:

  • Instead of applying PowerShell's default output formatting, Write-Host essentially calls the .ToString() method on its input, which results in different, often near-useless representations - with the notable exception of string input.

  • Additionally, Write-Host enumerates the input objects, if applicable, so that a given input object's elements are individually stringified.
    An input object is considered enumerable if it implements the [System.Collections.IEnumerable] interface.
    This enumeration happens recursively, which in the case of [xml] instances results in output that is not only useless, but also confusing - see below.

[xml] instances, which represent XML documents, are enumerable, and so are their enumerated elements (XML nodes), recursively.

Write-Host recursively enumerates the top-level nodes of the document - which is either the root element alone, or, additionally, if present, the XML declaration - and invariably hits one or more leaf nodes, whose enumeration is invariably empty and yields the empty string. Given that Write-Host separates the stringification of its (enumerated) input objects with a space each, you either get the empty string or one or more spaces as the overall output.

mklement0
  • 382,024
  • 64
  • 607
  • 775