In thuộc tính đối tượng trong Powershell


119

Khi làm việc trong bảng điều khiển tương tác nếu tôi xác định một đối tượng mới và gán một số giá trị thuộc tính cho nó như sau:

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

Sau đó, khi tôi nhập tên biến của mình vào cửa sổ tương tác, Powershell cung cấp cho tôi bản tóm tắt về các thuộc tính và giá trị của đối tượng:

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

Về cơ bản tôi chỉ muốn làm điều này nhưng từ bên trong một hàm trong tập lệnh. Hàm tạo một đối tượng và đặt một số giá trị thuộc tính và tôi muốn nó in ra một bản tóm tắt các giá trị đối tượng vào cửa sổ Powershell trước khi trả về. Tôi đã thử sử dụng Write-Host trong hàm:

Write-Host $obj

Nhưng điều này chỉ xuất ra loại đối tượng không phải là tóm tắt:

System.Object

Làm cách nào để hàm của tôi xuất ra bản tóm tắt các giá trị thuộc tính của đối tượng vào cửa sổ Powershell?

Câu trả lời:


186

Thử cái này:

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

hoặc là

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

4
Tôi đã phải vượt qua các -Forcetham số để làm cho nó làm việc, ví dụWrite-Host ($obj | Format-List -Force | Out-String)
Bart Verkoeijen

1
Ặc! Nó vẫn hiển thị theo chiều ngang trên màn hình .... nếu bất kỳ đầu ra nào nằm ngoài bộ đệm của bạn, nó sẽ đặt .... Tôi có một tình yêu ghét với Posh
Kolob Canyon

Sử dụng $objs = @();$objs = $objs + $obj; tôi có thể sử dụng ConvertTo-Html: $ cols = $ objs | ConvertTo-Html -Fragment -Tên thuộc tính, Kiểu dữ liệu, Mặc định, Danh tính, InPrimaryKey, IsForeignKey, Mô tả;
Kiquenet

32

Giải pháp của tôi cho vấn đề này là sử dụng khối biểu thức con $ () .

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"

Cung cấp:

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

16

Để in ra các thuộc tính và giá trị của đối tượng trong Powershell. Các ví dụ dưới đây hoạt động tốt cho tôi.

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

$ pool | Nhận thành viên

   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 * # Bạn có thể bỏ qua -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
Biến thể cuối cùng của điều này phù hợp nhất với tôi - thậm chí có thể rút ngắn nó thành $x | select *, tuyệt vời để tương tác.
kép

Tôi không nghĩ điều này hiệu quả nếu muốn đưa nó vào một kịch bản. Nếu vậy, tôi nghĩ rằng bạn cần phải làm điều gì đó bổ sung những gì được nêu để thực sự in nó ra cửa sổ Console (ví dụ: Write-Output <something-something>)
Fractal

11

Mẹo số 1

Không bao giờ sử dụng Write-Host.

Mẹo # 12

Cách chính xác để xuất thông tin từ lệnh ghép ngắn hoặc hàm PowerShell là tạo một đối tượng có chứa dữ liệu của bạn, sau đó ghi đối tượng đó vào đường dẫn bằng cách sử dụng Write-Output.

-Don Jones: Bậc thầy PowerShell

Lý tưởng nhất là script của bạn sẽ tạo các đối tượng của bạn ( $obj = New-Object -TypeName psobject -Property @{'SomeProperty'='Test'}) sau đó chỉ cần thực hiện a Write-Output $objects. Bạn sẽ chuyển đầu ra tới Format-Table.

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

Họ thực sự nên gọi PowerShell PowerObjectandPipingShell.


4
Cảm ơn Bob, tôi đã chấp nhận câu trả lời của mjolinor vì tôi cảm thấy nó trả lời câu hỏi trực tiếp hơn, tuy nhiên tôi đã học được nhiều điều từ các liên kết mà bạn cung cấp và đồng ý rằng trong hầu hết các trường hợp, Write-Host không phù hợp. Cảm ơn!
John

1
Kỹ thuật tương tự sẽ hoạt động và có lẽ sẽ phù hợp hơn khi sử dụng với Write-Verbose hoặc Write-Debug.
mjolinor

4
Tôi biết, tôi đã trễ nhiều năm, nhưng tôi không đồng ý về Never use Write-Host.tuyên bố. Bạn không thể sử dụng Write-Output bên trong các hàm trả về dữ liệu, vì nó sẽ "gây ô nhiễm" cho hàm này. Ví dụ đơn giản. Đoán xem hàm ReturnText sẽ xuất gì? Đây là lý do tại sao tôi luôn sử dụng các hàm bên trong Write-host. chức năng ReturnText () {Viết-Output "Một số thông điệp ngẫu nhiên" trở lại "Những gì tôi muốn quay trở lại"}
Denis Molodtsov

