PowerShell是一種強大的語言。但是是什麼使得這個腳本語言如此強大呢?PowerShell對象。這些神奇的對象是什麼,以及PowerShell如何與它們一起工作?敬請期待。
PowerShell是一種面向對象的語言和shell。這與傳統的cmd和Bash等shell不同。這些傳統的shell專注於文本,也就是字符串,雖然仍然有用,但在功能上有限。在PowerShell中,幾乎所有的東西都是對象。
在本文中,您將學習有關PowerShell中對象的一些關鍵概念。通過本文末尾的有用示例代碼和可視化,您將學會如何將這些知識應用於自己的腳本編寫中。
如果您更喜歡視覺化學習,可以觀看本文下方的相關視頻。
那麼準備好了嗎!您將經歷一次難忘的體驗,幫助您掌握PowerShell中對象的概念!
前提條件
在本文中,您將通過實際操作來學習PowerShell中的對象。如果您選擇跟隨並嘗試代碼示例,Windows PowerShell 5.1或任何版本的PowerShell 6+都應該可以使用。不過,您看到的所有示例都是在Windows 10 Build 1903上使用Windows PowerShell 5.1執行的。
理解對象的結構
在PowerShell中,對象無處不在。你可能會問自己:“對象是什麼樣子?”在這個第一部分中,你將獲得對象的概述。一旦你對對象的組成有了廣泛的了解,你就可以深入一些代碼示例了!
使用Get-Member發現對象成員
對象有許多不同類型的信息與之關聯。在PowerShell中,這些信息有時被稱為成員。對象成員是一個通用術語,指的是與對象相關的所有信息。
要發現對象的信息(成員),你可以使用Get-Member cmdlet。Get-Member cmdlet是一個方便的命令,允許你查找PowerShell中任何對象的可用屬性、方法等等。
例如,假設你想查看通過Get-Service cmdlet返回的特定對象的成員。你可以通過將Get-Service命令的輸出傳輸到Get-Member cmdlet中來實現,如下所示。
熟悉使用Get-Member cmdlet。在本文中,你將會經常使用它。
PowerShell中的每個輸出命令都可以將其傳輸到Get-Member。只需記住將該命令作為管道中的最後一個命令,因為它將用自己的輸出覆蓋輸出。
對象類型和類
不详细介绍面向对象编程,每个对象都有一个“模式”。对象的“模式”可以看作是一个包含创建对象蓝图的模板。这个蓝图被称为类型。
PowerShell中的每个对象都有一个特定的类型。每个对象都有一个创建它的蓝图。对象类型由一个类定义。考虑以下例子;9是数字,Bluegill是鱼,Labrador是狗,等等。类位于类型之前。
对象是具有特定类型的类的实例。
不用深入学习这个主题。除非你是软件开发人员,否则你可能不需要太过担心语义问题。然而,基本了解这个概念是很重要的。
属性
你应该了解的关于对象的最重要的概念是属性。属性是描述对象的特征。一个对象可以有许多不同的属性,代表各种特征。
发现对象上存在的属性的最简单的方法之一是使用Get-Member
命令。你可以看到,通过使用MemberType
参数,Get-Member
将限制返回的输出只包括对象。你还会看到它显示System.ServiceProcess.ServiceController的对象类型。

現在以前面提到的BITS服務為例,使用以下代碼查看該對象屬性的具體值。 Get-Member
cmdlet允許您查找屬性名稱,但不是值。然而,使用PowerShell的Select-Object
cmdlet,您可以檢查屬性值。
下面可以看到StartType
是對象的一個屬性。返回的對象有很多不同的成員,但使用Select-Object
cmdlet,它限制了輸出僅顯示該屬性。

屬性是在PowerShell中最常見的對象組件。
別名
某些屬性的MemberType
是Alias
。別名是屬性名稱的假名。它們有時可以給屬性提供更直觀的名稱。
您可以看到使用Get-Service
cmdlet再次顯示具有別名的對象的示例,如下所示。屬性Name
被別名為ServiceName
,RequiredServices
被別名為ServicesDependedOn
屬性。

