Drukowanie właściwości obiektu w programie PowerShell

121

Podczas pracy w konsoli interaktywnej, jeśli zdefiniuję nowy obiekt i przypiszę mu kilka wartości właściwości w następujący sposób:

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

Następnie, kiedy wpiszę nazwę mojej zmiennej w interaktywnym oknie, program PowerShell wyświetli podsumowanie właściwości i wartości obiektu:

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

Zasadniczo chcę to zrobić, ale z poziomu funkcji w skrypcie. Funkcja tworzy obiekt i ustawia niektóre wartości właściwości i chcę, aby przed zwróceniem wydrukowała podsumowanie wartości obiektu w oknie programu PowerShell. Próbowałem użyć Write-Host w funkcji:

Write-Host $obj

Ale to tylko wyświetla typ obiektu, a nie podsumowanie:

System.Object

W jaki sposób mogę sprawić, aby funkcja wyprowadzała podsumowanie wartości właściwości obiektu w oknie programu PowerShell?

Jan
źródło

Odpowiedzi:

188

Spróbuj tego:

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

lub

Write-Host ($obj | Format-List | Out-String)
mjolinor
źródło
4
Musiałem przekazać -Forceparametr, aby działał, np.Write-Host ($obj | Format-List -Force | Out-String)
Bart Verkoeijen
1
Fuj! Nadal wyświetla się poziomo na ekranie ... jeśli jakieś wyjście wychodzi poza twój bufor, po prostu umieszcza .... Mam miłość do nienawiści z POSH
Kolob Canyon
Używając $objs = @();i $objs = $objs + $obj; mogę użyć ConvertTo-Html: $ cols = $ objs | ConvertTo-Html -Fragment -Property Name, DataType, Default, Identity, InPrimaryKey, IsForeignKey, Description;
Kiquenet
33

Moim rozwiązaniem tego problemu było użycie bloku wyrażenia podrzędnego $ () .

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"

Daje:

My name is Bill
This won't work right: Thing.Name
David Peters
źródło
16

Aby wydrukować właściwości i wartości obiektu w programie PowerShell. Poniższe przykłady sprawdzają się u mnie dobrze.

$ 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 * # Możesz pominąć -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
...
kocie oczy
źródło
1
Ostatni wariant tego sprawdził się najlepiej - można go nawet skrócić do $x | select *, świetny do interaktywności.
dualed
Myślę, że to nie działa, jeśli chcesz umieścić to w skrypcie. Jeśli tak, myślę, że musisz zrobić coś więcej niż to, co zostało powiedziane, aby faktycznie wydrukować to na konsoli (np .: Write-Output <something-something>)
Fractal
11

Wskazówka nr 1

Nigdy nie używaj Write-Host.

Porada nr 12

Prawidłowym sposobem wyprowadzania informacji z polecenia cmdlet lub funkcji programu PowerShell jest utworzenie obiektu zawierającego dane, a następnie zapisanie tego obiektu w potoku przy użyciu funkcji Write-Output.

-Don Jones: Mistrz PowerShell

Idealnie byłoby, gdyby twój skrypt utworzył twoje obiekty ( $obj = New-Object -TypeName psobject -Property @{'SomeProperty'='Test'}), a następnie po prostu wykonałby plik Write-Output $objects. Możesz potokować wyjście do Format-Table.

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

Powinni naprawdę wywołać PowerShell PowerObjectandPipingShell.

ZŁO
źródło
4
Dzięki Bob, zaakceptowałem odpowiedź mjolinor, ponieważ wydaje mi się, że odpowiada ona bardziej bezpośrednio na pytanie, jednak wiele nauczyłem się z podanych przez ciebie linków i zgadzam się, że w większości przypadków Write-Host nie jest odpowiedni. Dzięki!
John
1
Ta sama technika zadziała i prawdopodobnie będzie bardziej odpowiednia do stosowania z zapisem-pełnym lub debugowaniem zapisu.
mjolinor
4
Wiem, spóźniłem się wiele lat, ale nie zgadzam się co do Never use Write-Host.stwierdzenia. Nie można używać funkcji Write-Output wewnątrz funkcji zwracających dane, ponieważ spowoduje to „zanieczyszczenie” tej funkcji. Prosty przykład. Zgadnij, jaka funkcja ReturnText wyświetli? Dlatego zawsze używam wewnętrznych funkcji Write-host. function ReturnText () {Write-Output "Some random message" return "What I want to return"}
Denis Molodtsov
3
@DenisMolodtsov Całkowicie się zgadzam. Do celów rejestrowania informacji Write-Output NIGDY nie powinno być używane, chyba że funkcja jest trywialna. Gdy istnieje wiele poziomów funkcji i musisz zwrócić dane wyjściowe, MUSISZ użyć czegoś innego, a Write-Host spełnia rachunek.
RobG
2
Write-Host zostanie również natychmiast skierowany z powrotem z sesji zdalnej, co pozwoli ci zobaczyć postęp, a jeśli sesja zdalna zgłosi błąd, informacja o zapisie i wyjściu zostanie utracona.
RobG
3

