[powershell] Printing object properties in Powershell

When working in the interactive console if I define a new object and assign some property values to it like this:

$obj = New-Object System.String
$obj | Add-Member NoteProperty SomeProperty "Test"

Then when I type the name of my variable into the interactive window Powershell gives me a summary of the object properties and values:

PS C:\demo> $obj
SomeProperty                                                                                                                                                                                  
------------                                                                                                                                                                                  
Test

I basically want to do just this but from within a function in a script. The function creates an object and sets some property values and I want it to print out a summary of the object values to the Powershell window before returning. I tried using Write-Host within the function:

Write-Host $obj

But this just output the type of the object not the summary:

System.Object

How can I have my function output a summary of the object's property values to the Powershell window?

This question is related to powershell

The answer is


Try this:

Write-Host ($obj | Format-Table | Out-String)

or

Write-Host ($obj | Format-List | Out-String)

To print out object's properties and values in Powershell. Below examples work well for me.

$pool = Get-Item "IIS:\AppPools.NET v4.5"

$pool | Get-Member

   TypeName: Microsoft.IIs.PowerShell.Framework.ConfigurationElement#system.applicationHost/applicationPools#add

Name                        MemberType            Definition
----                        ----------            ----------
Recycle                     CodeMethod            void Recycle()
Start                       CodeMethod            void Start()
Stop                        CodeMethod            void Stop()
applicationPoolSid          CodeProperty          Microsoft.IIs.PowerShell.Framework.CodeProperty
state                       CodeProperty          Microsoft.IIs.PowerShell.Framework.CodeProperty
ClearLocalData              Method                void ClearLocalData()
Copy                        Method                void Copy(Microsoft.IIs.PowerShell.Framework.ConfigurationElement ...
Delete                      Method                void Delete()
...

$pool | Select-Object -Property * # You can omit -Property

name                        : .NET v4.5
queueLength                 : 1000
autoStart                   : True
enable32BitAppOnWin64       : False
managedRuntimeVersion       : v4.0
managedRuntimeLoader        : webengine4.dll
enableConfigurationOverride : True
managedPipelineMode         : Integrated
CLRConfigFile               :
passAnonymousToken          : True
startMode                   : OnDemand
state                       : Started
applicationPoolSid          : S-1-5-82-271721585-897601226-2024613209-625570482-296978595
processModel                : Microsoft.IIs.PowerShell.Framework.ConfigurationElement
...

Some general notes.


$obj | Select-Object ? $obj | Select-Object -Property *

The latter will show all non-intrinsic, non-compiler-generated properties. The former does not appear to (always) show all Property types (in my tests, it does appear to show the CodeProperty MemberType consistently though -- no guarantees here).


Some switches to be aware of for Get-Member

  • Get-Member does not get static members by default. You also cannot (directly) get them along with the non-static members. That is, using the switch causes only static members to be returned:

    PS Y:\Power> $obj | Get-Member -Static
    
       TypeName: System.IsFire.TurnUpProtocol
    
    Name        MemberType Definition
    ----        ---------- ----------
    Equals      Method     static bool Equals(System.Object objA, System.Object objB)
    ...
    
  • Use the -Force.

    The Get-Member command uses the Force parameter to add the intrinsic members and compiler-generated members of the objects to the display. Get-Member gets these members, but it hides them by default.

    PS Y:\Power> $obj | Get-Member -Static
    
       TypeName: System.IsFire.TurnUpProtocol
    
    Name          MemberType     Definition
    ----          ----------     ----------
    ...
    pstypenames   CodeProperty   System.Collections.ObjectModel.Collection...
    psadapted     MemberSet      psadapted {AccessRightType, AccessRuleType,...
    ...
    

Use ConvertTo-Json for depth and readable "serialization"

I do not necessary recommend saving objects using JSON (use Export-Clixml instead). However, you can get a more or less readable output from ConvertTo-Json, which also allows you to specify depth.

Note that not specifying Depth implies -Depth 2

PS Y:\Power> ConvertTo-Json $obj -Depth 1
{
    "AllowSystemOverload":  true,
    "AllowLifeToGetInTheWay":  false,
    "CantAnyMore": true,
    "LastResortOnly": true,
...

And if you aren't planning to read it you can -Compress it (i.e. strip whitespace)

PS Y:\Power> ConvertTo-Json $obj -Depth 420 -Compress

Use -InputObject if you can (and are willing)

99.9% of the time when using PowerShell: either the performance won't matter, or you don't care about the performance. However, it should be noted that avoiding the pipe when you don't need it can save some overhead and add some speed (piping, in general, is not super-efficient).

That is, if you all you have is a single $obj handy for printing (and aren't too lazy like me sometimes to type out -InputObject):

# select is aliased (hardcoded) to Select-Object
PS Y:\Power> select -Property * -InputObject $obj
# gm is aliased (hardcoded) to Get-Member
PS Y:\Power> gm -Force -InputObject $obj

Caveat for Get-Member -InputObject: If $obj is a collection (e.g. System.Object[]), You end up getting information about the collection object itself:

PS Y:\Power> gm -InputObject $obj,$obj2
   TypeName: System.Object[]

Name        MemberType            Definition
----        ----------            ----------
Count       AliasProperty         Count = Length
...

If you want to Get-Member for each TypeName in the collection (N.B. for each TypeName, not for each object--a collection of N objects with all the same TypeName will only print 1 table for that TypeName, not N tables for each object)......just stick with piping it in directly.


The below worked really good for me. I patched together all the above answers plus read about displaying object properties in the following link and came up with the below short read about printing objects

add the following text to a file named print_object.ps1:

$date = New-Object System.DateTime
Write-Output $date | Get-Member
Write-Output $date | Select-Object -Property *

open powershell command prompt, go to the directory where that file exists and type the following:

powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated

Just substitute 'System.DateTime' with whatever object you wanted to print. If the object is null, nothing will print out.


My solution to this problem was to use the $() sub-expression block.

Add-Type -Language CSharp @"
public class Thing{
    public string Name;
}
"@;

$x = New-Object Thing

$x.Name = "Bill"

Write-Output "My name is $($x.Name)"
Write-Output "This won't work right: $x.Name"

Gives:

My name is Bill
This won't work right: Thing.Name

# Json to object
$obj = $obj | ConvertFrom-Json
Write-host $obj.PropertyName

Tip #1

Never use Write-Host.

Tip #12

The correct way to output information from a PowerShell cmdlet or function is to create an object that contains your data, and then to write that object to the pipeline by using Write-Output.

-Don Jones: PowerShell Master

Ideally your script would create your objects ($obj = New-Object -TypeName psobject -Property @{'SomeProperty'='Test'}) then just do a Write-Output $objects. You would pipe the output to Format-Table.

PS C:\> Run-MyScript.ps1 | Format-Table

They should really call PowerShell PowerObjectandPipingShell.