當屬性有別名時,您可以使用別名而不是實際屬性名稱來引用該屬性的值。在這個例子中,像Name
和RequiredServices
這樣的描述性屬性名稱比ServiceName
和ServicesDependedOn
更直觀且更容易輸入。
您可以在下面看到引用這些別名的示例。
您應該看到以下輸出。請注意,無論使用別名還是不使用別名,信息都是相同的:

方法
屬性只是創建物件的其中一部分;方法也是一個重要的概念。方法是可以對物件執行的操作。與屬性一樣,您可以使用Get-Member
cmdlet來查找物件上的方法。
為了將Get-Member
的輸出限定為僅包含方法,將MemberType
參數值設置為Method
,如下所示。

作為初學者,您會比較少使用方法。
其他MemberTypes
屬性、方法和別名不是物件可能具有的唯一成員類型。然而,它們將是您最常使用的成員類型。
為了完整起見,以下是您可能遇到的幾種其他成員類型。
- 腳本屬性 – 用於計算屬性值。
- 注意屬性 – 用於靜態屬性名稱。
- 屬性集 – 這些就像包含名稱所暗示的別名一樣的集合屬性。例如,您為您的
Get-CompInfo
函數創建了一個自定義屬性Specs
。Specs
實際上是Cpu、Mem、Hdd、IP屬性的一個子集。屬性集的主要目的是提供一個單一的屬性名稱來連接一組屬性。
還要提到對象事件的概念。事件超出了本文的範圍。
在PowerShell中使用對象
現在您對對象的組成有了基本的了解,讓我們開始動手寫一些代碼。
許多PowerShell命令產生輸出,但有時您不需要看到所有這些輸出。您需要限制或操作該輸出的某些方面。幸運的是,PowerShell有一些不同的命令,可以讓您做到這一點。
讓我們首先以列舉本地計算機上的所有服務為例,使用如下所示的Get-Service
命令。您可以通過輸出看到返回了許多不同的服務(對象)。

控制返回的對象屬性
繼續使用Get-Service
的示例,也許您不需要看到每個屬性。相反,您只需要看到Status
和DisplayName
屬性。要限制返回的屬性,您可以使用Select-Object
命令。
Select-Object
cmdlet “過濾” 從 PowerShell 管線返回的各種屬性。要從返回的物件屬性中 “過濾”,您可以使用 Property
參數,並指定以逗號分隔的一個或多個屬性集合以返回。
您可以在下面看到一個例子,只返回 Status
和 DisplayName
屬性。

對象排序
也許您正在建立一個報表來顯示服務及其狀態。為了方便信息消化,您希望將返回的對象按照 Status
屬性的值進行排序。為此,您可以使用 Sort-Object
cmdlet。
Sort-Object
cmdlet 允許您收集所有返回的對象,然後按您定義的順序輸出它們。
例如,使用 Sort-Object
的 Property
參數,您可以指定從 Get-Service
收到的對象中的一個或多個屬性進行排序。PowerShell 將每個對象傳遞給 Sort-Object
cmdlet,然後按照屬性的值對它們進行排序並返回。
您可以在下面看到一個示例,返回按其 Status
屬性降序排序的所有服務對象,使用 Sort-Object
的 Descending
切換參數。

在 PowerShell 中,管道 [
|
] 是您在必要時應該使用的幾種連續行技術之一。在必要時使用它,而不是使用重音符。
過濾物件
也許你決定不想看到機器上的所有服務。相反地,你需要根據特定標準來限制輸出。一種限制返回物件數量的方法是使用Where-Object
指令。
雖然Select-Object
指令可以限制特定屬性的輸出,但Where-Object
指令可以限制整個物件的輸出。
Where-Object
指令的功能類似於SQL WHERE子句。它作為原始來源的過濾器,只返回符合特定標準的物件。
也許你已經決定只返回具有Status
屬性值為Running
且只返回具有以A
開頭的DisplayName
屬性值的物件。
你可以在下面的程式碼片段中看到,在管道順序中,在Select-Object
和Sort-Object
之間插入了Where-Object
參考。使用具有必要條件的腳本區塊值,通過FilterScript
參數,你可以創建任何類型的查詢。
如果你想操縱如何將輸出返回到控制台,請查看
Format-Table
指令。