Kilka uwag ogólnych.


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

Ta ostatnia pokaże wszystkie nie wewnętrzne, nie wygenerowane przez kompilator właściwości. Pierwsza z nich nie wydaje się (zawsze) pokazywać wszystkich typów właściwości (w moich testach wydaje się, że pokazuje to CodeProperty MemberTypekonsekwentnie - tutaj nie ma gwarancji).


Niektóre przełączniki, o których należy pamiętać w przypadku Get-Member

  • Get-Memberma nie dostać elementy statyczne domyślnie. Nie możesz również (bezpośrednio) uzyskać ich razem z niestatycznymi członkami. Oznacza to, że użycie przełącznika powoduje zwrócenie tylko statycznych elementów członkowskich:

    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)
    ...
  • Użyj -Force.

    Get-MemberKomenda używa Mocy parametr dodać swoistych członków i kompilatora generowane z obiektów na ekranie. Get-Memberpobiera tych członków, ale domyślnie ich ukrywa.

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

Używaj ConvertTo-Jsondo dokładnej i czytelnej „serializacji”

Ja nie niezbędne polecić zapisywanie obiektów za pomocą JSON (stosowanie Export-Clixmlzamiast). Można jednak uzyskać mniej lub bardziej czytelne dane wyjściowe ConvertTo-Json, co pozwala również określić głębokość.

Zauważ, że brak określenia Depthoznacza-Depth 2

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

A jeśli nie planujesz tego czytać, możesz to -Compresszrobić (tj. Usuń spacje)

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

Użyj, -InputObjectjeśli możesz (i chcesz)

99,9% czasu podczas korzystania z PowerShell: albo wydajność nie ma znaczenia, albo nie przejmujesz się wydajnością. Jednakże , należy zauważyć, że unikanie rurę, kiedy nie potrzeba może zaoszczędzić trochę napowietrznych i dodać trochę prędkości (rurociągi, ogólnie rzecz biorąc, nie jest super-wydajny).

Oznacza to, że jeśli masz wszystko, co masz, to jedna $objporęczna do drukowania (i nie jesteś tak leniwy jak ja, żeby czasami pisać -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

Uwaga na Get-Member -InputObject: jeśli $ obj jest kolekcją (np. System.Object[]), W końcu uzyskujesz informacje o samym obiekcie kolekcji:

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

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

Jeśli chcesz Get-Memberdla każdego TypeNamew kolekcji (uwaga dla każdego TypeName, nie dla każdego obiektu - zbiór N obiektów z takimi samymi TypeNamewypisuje tylko 1 tabelę TypeName, a nie N tabel dla każdego obiektu) ...... po prostu trzymaj się go bezpośrednio.

YenForYang
źródło
1

Poniższe działały naprawdę dobrze dla mnie. Poprawiłem wszystkie powyższe odpowiedzi oraz przeczytałem o wyświetlaniu właściwości obiektów w poniższym linku i wymyśliłem poniżej krótką lekturę o drukowaniu obiektów

dodaj następujący tekst do pliku o nazwie print_object.ps1:

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

otwórz wiersz polecenia powershell, przejdź do katalogu, w którym istnieje ten plik i wpisz:

powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated

Po prostu zastąp „System.DateTime” dowolnym obiektem, który chcesz wydrukować. Jeśli obiekt jest pusty, nic nie zostanie wydrukowane.

Fraktal
źródło
0
# Json to object
$obj = $obj | ConvertFrom-Json
Write-host $obj.PropertyName
Ramanujam Allam
źródło