iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0

在 PowerShell 中,資料不僅僅是文字、數字或符號,而是可以成為功能強大、富有結構的物件。物件化資料處理是 PowerShell 最為顯著的特點之一,它將資料轉化為具體的、有屬性和方法的物件,讓操作更加直觀、靈活且精確。

因此今天的重點在於幫助你理解物件的概念及其應用,為什麼在 PowerShell 中資料以物件的形式存在,能夠讓我們以全新的方式處理資料,並提高工作效率。

藉由深入理解物件的特性與運用,你將不僅僅是執行命令,而是能夠以面向物件的方式管理各種資料,這不僅有助於簡化日常管理任務,更能大幅提升腳本的可讀性與可維護性。因此,掌握物件是學習 PowerShell 的關鍵,這不僅是技術上的進階,更是對資料理解方式的根本性轉變。接下來,我們將探索物件的世界,揭開其背後的運作原理與強大之處。


什麼是物件

物件是一種資料結構,它將資料與行為封裝在一起。具體來說,物件是來自於類別(Class)的實例,類別定義了物件的屬性和方法。屬性是描述物件特徵的變數,而方法是物件可以執行的操作或行為。

書中以 Get-Process 這個命令為例,當在終端機執行該指令時,你只會看到針對「處理程序」眾多資訊當中的極小部分,然後實際上每個處理程序物件( process object )都包含了機器名稱、主視窗控制碼( main windows handle )、最大工作集大小( maximum working set size )、結束代碼( exit code )等等超過 60 種相關的資訊,但是當你沒有特別為該命令指定你特別想看的欄位時,PowerShell 會參考 Microsoft 提供的設定檔後,只顯示 Microsoft 認為你想看的那些欄位。
https://ithelp.ithome.com.tw/upload/images/20240923/20168708cfhibTNjHI.png

有一個方法能查看所有的欄位,就是使用 ConvertTo-Html ,這個 cmdlet 不會篩選任何欄位。它會產生一個包含所有欄位的 HTML 檔案,這就是查看完整表格的一種方式。

PS /Users/kanglin/code/30days> Get-Process | ConvertTo-Html | Out-File getProcessHtml.html
PS /Users/kanglin/code/30days> ls -l
total 944
-rw-r--r--@ 1 kanglin  staff  481558  9 23 12:51 getProcessHtml.html

https://ithelp.ithome.com.tw/upload/images/20240923/201687084W51rey6Wf.png

當你下了一個可以產生輸出結果的命令時,該輸出命令會以「表格」的形式存於記憶體中,而當你透過 pipeline 將第一個命令的輸出結果傳遞給下一個命令時,該「表格」會完整被傳遞給下一個命令。

術語的定義

我會透過上面的 html table 截圖搭配書中所形容的術語做明顯標記,以便釐清。

PowerShell 不會把「儲存在記憶體的表格」稱為表格( table )。而是使用以下幾個特定名稱:

物件(Object)

這是我們所說的表格中的一列( table row )。它代表一個實體,例如一個處理程序,或是一個儲存體帳戶( storage account )。
以下面截圖作為例子,red box 是一個物件,而一列就是一個獨立的物件,一個物件裡面會存放個別屬性的值。
https://ithelp.ithome.com.tw/upload/images/20240923/20168708zZuVRbt7JL.png

屬性( Property )

這是我們所說的表格中的欄位( table column)。它代表一個物件的某項特定資訊,例如處理程序名稱、處理程序識別碼( process ID)、VM 的執行狀態( running status )等等。
以下面截圖作為例子,red box 物件的 SI 屬性值為 39406,green box 物件的 SI 屬性值為 297。
https://ithelp.ithome.com.tw/upload/images/20240923/20168708fwYkOxySRw.png

集合( Collection )

這是所有物件的整體組合,也就是我們之前所稱的表格。

為什麼 PowerShell 使用物件?

提高操作的精確度

物件化資料使得我們可以精確地獲取和操作資料的特定屬性,而不需要手動解析文字輸出。例如,我們可以直接存取一個程序物件的 CPU 屬性,而不必去分析命令的輸出文字。

簡化資料處理

透過物件的屬性和方法,我們可以用簡單且一致的方式操作各種不同類型的資料,無需編寫複雜的字串處理程式碼。

增強腳本的可讀性和維護性

使用物件能讓腳本的語意更加清晰,使得腳本不僅易於撰寫和閱讀,也更容易進行維護和擴展。


探索物件:使用 Get-Member 命令

透過 Get-Member 獲取物件的屬性與方法,僅需要在產生輸出結果的 cmdlet 後面透過 pipeline 將其結果( object )傳遞給 Get-Member 後,它便能存取該物件的所有屬性與方法後,在終端機畫面上列出物件所擁有的屬性與方法。

PS /Users/kanglin/code/30days> get-help Get-Member

NAME
    Get-Member

SYNOPSIS
    Gets the properties and methods of objects.

DESCRIPTION
    The `Get-Member` cmdlet gets the members, the properties and methods, of objects.

    To specify the object, use the InputObject parameter or pipe an object to `Get-Member`. To get information about static members, the members of the class, not of the instance, use the Static parameter. To get only certain types of members, such as NoteProperties, use the MemberType parameter.

    `Get-Member` returns a list of members that's sorted alphabetically. Methods are listed first, followed by the properties.

