Powershell – Format-List in Powershell-Function not working

powershell

i want to use format-list inside a function in a powershell script to have some nice-formatted output. But when I use it, it simply doesn't print anything. In this thread the author had the same problem. He was told not to call fl inside a function, but pipe the result back to main and output there.

Piping the results back to the caller sounds like a good idea, sure.

But what if functions are nested + already have a return value?

I want to output Certificate-Information for an sslstream. To do this, I have to use a custom Callback-Function for Validation. In this Callback-Function, the Certificate-Chain is available (and should be printed to screen). The Function is required to return $true

Simplified:

function write-CertDetails([System.Security.Cryptography.X509Certificates.X509Certificate]$cert){
    #perform some conversions etc... e.g.:
    $certprops = new-object psobject
    $certprops | Add-Member -MemberType NoteProperty -Name "FriendlyName" -Value $Cert.FriendlyName
    $certprops | Add-Member -MemberType NoteProperty -Name "SubjectName" -Value $Cert.SubjectName

    $certprops | fl #this does not work!
}

[System.Net.Security.RemoteCertificateValidationCallback] $CertValCallback = {
param($sender, $certificate, $chain, $sslPolicyErrors)
    for($i = $chain.ChainElements.Count; $i-- -gt 0; ){
        write-CertDetails $currElement.Certificate
    }
    $true
}

# Create a TCP-Connection, open it in $tcpstream
Pseudo: $tcpstream = new-Object tcpConnection($host)
# now SSL/TLS-Handshake is performed. This calls the CertValCallback (which has to return true). New SslStream-Object is returned.
$sslStream = New-Object System.Net.Security.SslStream($tcpstream,$false,$CertValCallback)

I have no idea, how I should get the $certprops-Collection back to Main-Function…

Thanks for your Help

Filipp

Best Answer

Hm this is tricky. I agree with the assertion that you should not use Format- cmdlets in functions, and should let the caller work with the objects.

But if the information is only available as a callback, you don't have control of the caller nor the function definition nor the parameters getting passed in so you can't really workaround much of this to get a value back to your code. So I'm assuming writing to the screen really is the only option here.

The reason piping the value to fl doesn't work in the function, is that the Format- cmdlets don't actually write anything to the screen. They merely format the output. Typically in a function those format objects get returned, and returned from whatever function called that function, and so on. Eventually if you're not in a function anymore, the objects are written to the screen by the host.

To see how this differs from explicitly writing to the host, consider $v = $obj | Format-List vs $v = Write-Host $obj. The latter will write $obj to the screen and $v will be empty/null. The former will output nothing to the screen and $v will contain the format object(s).

So to answer your question, you can try this:

$certprops | Format-List | Out-Host

That should force it out to the host without returning anything, so it won't mess with the callback's return value. Write-Host in this case wouldn't work because it would just display the class name.