การพิมพ์คุณสมบัติของวัตถุใน Powershell


121

เมื่อทำงานในคอนโซลแบบโต้ตอบถ้าฉันกำหนดวัตถุใหม่และกำหนดค่าคุณสมบัติบางอย่างให้เป็นดังนี้:

$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)
Bart Verkoeijen

1
ฮึ มันยังคงแสดงในแนวนอนบนหน้าจอ .... หากเอาต์พุตใด ๆ ออกไปนอกบัฟเฟอร์ของคุณมันก็วาง...ไว้ ฉันมีความรักเกลียด POSH
Kolob Canyon

การใช้$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 = รับรายการ "IIS: \ AppPools.NET v4.5"

$ พูล | ได้รับการบริการสมาชิก

   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 *เหมาะสำหรับการโต้ตอบ
ดวล

ฉันไม่คิดว่าจะได้ผลถ้าต้องการใส่ไว้ในสคริปต์ ถ้าเป็นเช่นนั้นฉันคิดว่าคุณต้องทำอะไรเพิ่มเติมซึ่งสิ่งที่ระบุไว้เพื่อที่จะพิมพ์ลงในคอนโซลได้จริง (เช่น: Write-Output <something-something>)
Fractal

11

เคล็ดลับ # 1

ห้ามใช้ Write-Host

เคล็ดลับ # 12

วิธีที่ถูกต้องในการส่งออกข้อมูลจาก PowerShell cmdlet หรือฟังก์ชันคือการสร้างออบเจ็กต์ที่มีข้อมูลของคุณจากนั้นจึงเขียนวัตถุนั้นไปยังท่อโดยใช้ Write-Output

- ดอนโจนส์: PowerShell Master

ตามหลักการแล้วสคริปต์ของคุณจะสร้างวัตถุของคุณ ( $obj = New-Object -TypeName psobject -Property @{'SomeProperty'='Test'}) จากนั้นทำไฟล์Write-Output $objects. Format-Tableคุณจะท่อออกไป

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

พวกเขาควรเรียก PowerShell PowerObjectandPipingShell


4
ขอบคุณ Bob ฉันยอมรับคำตอบของ mjolinor แล้วเพราะฉันรู้สึกว่ามันตอบคำถามได้ตรงกว่า แต่ฉันได้เรียนรู้มากมายจากลิงก์ที่คุณให้มาและยอมรับว่าในกรณีส่วนใหญ่ Write-Host ไม่เหมาะสม ขอบคุณ!
John

1
เทคนิคเดียวกันนี้จะใช้ได้ผลและน่าจะเหมาะกว่าเมื่อใช้กับ Write-Verbose หรือ Write-Debug
mjolinor

4
ฉันรู้ว่าฉันมาช้าไปหลายปี แต่ฉันไม่เห็นด้วยกับNever use Write-Host.คำชี้แจง คุณไม่สามารถใช้ฟังก์ชัน Write-Output ภายในที่ส่งคืนข้อมูลได้เนื่องจากจะทำให้ฟังก์ชันนี้ "ก่อมลพิษ" ตัวอย่างง่ายๆ เดาว่าฟังก์ชัน ReturnText จะส่งออกอะไร? นี่คือเหตุผลที่ฉันใช้ฟังก์ชัน Write-host ภายในเสมอ function ReturnText () {Write-Output "Some random message" return "What I want to return"}
Denis Molodtsov

3
@DenisMolodtsov ฉันเห็นด้วยอย่างยิ่ง เพื่อวัตถุประสงค์ในการบันทึกข้อมูลไม่ควรใช้ Write-Output เว้นแต่ว่าฟังก์ชันจะไม่สำคัญ เมื่อมีหลายระดับฟังก์ชันและคุณต้องการส่งคืนผลลัพธ์คุณต้องใช้อย่างอื่นและ Write-Host ตรงตามใบเรียกเก็บเงิน
RobG

2
Write-Host จะถูกส่งกลับทันทีจากเซสชันระยะไกลเพื่อให้คุณเห็นความคืบหน้าและหากเซสชันระยะไกลแสดงข้อผิดพลาดข้อมูลการเขียนผลลัพธ์จะสูญหาย
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คำสั่งใช้กองทัพพารามิเตอร์ที่จะเพิ่มสมาชิกภายในและสมาชิกคอมไพเลอร์ที่สร้างจากวัตถุที่จะแสดงผล 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ไม่ยังไม่มีตารางสำหรับแต่ละวัตถุ) ...... เพียงแค่ติดกับท่อโดยตรง


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' ด้วยวัตถุที่คุณต้องการพิมพ์ ถ้าวัตถุเป็นโมฆะจะไม่มีอะไรพิมพ์ออกมา


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.