了解物件類型

執行 Get-Process 將處理程序物件放到管線中,接在管線後面的命令是 Sort-Object ,這個命令不會變更到管線中的Collection,僅是依據 Collection 裡的物件們將其做降序呈現,因此透過下個管線的 Get-Member 可得知其物件類型並未發生變化。

PS /Users/kanglin/code/30days> Get-Process | Sort-Object CPU -Descending  | gm

   TypeName: System.Diagnostics.Process

Name                       MemberType     Definition
----                       ----------     ----------
Handles                    AliasProperty  Handles = Handlecount
Name                       AliasProperty  Name = ProcessName
NPM                        AliasProperty  NPM = NonpagedSystemMemorySize64

重覆剛剛的指令,但是在下個管線中,使用 Select-Object 時,它不會直接移除那些你不想保留的屬性,而是透過建立一個新型態的自訂物件,它透過處理程序中複製你想要的物件,最終生成一個型態為 Selected.System.Diagnostics.Process 的物件。

PS /Users/kanglin/code/30days> Get-Process | Sort-Object CPU -Descending  | Select-Object Name,ID,CPU,SI | gm

   TypeName: Selected.System.Diagnostics.Process

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()

操作物件

排序

預設升序,僅執行 Sort-Object 並指定對應的屬性即可,若要進行降序,則是加上 -Descending 的參數即可。

PS /Users/kanglin/code/30days> Get-Process | Sort-Object CPU -Descending  | Select-Object -First 10

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
      0     0.00     128.33  12,415.01    1059   1 Telegram
      0     0.00     159.12   4,819.24    4014   1 Anytype Helper
      0     0.00     153.47   4,805.44   55179   1 Google Chrome
      0     0.00      23.62   4,497.21   31866   1 Notion Helper (
      0     0.00      70.83   4,032.95    1309   1 iTerm2
      0     0.00      75.95   3,207.82   31880   1 Notion Helper (
      0     0.00      89.27   2,886.01   39440 …06 pwsh
      0     0.00      41.16   2,661.18   55292   1 Google Chrome H
      0     0.00      29.69   2,660.76   55228   1 Google Chrome H
      0     0.00      62.00   2,303.03    4006   1 anytypeHelper

PS /Users/kanglin/code/30days> Get-Process | Sort-Object CPU  | Select-Object -First 10

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
      0     0.00       0.00       0.00       0 …06
      0     0.00       0.00       0.00    1248   1
      0     0.00       0.00       0.00    1354 …54
      0     0.00       0.00       0.00    1355 …55
      0     0.00       0.00       0.00    1838 …38
      0     0.00       0.00       0.00    2188 …88
      0     0.00       0.00       0.00    2315 …15
      0     0.00       0.00       0.00    2324   1
      0     0.00       0.00       0.00    2978 …78
      0     0.00       0.00       0.00    4098 …98

選擇你想要看到的物件屬性及值

先透過 Get-Member 確認目前物件所有的屬性( 截圖為部分結果 )

PS /Users/kanglin/code/30days> Get-Process | Get-Member -MemberType Property | Format-Table

   TypeName: System.Diagnostics.Process

Name                       MemberType Definition
----                       ---------- ----------
BasePriority               Property   int BasePriority {get;}
Container                  Property   System.ComponentModel.IContainer Container {get;}
EnableRaisingEvents        Property   bool EnableRaisingEvents {get;set;}
ExitCode                   Property   int ExitCode {get;}
ExitTime                   Property   datetime ExitTime {get;}
Handle                     Property   System.IntPtr Handle {get;}
HandleCount                Property   int HandleCount {get;}
HasExited                  Property   bool HasExited {get;}
Id                         Property   int Id {get;}
MachineName                Property   string MachineName {get;}
MainModule                 Property   System.Diagnostics.ProcessModule MainModule {get;}

接著便可以透過 Select-Object 選擇你想要的屬性,另外可透過 -First-Last 呈現最初或最後的筆數。

PS /Users/kanglin/code/30days> Get-Process | Select-Object -Property ProcessName,Threads,Id,Handle -Last 5

ProcessName     Threads                                             Id Handle
-----------     -------                                             -- ------
WeatherWidget   {103387168, 1804136672, 1804710112, 1805283552…} 17726   7164
WiFiAgent       {103387168, 1804431584, 1805005024, 1800417504…}   687   1072
WindowManager   {103387168, 1870328032, 1871474912, 1868034272}    590   6328
WorldClockWidge {103387168, 1873653984, 1874227424, 1874800864}  17727   6372
zsh             {103387168}                                      39407   7112

PS /Users/kanglin/code/30days> Get-Process | Select-Object -Property ProcessName,Threads,Id,Handle -First 5

ProcessName Threads  Id Handle
----------- -------  -- ------
            {}        0   5176
            {}        1   2580
            {}      297   4276
            {}      299   4484
            {}      301   5368

明日主題

Day 10 - 深度探索管線


上一篇
Day 8 - 擴充命令
下一篇
Day 10 - 深度探索管線
系列文
《30天挑戰精通 PowerShell:從 Windows Server 到 Azure DevOps 自動化之旅》30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言