Печать свойств объекта в Powershell


122

Если при работе в интерактивной консоли я определяю новый объект и присваиваю ему некоторые значения свойств следующим образом:

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

Затем, когда я ввожу имя своей переменной в интерактивное окно, Powershell дает мне сводку свойств и значений объекта:

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

Я в основном хочу сделать это, но из функции скрипта. Функция создает объект и устанавливает некоторые значения свойств, и я хочу, чтобы он распечатал сводку значений объекта в окне Powershell перед возвратом. Я пробовал использовать Write-Host в функции:

Write-Host $obj

Но это просто выводит тип объекта, а не сводку:

System.Object

Как сделать так, чтобы моя функция выводила сводку значений свойств объекта в окно Powershell?

Ответы:


188

Попробуй это:

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

или

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

4
Мне пришлось передать -Forceпараметр, чтобы он работал, напримерWrite-Host ($obj | Format-List -Force | Out-String)
Барт Веркойен 01

1
Тьфу! Он по-прежнему отображается на экране горизонтально .... если какой-либо вывод выходит за пределы вашего буфера, он просто помещается .... Я ненавижу POSH
Каньон Колоб

Используя $objs = @();и $objs = $objs + $obj; я могу использовать ConvertTo-Html: $ cols = $ objs | ConvertTo-Html -Fragment -Property Name, DataType, Default, Identity, InPrimaryKey, IsForeignKey, Description;
Kiquenet

33

Мое решение этой проблемы заключалось в использовании блока подвыражения $ () .

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"

дает:

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

16

Чтобы распечатать свойства и значения объекта в Powershell. Примеры ниже подходят мне.

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

$ бассейн | 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()
...

$ бассейн | Select-Object -Property * # Вы можете опустить -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
...

1
Последний вариант этого сработал для меня лучше всего - можно даже сократить его до $x | select *, отлично подходит для интерактивного.
Duled

Я не думаю, что это сработает, если захочется поместить это в сценарий. Если это так, я думаю, вам нужно сделать что-то еще, помимо заявленного, чтобы фактически распечатать это на консоли (например: Write-Output <something-something>)
Fractal

11

Совет # 1

Никогда не используйте Write-Host.

Совет № 12

Правильный способ вывода информации из командлета или функции PowerShell - создать объект, содержащий ваши данные, а затем записать этот объект в конвейер с помощью Write-Output.

-Дон Джонс: Мастер PowerShell

В идеале ваш сценарий должен создавать ваши объекты ( $obj = New-Object -TypeName psobject -Property @{'SomeProperty'='Test'}), а затем просто выполнять Write-Output $objects. Вы должны направить вывод в Format-Table.

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

Им действительно следует называть PowerShell PowerObjectandPipingShell.


4
Спасибо, Боб, я принял ответ mjolinor, так как считаю, что он отвечает на вопрос более прямо, однако я многому научился из предоставленных вами ссылок и согласен с тем, что в большинстве случаев Write-Host не подходит. Спасибо!
Джон

1
Тот же самый метод будет работать и, вероятно, будет более подходящим для использования с Write-Verbose или Write-Debug.
mjolinor 03

4
Я знаю, я опоздал на много лет, но я не согласен с Never use Write-Host.утверждением. Вы не можете использовать Write-Output внутри функций, возвращающих данные, потому что это «загрязнит» эту функцию. Простой пример. Угадайте, что будет выводить функция ReturnText? Вот почему я всегда использую внутри функций Write-host. function ReturnText () {Write-Output "Some random message" return "What I want to return"}
Денис Молодцов

3
@DenisMolodtsov Полностью согласен. Для записи информации в журнал НИКОГДА не следует использовать функцию записи-вывода, если только функция не является тривиальной. Если есть несколько уровней функций и вам нужно вернуть вывод, вы ДОЛЖНЫ использовать что-то еще, и Write-Host отвечает всем требованиям.
RobG

2
Write-Host также будет немедленно перенаправлен обратно из удаленного сеанса, что позволит вам видеть прогресс, и если удаленный сеанс выдает ошибку, информация Write-Output теряется.
RobG

3

Несколько общих замечаний.


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

Последний покажет все не внутренние, не созданные компилятором свойства. Первый, похоже, не (всегда) показывает все типы свойств (в моих тестах он, похоже, показывает CodeProperty MemberTypeпоследовательно - здесь нет никаких гарантий).


Некоторые переключатели, о которых следует знать для Get-Member

  • Get-Memberникак не получить статические члены по умолчанию. Вы также не можете (напрямую) получить их вместе с нестатическими членами. То есть использование переключателя приводит к возврату только статических членов:

    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)
    ...
  • Используйте расширение -Force.

    Команда Get-Memberиспользует параметр Force для добавления внутренних членов и созданных компилятором членов объектов к отображению. Get-Memberполучает эти члены, но по умолчанию скрывает их.

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

Используйте ConvertTo-Jsonдля глубины и удобочитаемой "сериализации"

Я не рекомендую сохранять объекты с помощью JSON (используйте Export-Clixmlвместо этого). Однако вы можете получить более или менее читаемый вывод ConvertTo-Json, который также позволяет указать глубину.

Обратите внимание, что отсутствие указания Depthподразумевает-Depth 2

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

И если вы не планируете его читать, вы можете -Compressэто (т.е. убрать пробелы)

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

Используйте, -InputObjectесли можете (и хотите)

В 99,9% случаев при использовании PowerShell: либо производительность не имеет значения, либо вы не заботитесь о производительности. Однако следует отметить, что отказ от канала, когда он вам не нужен, может сэкономить некоторые накладные расходы и добавить некоторую скорость (трубопровод, как правило, не сверхэффективен).

То есть, если у вас есть все, что у вас есть, это единственный $objудобный для печати (и не слишком ленив, как я иногда, чтобы печатать -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

Предостережение Get-Member -InputObject: если $ obj является коллекцией (например System.Object[]), вы получите информацию о самом объекте коллекции:

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

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

Если вы хотите Get-Memberдля каждого TypeNameв коллекции (NB для каждого TypeName, а не для каждого объекта - набор из N объектов со всеми одинаковыми TypeNameбудет печатать только 1 таблицу для этого TypeName, а не N таблиц для каждого объекта) ...... просто вставьте его напрямую.


1

Приведенное ниже сработало для меня очень хорошо. Я исправил все вышеперечисленные ответы, а также прочитал об отображении свойств объекта по следующей ссылке и придумал ниже краткое прочтение о печати объектов

добавьте следующий текст в файл с именем print_object.ps1:

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

откройте командную строку PowerShell, перейдите в каталог, в котором существует этот файл, и введите следующее:

powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated

Просто замените System.DateTime на любой объект, который вы хотите напечатать. Если объект равен нулю, ничего не распечатывается.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.