Forum Discussion

Bosjabouter's avatar
Bosjabouter
Tin Contributor
Jun 15, 2026

Get-ChildItem | Write-Host

The command in the title lists all the short names of files and folders in the current folder,  whereas `Get-ChildItem * | Write-Host`  lists the full names (including paths).  I compared the output of `Get-ChildItem | gm` with the output of `Get-ChildItem * | gm`: no difference. If the very same objects are piped into Write-Host, how can the cmdlet give consistently different outputs?

5 Replies

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    Hi Bosjabouter​,

     

    Write-Host isn't behaving differently. In fact, this actually has nothing to do with Write-Host at all.

     

    While I can't go so far as to debug the compiled .dll that Get-ChildItem is shipped in, the behaviour you're observing (which I can also reproduce across both Windows PowerShell and PowerShell) can be explained by the underlying .NET type, and the ToString() method in particular:

     

     

    As noted in the above documentation, ToString() returns the string provided to the class' constructor.

     

    What the key events look like in reverse chronology is:

     

    1. Write-Host (not that it's specific to Write-Host) calls [objectType].ToString();
    2. ToString() returns the path provided to the constructor;
    3. The Get-ChildItem commandlet creates a new instance of [objectType], passing in a string literal to the constructor. This is where your observed behaviour originates from;
    4. The Get-ChildItem commandlet enumerates file system objects.

     

    Leaving Write-Host out of the equation entirely, you can see the behaviour persists even when calling collection-specific methods:

     

     

    What this comes down to is it's an oversight (bug, if you must) within the Get-ChildItem commandlet itself, where it's what's producing the inconsistent output. But then referring back to the class documentation above, this is what's being acknowledged by the remarks where if you want consistent output, refer to the Name or FullName attributes explicitly:

     

     

    Cheers,

    Lain

  • Small addition: -Filter is also the most performant option, because the filtering is done by the provider before PowerShell creates any objects.

    That’s why it’s generally preferable when possible.

  • Hi,

    The difference you’re seeing doesn’t come from the objects themselves, but from how PowerShell resolves the pattern before sending data into the pipeline.

    Here is a simple example that shows it clearly:

    Get-ChildItem -Filter *.log | Write-Host   # Filter applied after enumeration → Name
    Get-ChildItem -Path *.log   | Write-Host   # Wildcard resolved before GCI runs → FullName
    Get-ChildItem *.log         | Write-Host   # Same → FullName

    ✔️ Why this happens

    • With -Filter, PowerShell enumerates the directory first, then applies the filter.
      The pipeline receives directory entries, and their default string representation is the Name.
    • With -Path or a direct wildcard (*.log), the wildcard is resolved before Get-ChildItem runs.
      The pipeline receives resolved full paths, so Write-Host prints the FullName.

    ✔️ If you want to always display only the file name

    Get-ChildItem *.log | Select-Object -ExpandProperty Name

    or:

    Get-ChildItem *.log | ForEach-Object { $_.Name }

    Hope this helps!

    • Bosjabouter's avatar
      Bosjabouter
      Tin Contributor

      Charlie34000, thank you for your elaborate answer. 

      As I understand  you, you are saying that Get-ChildItem passes objects into the pipeline that have the properties  Name or FullName depending on the  presence of either the parameter -Filter or -Path.  This makes sense to me.

      But,  I had hoped (and this was really what my question was about) that Get-Member would show the differences.  I compared by computer the outputs of  Get-ChildItem * | gm > a.txt   and   Get-ChildItem  | gm > b.txt .  The only difference between a.txt and b.txt is the value of PSChildName (a.txt and b.txt, respectively). That while Write-Host acts differently on the commands that generate a.txt and b.txt, just as it acts differently with -Filter or -Path in the parameter list.

      Apparently, I expected too much of Get-Member and I have to revise accordingly my  understanding of the PowerShell pipeline. My main purpose in this discussion  is to find the logic behind the rules that cmdlets and  objects follow in their interaction with pipelines and I had hoped that Get-Member would be a useful tool.

      • Charlie34000's avatar
        Charlie34000
        MCT

        Hi again,

        You understood correctly that the objects are the same — and that’s exactly why Get-Member shows no difference.

        The key point is that the difference does not come from the object type, but from the string representation that PowerShell produces before Write-Host prints it.

         

        Write-Host does not display the object itself.

        It displays the default string representation of whatever is sent into the pipeline.

        And this is where the difference comes from:

        • With -Filter, PowerShell enumerates the directory first and sends directory entries into the pipeline.
          Their default string representation is the Name.
        • With a wildcard in the path (*.log, Win*, etc.), the wildcard is resolved before Get-ChildItem runs.
          What enters the pipeline is a resolved full path, whose string representation is the FullName.

         

        So Get-Member shows identical objects, but Write-Host prints different strings because the stringification step happens earlier in the wildcard case.

        Hope this clarifies why GM cannot show this difference.