How do I pass the string from powershell's out-string as an argument to get-content / cat (directly)?

Viewed 137

I want to basically do this:

Get-Childitem -Recurse -filter "* *" -Force | foreach-object {
  get-childitem $_ | select-object fullname |
    Format-Table -HideTableHeaders -wrap |
    out-string | cat $input
}

Cat here is an alias of powershell's get-content I think, but I frequently use it after writing bash code. I don't think that's the problem. It gives the error:

cat : The input object cannot be bound to any parameters for the command either because the command does not take
+ ... me | Format-Table -HideTableHeaders -wrap | out-string | cat $input }

Trying get-content:

Get-Childitem -Recurse -filter "* *" -Force | foreach-object {
  get-childitem $_ | select-object fullname |
    Format-Table -HideTableHeaders -wrap |
    out-string | Get-Content $input
}

Similar error:

Get-Content : The input object cannot be bound to any parameters for the command either because the command does
not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

I also tried removing out-string.

Searching for the answer to this question is how I arrived at out-string, but it didn't work. I'm curious to know how to do it without assigning a variable if feasible.

2 Answers

Indeed, cat is an alias for Get-Content on Windows.

The only form of pipeline input Get-Content accepts are objects or strings representing file paths, whose content is then output.

This is not what Out-String outputs (it generally outputs a single, multi-line string, which in your case is the string representation of the for-display-formatted output produced by Format-Table).

Based on your comments, you're looking for something like this:

Get-Childitem -Recurse -Directory -Filter "* *" -Force | 
  Get-ChildItem -File |
    Get-Content

As an aside: the automatic $input variable is only defined in specific contexts, and cannot be used as a command argument the way you tried. Specifically, $input represents outside pipeline / stdin input for the entire scope at hand, not what flows through a given pipeline.

See @mklement's answer for how to achieve your end goal. Nothing much I can add on that point he hasn't covered.


However, your understanding of $input is a bit flawed. $input represents the pipeline input passed into a function or ScriptBlock, not the object being passed down the pipeline. You can't reference the pipeline data directly within the same expression, with a slight exception for cmdlets which support $PSItem/$_ like Where-Object or ForEach-Object within their relevant ScriptBlock arguments.

If a cmdlet doesn't take pipeline input, assign what you would have piped to the cmdlet to a variable (or squeeze the expression with () where the parameter would be passed, optionally referencing a property if necessary from the expression result) and call the cmdlet with the previous output as an explicit parameter. @mklement's answer demonstrates this but I'll point it out here as well. For instance:

$files = ( Get-ChildItem $someDir -File ).FullName
Get-Content $files

Alternatively, to insert the expression result directly as a parameter without an intermediary variable:

Get-Content ( Get-ChildItem $someDir -File ).FullName

Additionally, FileInfo objects (the object type of files returned by Get-ChildItem ToStrings to its FullName property, so referencing .FullName here is technically redundant. The following also works:

Get-Content ( Get-ChildItem -File )
Related