PortMan
PortMan

Reputation: 4523

Write-Host strips newline characters where Write-Output does not

The command $output = Invoke-Expression "cfn-lint *.yaml" gives me an array for $output:

$output.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Write-Output $output gives me this nice output:

Write-Output $output
W2506 Parameter AMIID should be of type [AWS::EC2::Image::Id, 
AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>]
trace3-ec2-virtual-machine-creation.yaml:27:3

W2001 Parameter VpcId not used.
trace3-ec2-virtual-machine-creation.yaml:32:3

But Write-Host $output gives me a version with all the newlines stripped out:

Write-Host $output                                                                                                                                                                                                                
W2506 Parameter AMIID should be of type [AWS::EC2::Image::Id, AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>] trace3-ec2-virtual-machine-creation.yaml:27:3  W2001 Parameter VpcId not used. trace3-ec2-virtual-machine-creation.yaml:32:3

Why is it doing this?

I know that I can get around this with the call Write-Host ($output | Out-String), but I don't understand why that works.

Upvotes: 0

Views: 632

Answers (1)

Santiago Squarzon
Santiago Squarzon

Reputation: 60045

Write-Output takes [-InputObject] <PSObject[]> as argument while Write-Host takes [[-Object] <Object>] as argument.

Write-Output returns the objects that are submitted as input.

Write-Host sends the objects to the host. It does not return any objects. However, the host displays the objects that Write-Host sends to it.

As you can see, Write-Ouput takes an array of PSObject as Input parameter and returns the same array as Output.

Out-String works fine with Write-Host because it is converting your array to a multiline string hence Write-Host will return it as literal to the Information Stream while without the Out-String it is taking all lines of your array and joining them into a single line string.

PS /> $test = @(
    'this is a'
    'test'
)

$writeHost = Write-Host -Object $test 6>&1
$writeOutput = Write-Output -Object $test

$writeHost.GetType()
$writeOutput.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                       
-------- -------- ----                                     --------                                                                                                       
True     False    InformationRecord                        System.Object                                                                                                  
True     True     Object[]                                 System.Array

Edit

Following your comment, I don't know for sure why, I couldn't find any relevant information on MS Docs for the cmdlet but we can assume it is doing some sort of manipulation on the input objects. We do know that Write-Host is a wrapper for Write-Information.

Take this function as an example, it receives a [object] in this case it receives an array with 2 items as input and writes to the information stream a string representation of it's input:

$test = @(
    'this is a'
    'test'
)

function TestString ([object]$String) {
    Write-Information ([string]$String) -InformationAction Continue
}

PS /> TestString $test
this is a test

Upvotes: 1

Related Questions