計算和平均返回的物件數量
Get-Service
命令返回多个不同的对象。使用 Where-Object
cmdlet,您已经过滤出了其中的一部分对象,但是有多少个呢?介绍一下 Measure-Object
cmdlet。
Measure-Object
cmdlet 是 PowerShell 命令之一,它可以对通过管道接收到的对象进行数学运算,包括计算对象的数量。
也许您想知道在组合命令运行时最终返回了多少个对象。您可以将最终的输出作为管道输入到 Measure-Object
cmdlet 中,以找到返回的对象总数,如下所示。
一旦命令处理完成,您将看到在这种情况下,最初由 Get-Service
命令创建了 21 个对象。

也许您只想知道返回的对象总数。由于 Measure-Object
命令通过 Count
属性返回找到的总对象数,您可以再次参考 Select-Object
cmdlet。但这次,只返回 Count
属性。

在循环中对对象采取操作
通过管道处理每个对象时,您可以使用循环对每个对象采取操作。PowerShell 中有不同类型的循环,但是在管道示例中,我们将重点介绍 ForEach-Object
cmdlet。
ForEach-Object
cmdlet 允许您对流入其中的每个对象采取操作。这种行为最好通过示例来解释。
繼續使用 Get-Service
的例子,也許您想找出在 Windows 電腦上名稱以 “Windows” 開頭且正在執行的所有服務。使用 Where-Object
cmdlet,您可以像之前一樣建立條件。
但現在不再返回整個物件或僅返回幾個屬性,而是希望對每個物件返回字符串 <ServiceName> 正在執行,使用代碼 **Write-Host -ForegroundColor 'Yellow' <ServiceName> "is running"
。
您現在正在操作輸出並創建自己的字符串。唯一的方法是使用 ForEach-Object
cmdlet,如下所示。下面您可以看到,對於每個通過 Where-Object
返回的物件,PowerShell 執行代碼 Write-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"
。

ForEach-Object
cmdlet 在很多方面都很有用。例如,您可以在找到的每個服務物件中建立其他邏輯,並根據屬性值更改輸出字符串的顏色和措辭,甚至執行其他操作,例如啟動已停止的服務。
想像一下這給您帶來的可能性!只需稍加思考和計劃,您可以創建一個腳本,將一個命令輕鬆執行在許多物件上。
比較物件
有時需要查看兩個物件並比較屬性值。
也许你的网络上有两个几乎相同的系统。然而,你遇到了一个你认为是配置问题的服务问题,出现在其中一个系统上。
你得出的结论是,由于这些系统位于网络的不同部分,你需要使用远程命令在 PowerShell 会话中收集信息。你打开你最喜欢的编辑器并创建一个脚本。如下面所示,这个脚本连接到两个不同的服务器,并枚举每个服务器上的所有进程。
你现在已经在$ProcA
和$ProcB
变量中捕获了每台计算机上的所有进程。现在你需要比较它们。你可以手动查看每组进程,或者你可以选择简单的方法,使用一个叫做Compare-Object
的 cmdlet。
Compare-Object
允许你比较两个不同对象的属性值。这个 cmdlet 读取每个对象中的每个属性,查看它们的值,然后返回默认的不同之处,以及相同之处。
要使用Compare-Object
,请指定一个ReferenceObject
和一个DifferenceObject
参数,并将每个对象作为参数值提供,如下所示。
默认情况下,Compare-Object
只会返回由SideIndicator
属性指示的对象之间的差异。所使用的符号或边指示器是>
、<
和=
,用于显示正在比较的对象的匹配情况。

