ChatGPT解决这个技术问题 Extra ChatGPT

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?


m
mjolinor

Try this:

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

or

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

I had to pass the -Force parameter to make it work, e.g. Write-Host ($obj | Format-List -Force | Out-String)
Ugh! It still displays horizontally on the screen.... if any output goes outside your buffer it just puts .... I have a love hate with POSH
Using $objs = @(); and $objs = $objs + $obj; I can use ConvertTo-Html : $cols = $objs | ConvertTo-Html -Fragment -Property Name, DataType, Default, Identity, InPrimaryKey, IsForeignKey, Description;
This is perfect for debugging purposes as well, using Write-Debug ($obj | Format-Table | Out-String) :)
D
David Peters

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

c
cateyes

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
...

Last variant of this worked for me best - can even shorten it to $x | select *, great for interactive.
I don't think this works if want to put it in a script. If so, I think you have to do something additional that what is stated in order to actually print it to the console (ie: Write-Output )
E
E.V.I.L.

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.


Thanks Bob, I have accepted mjolinor's answer as I feel it answers the question more directly, however I learned a lot from the links you provided and agree that in most cases Write-Host is not suitable. Thanks!
The same technique will work, and would probably be more suitable used with Write-Verbose or Write-Debug.
I know, I'm many years late, but I disagree about Never use Write-Host. statement. You cannot use Write-Output inside functions that return data, because it will "pollute" this function. Simple example. Guess what ReturnText function will output? This is why I always use Write-host inside functions. function ReturnText(){ Write-Output "Some random message" return "What I want to return" }
@DenisMolodtsov I completely agree. For the purpose of logging information Write-Output should NEVER be used unless the Function is trivial. Once there is multiple function levels and you need to return output you MUST use something else, and Write-Host meets the bill.
Write-Host will also be immediately channeled back from a remote session allowing you to see progress, and if a remote session throws an error Write-Output information is lost.
Y
YenForYang

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.


F
Fractal

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.


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