Search code examples
powershellpowershell-4.0powershell-remotinginvoke-command

Formatting Output with Invoke-Command


I'm trying to format my output to look like so

PSComputerName       Value
--------------       ------
Computer1           Restricted
Computer2           Unrestricted
Computer3           Unrestricted

This is my code the variable $computers points to Get-Content of a file with computer names that I will be connecting to remotely

$test = Invoke-Command -ComputerName $computers -ScriptBlock {
$policy3 = Get-ExecutionPolicy 
Write-Output $policy3
}
write $test 

The output

PSComputerName             RunspaceId                 Value                     
--------------             ----------                 -----                     
Computer1                    7e4ebfbe-62d3-4035-9d5a... Restricted                
Computer2                    2ecd6932-1ed4-4f57-b9e9... Unrestricted              
Computer3                    73a119de-5d6d-4525-9958... Restricted                

I've been trying to get rid of the RunSpaceId by echoing the invoke-command and doing a foreach of the computer names, I only did PSComputerNames to test if it would work.

write $test % {$_.PSComputerName }

I know that Invoke-Command has a foreach function built in it but I don't know how to use to my advantage in this situation. What is the best way to achieve my desired output?


Solution

  • PS> Invoke-Command $computers { Get-ExecutionPolicy } |
          Format-Table PSComputerName, Value
    
    PSComputerName  Value                     
    --------------  -----                     
    Computer1       Restricted                
    ...
    

    As BACON points out in comments on the question, it is Invoke-Command that implicitly adds the PSComputerName and RunSpaceId properties to the objects returned by the script block ({ ... }) run on each target computer, and whether they are displayed by default depends on the type of the object returned.
    In the case of the [Microsoft.PowerShell.ExecutionPolicy] instances returned by Get-ExecutionPolicy, they are displayed by default, which means that in order to display only the properties of interest you need an explicit Format-* call.

    Note that an automatically added Value property is an artifact of the remotely executed script block returning an instance of an [enum]-derived type, such as the instances of [Microsoft.PowerShell.ExecutionPolicy] returned by Get-ExecutionPolicy.

    Remotely invoked Invoke-Command script blocks outputting non-primitive-.NET-type instances return deserialized objects of type Deserialized.<original-type-name>.
    [enum]-derived instances result in a deserialized type with a Value property defined as a ScriptProperty member with signature System.Object Value {get=$this.ToString();}; for general information about how serialization and deserialization works in PowerShell remoting and background jobs, see this answer.


    General tips:

    • Write-Output is generally not needed, because the output of any statement that is not captured in a variable or redirected to a file / to $null is implicitly sent to the output stream.

    • If you ever need to write cross-platform-compatible code, avoid aliases such as write, because they won't work as expected on Unix-like platforms in PowerShell Core, where aliases that would shadow native utilities aren't defined.