3
@DenisMolodtsov Tôi hoàn toàn đồng ý. Đối với mục đích ghi thông tin Ghi-Đầu ra KHÔNG BAO GIỜ được sử dụng trừ khi Chức năng là tầm thường. Một khi có nhiều mức chức năng và bạn cần trả lại đầu ra, bạn PHẢI sử dụng thứ khác, và Write-Host đáp ứng được hóa đơn.
RobG

2
Write-Host cũng sẽ được chuyển ngay lập tức trở lại từ một phiên từ xa cho phép bạn xem tiến trình, và nếu một phiên từ xa gây ra lỗi, thông tin Ghi-Đầu ra sẽ bị mất.
RobG

3

Một số lưu ý chung.


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

Cái sau sẽ hiển thị tất cả các thuộc tính không phải nội tại, không do trình biên dịch tạo ra. Trước đây dường như không (luôn luôn) hiển thị tất cả các loại Thuộc tính (trong các thử nghiệm của tôi, nó dường như hiển thị CodeProperty MemberTypemặc dù nhất quán - không đảm bảo ở đây).


Một số điểm chuyển đổi cần lưu ý đối với Get-Member

  • Get-Memberkhông không có được các thành viên tĩnh theo mặc định. Bạn cũng không thể (trực tiếp) làm cho chúng cùng với các thành viên không tĩnh. Đó là, việc sử dụng switch chỉ trả về các thành viên tĩnh:

    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)
    ...
  • Sử dụng -Force.

    Các Get-Memberlệnh sử dụng Force tham số để thêm các thành viên nội tại và các thành viên biên dịch tạo ra các đối tượng để hiển thị. Get-Membernhận được các thành viên này, nhưng nó ẩn chúng theo mặc định.

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

Sử dụng ConvertTo-Jsoncho độ sâu và "tuần tự hóa" có thể đọc được

Tôi không cần thiết, khuyên bạn nên lưu các đối tượng bằng JSON (sử dụng Export-Clixmlthay thế). Tuy nhiên, bạn có thể nhận được nhiều hơn hoặc ít hơn đầu ra có thể đọc được ConvertTo-Json, điều này cũng cho phép bạn chỉ định độ sâu.

Lưu ý rằng không chỉ định Depthngụ ý-Depth 2

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

Và nếu bạn không định đọc nó, bạn có thể đọc -Compressnó (tức là loại bỏ khoảng trắng)

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

Sử dụng -InputObjectnếu bạn có thể (và sẵn lòng)

99,9% thời gian khi sử dụng PowerShell: hiệu suất sẽ không thành vấn đề hoặc bạn không quan tâm đến hiệu suất. Tuy nhiên , cần lưu ý rằng tránh sử dụng đường ống khi bạn không cần thiết có thể tiết kiệm một số chi phí và tăng thêm một số tốc độ (đường ống, nói chung, không phải là siêu hiệu quả).

Đó là, nếu tất cả những gì bạn có là một $objtiện ích để in (và đôi khi không quá lười biếng như tôi để gõ ra -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

Lưu ý Get-Member -InputObject: Nếu $ obj là một bộ sưu tập (ví dụ System.Object[]), bạn sẽ nhận được thông tin về chính đối tượng bộ sưu tập:

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

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

Nếu bạn muốn Get-Membercho mỗi TypeNametrong bộ sưu tập (NB cho mỗi TypeName, không cho từng đối tượng - một bộ sưu tập của N đối tượng với tất cả cùng TypeNamesẽ chỉ in 1 bảng cho rằng TypeName, không tồn bảng cho từng đối tượng) ...... chỉ cần gắn trực tiếp vào đường ống.


1

Dưới đây làm việc thực sự tốt cho tôi. Tôi đã kết hợp tất cả các câu trả lời ở trên cùng với việc đọc về cách hiển thị thuộc tính đối tượng trong liên kết sau và tìm ra bài đọc ngắn dưới đây về việc in đối tượng

thêm văn bản sau vào tệp có tên print_object.ps1:

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

mở dấu nhắc lệnh powershell, chuyển đến thư mục chứa tệp đó và nhập như sau:

powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated

Chỉ cần thay thế 'System.DateTime' bằng bất kỳ đối tượng nào bạn muốn in. Nếu đối tượng là null, sẽ không có gì được in ra.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.