您可以使用
Compare-Object
命令的开关参数IncludeEqual
来返回相同的对象属性。如果是这样,您将看到==
作为边指示器。同样,您可以使用ExcludeDifferent
来排除不同之处。
Compare-Object
命令是一个非常有用的命令。如果您想了解更多信息,请务必访问在线文档。
使用自定义对象
现在您已经对对象有了很好的理解,并且知道如何处理它们,现在是时候创建自己的对象了!
使用哈希表创建自定义对象
创建自己的对象的一种方法是使用哈希表。哈希表是一组键/值对,正好可以用来创建对象的属性。
让我们从使用哈希表创建一些键/值对的自定义PowerShell对象开始。在下面的示例中,您正在创建一个哈希表。这个哈希表表示一个单独的对象及其属性。一旦定义了哈希表$CarHashtable
,您就可以使用PsCustomObject
类型加速器进行转换。
pscustomobject類型加速器是一種快速創建pscustomobject類實例的方法。這種行為稱為轉換。
在下面的代碼片段結束時,你將擁有一個類型為pscustomobject的對象($CarObject
),並且為其分配了五個屬性。
另外,你也可以使用New-Object
cmdlet。使用相同的哈希表,而不是使用pscustomobject類型加速器,你可以使用New-Object
的長格式方式。下面是一個示例。
當創建$CarObject
時,你可以看到下面的代碼,你可以像使用內置的PowerShell cmdlet(例如Get-Service
)那樣引用每個屬性。

添加和刪除屬性
你不僅可以創建自定義對象,還可以向其添加屬性。還記得使用Get-Member
cmdlet嗎?Get-Member
有一個相對應的命令Add-Member
。Add-Member
cmdlet不枚舉成員,而是添加它們。
以前創建的自定義對象為例,也許你想向該對象添加一個車型年份屬性。你可以通過將對象傳遞給Add-Member
並指定:
- 成員的類型(在這個案例中是一個簡單的
NoteProperty
) - 屬性的名稱(
Year
) - 屬性的值(
Value
)
你可以在下面看到一個例子。
你可以再次看到它看起來就像任何其他屬性一樣。

你可以使用類似的技巧來添加許多不同類型的成員。如果你想自己探索更多,可以查看Add-Member
的文檔。
同樣地,你也可以輕鬆地從對象中刪除成員。雖然沒有Remove-Member
的命令,但你仍然可以通過在對象上調用Remove()
方法來實現。下面的示例將介紹如何使用方法。你將在下一節中學習有關方法的知識。
方法簡介
在本文中,你一直在使用屬性。你讀取屬性值,創建自己的屬性,添加和刪除它們。但你對環境沒有做太多的改變。你沒有改變伺服器上的任何東西。現在讓我們使用方法來採取一些行動。
方法執行某種操作。對象存儲信息,而方法則執行操作。
例如,你可能知道Stop-Service
命令。這個命令停止一個Windows服務。要做到這一點,你可以將從Get-Service
獲取的對象直接發送給Stop-Service
。
您可以在下面看到停止 BITS 服務的示例。此示例停止 BITS 服務,然後檢查狀態以確保已停止。您執行了兩個動作:停止服務和檢查狀態。
不必兩次運行 Get-Service
,並執行單獨的命令 Stop-Service
,相反,您可以利用內置在服務對象中的方法。許多對象都有方法。在這種情況下,使用 Stop-Service
,甚至不需要第二個 Get-Service
引用。

通過在服務對象本身上調用方法,您可以停止並檢索更新後的狀態,所有這些都可以使用單個對象完成。下面您可以看到此示例。請注意,通過使用 Stop()
和 Start()
方法,您可以像命令一樣操作服務。
為確保服務狀態更改後 Status
屬性值是最新的,您可以調用 Refresh()
方法,它的作用類似於另一個 Get-Service
命令的調用。
您應該看到以下輸出:

要了解更多關於方法的資訊,請查看「about_Methods」幫助主題。
結論
PowerShell 中的對象具有許多用途。本文只是一個入門指南,讓您開始學習它們。在本文中,您已經學到了一些關於對象的基礎知識,以及如何進行操作、操作和創建它們。您已經看到了一些不同的場景,並通過代碼示例展示了如何執行這些任務。保持冷靜,學習 PowerShell。感謝閱讀!