Powershell 進(jìn)階語(三)
PowerShell 管道
管道輸出
PowerShell 命令不會生成文本作為輸出,而是會生成對象,對象是描述內(nèi)存中數(shù)據(jù)結(jié)構(gòu)的通用詞。
運(yùn)行 Get-Service 命令時,它會返回服務(wù)對象的集合,每個對象都包含 Name、DisplayName 和 Status 等名稱的屬性。
控制管道輸出的格式設(shè)置
格式設(shè)置 cmdlet 為:
- Format-List
- Format-Table
- Format-Wide
- Format-Custom
Format-Custom cmdlet 需要創(chuàng)建定義格式的自定義 XML 配置文件。 該 cmdlet 不經(jīng)常使用。
Format-List
Format-List cmdlet 將命令的輸出格式化為一個簡單的屬性列表,其中每個屬性顯示在一個新行上。
如果將輸出傳遞給 Format-List 的命令返回多個對象,則會為每個對象顯示單獨(dú)屬性列表。
當(dāng)命令返回大量很難以表格格式查看的屬性時,列表格式尤其有用。
Format-List cmdlet 的別名是 fl。
Format-Table
Format-Table cmdlet 將輸出格式化為表格,其中每一行表示一個對象,每一列表示一個屬性。
這個輸出的效果和默認(rèn)的沒啥效果,多了一個就是你可以選擇參數(shù)來進(jìn)行定義你輸出的效果,下面介紹參數(shù)↓↓↓
可使用多種參數(shù)修改此格式,例如:
-
-AutoSize。 此參數(shù)可根據(jù)數(shù)據(jù)的寬度來調(diào)整列的大小和數(shù)量。 在 Windows PowerShell 5.0 及更高版本中,-AutoSize 默認(rèn)設(shè)置為 true。 在更低版本的 Windows PowerShell 中,默認(rèn)值可能會截斷表中的數(shù)據(jù)。
-
-HideTableHeaders。 此參數(shù)會從輸出中移除表標(biāo)頭。
-
-Wrap。 此參數(shù)會使超出列寬的文本換行到下一行。
Format-Table cmdlet 的別名是 ft。
Format-Wide
Format-Wide cmdlet 的輸出是單個列表中分多列顯示的單個屬性。
這個其實(shí)只需要知道:使用 -Property 參數(shù),指定一個屬性去進(jìn)行多個列展示,不用單個列展示這么難看
下面展示的就是服務(wù)的所有名字,但是我們是用3列進(jìn)行展示
Get-Service | fw -Property Name -Column 3
管道選擇、排序和度量對象
排序和分組
Sort-Object
Sort-Object 命令接受一個或多個屬性名作為排序依據(jù), 默認(rèn)情況下,命令按升序排序
Get-Service | Sort-Object –Property Name –Descending
Get-Service | Sort Name –Desc
Get-Service | Sort Status,Name
默認(rèn)情況下,字符串屬性的排序不考慮大小寫。
(但是Sort-Object 也有參數(shù)去支持指定區(qū)分大小寫的排序、特定區(qū)域性的排序規(guī)則和其他選項)
Format 的 GroupBy分組
Format-List、Format-Table 和 Format-Wide 格式設(shè)置 cmdlet 具有接受屬性名的 -GroupBy 參數(shù)。 通過使用 -GroupBy 參數(shù),可以按指定屬性對輸出進(jìn)行分組。
注意:這里說的是Format的幾個格式設(shè)置的分組,所以要用格式cmdlet然后再使用這個GroupBy參數(shù)
Get-Service | Sort-Object Status,Name | fw -GroupBy Status
-GroupBy 參數(shù)的運(yùn)行方式與 Group-Object 命令類似。 Group-Object 命令接受管道輸入,讓你可以更好地控制對象分組。 Group-Object 具有別名 group。
度量管道中的對象
Measure-Object 默認(rèn)情況下,該命令會對集合中的對象數(shù)進(jìn)行計數(shù),并生成包含計數(shù)的測量對象。
使用 Measure-Object 的 -Property 參數(shù)可指定單個屬性,該屬性必須包含數(shù)值。 隨后,可以添加 -Sum、-Average、-Minimum 和 -Maximum 參數(shù),以計算指定屬性的這些聚合值。
(通常可注意到 -Sum、-Average、-Minimum 和 -Maximum 參數(shù)被截斷為 -Sum、-Ave、-Min 和 -Max)
以下命令計算文件夾中的文件數(shù),并顯示文件大小的最小、最大和平均值:
(Recurse遞歸讀取)
Get-ChildItem -File -Recurse | Measure -Property Length -Sum -Average -Minimum -Max
效果如下圖:

Select-Object
Select-Object 命令具有別名 Select。
這個命令比較簡單,用法如下:
用Property指定要選擇的對象即可,多個就用逗號隔開
Get-Process | Select-Object -Property 列名1,列名2
- 選擇最少虛擬內(nèi)存使用量排名前 10 的進(jìn)程
Get-Process | Sort-Object –Property VM | Select-Object –First 10
- 選擇最后 10 個正在運(yùn)行的服務(wù)并按名稱排序
Get-Service | Sort-Object –Property Name | Select-Object –Last 10
- 選擇 CPU 用量最少的五個進(jìn)程,并跳過使用最少 CPU 的那一個進(jìn)程
Get-Process | Sort-Object –Property CPU –Descending | Select-Object –First 5 –Skip 1
Unique去重
只需要在指定對象后添加多一個-Unique參數(shù)即可
- 顯示某個用戶在每個部門中的用戶信息
Get-ADUser -Filter * -Property Department | Sort-Object -Property Department | Select-Object Department -Unique
Property
沒啥好說的,就是select-object 的 參數(shù)Property 指定顯示的進(jìn)程屬性即可
- 顯示一個表,其中包含本地計算機(jī)上運(yùn)行的所有進(jìn)程的名稱、進(jìn)程 ID、虛擬內(nèi)存大小、分頁內(nèi)存大小和 CPU 使用率:
Get-Process | Select-Object –Property Name,ID,VM,PM,CPU | Format-Table
- -Property 參數(shù)適用于 -First 或 -Last 參數(shù)。 以下命令返回具有最大 CPU 使用率的 10 個進(jìn)程的名稱和 CPU 使用率:
Get-Process | Sort-Object –Property CPU –Descending | Select-Object –Property Name,CPU –First 10
自定義屬性并設(shè)置表達(dá)式與格式
- 定義屬性的名字:
- label、l、name 或 n:這指定計算屬性的標(biāo)簽或名稱。 由于小寫字母 l 在某些字體中類似于數(shù)字 1,因此請嘗試使用 name、n 或 label。
- 設(shè)置屬性計算的式子:
- expression 或 e:這將指定設(shè)置計算屬性值的表達(dá)式。
Get-Process |
Select-Object Name,ID,@{n='VirtualMemory';e={$PSItem.VM}},@{n='PagedMemory';e={$PSItem.PM}}
$PSItem 是由 Windows PowerShell 創(chuàng)建的特殊變量。 它表示通過管道傳輸?shù)?Select-Object 命令中的任何對象。 在上一個示例中,這是一個 Process 對象。 $PSItem 之后的句點(diǎn)允許訪問對象的單個成員。 在此示例中,一個計算屬性使用 VM 屬性,另一個使用 PM 屬性。
當(dāng)我們輸入正常的Get-Process 并獲取他的所有屬性的時候你會看到VM這個屬性,所以我們$PSItem.VM是能夠獲取到的
檢查一下是否有VM
Get-Process | Get-Member | Select-Object -Property Name | Format-Wide -Column 5
下圖可以看到確實(shí)有VM屬性

- 為什么用@{}
解釋:還記不記得之前創(chuàng)建空數(shù)組是用@(),這里是創(chuàng)建hash表,所以用@{},n是屬性名,對應(yīng)鍵,e是計算式子相當(dāng)于值,所以說我們還能知道在自定義的時候不能定義同一個名字的屬性
計算
你可能想要修改前面的命令以顯示內(nèi)存值(以兆字節(jié) (MB) 為單位)。 PowerShell 將縮寫 KB、MB、GB、TB 和 PB 分別表示千字節(jié)、兆字節(jié)、千兆字節(jié)、兆兆字節(jié)和拍字節(jié)。 因此,可以按如下所示修改命令:
($PSItem是接收傳過來的對象,$_也是一樣的, 用的比較多的是$_,所以說我們可以在Get-Process出來的對象中一個個用$PSItem去取你想要的屬性或者激活方法)
Get-Process |
Select-Object Name,
ID,
@{n='VirtualMemory(MB)';e={$PSItem.VM / 1MB}},
@{n='PagedMemory(MB)';e={$PSItem.PM / 1MB}}
生成的值有幾個小數(shù)位,這在視覺上是不理想的。
若要改進(jìn)輸出,請進(jìn)行以下更改:
Get-Process |
Select-Object Name,
ID,
@{n='VirtualMemory(MB)';e={'{0:N2}' –f ($PSItem.VM / 1MB) -as [Double] }},
@{n='PagedMemory(MB)';e={'{0:N2}' –f ($PSItem.PM / 1MB) -as [Double] }}
上一個示例中的語法可能看起來令人困惑,因為它包含許多標(biāo)點(diǎn)符號。 從基本表達(dá)式開始:
'{0:N2}' –f ($PSItem.VM / 1MB)
上一個表達(dá)式將 VM 屬性除以 1 MB,然后將結(jié)果格式化為最多兩個小數(shù)位的數(shù)字。 然后將該表達(dá)式放入哈希表中:
該哈希表創(chuàng)建名為 VirtualMemory(MB) 的自定義屬性。
@{n='VirtualMemory(MB)';e={'{0:N2}' –f ($PSItem.VM / 1MB) }}
從管道中篩選對象
比較運(yùn)算符
| 操作 | DESCRIPTION |
|---|---|
| -eq | 等于 |
| -ne | 不等于 |
| -gt | 大于 |
| -lt | 小于 |
| -le | 小于或等于 |
| -ge | 大于或等于 |
在powershell中默認(rèn)是不區(qū)分大小寫,但是在比較的時候難免希望對大小寫的區(qū)分
所以我們可以在操作中添加一個前綴c作為比較區(qū)分大小寫的標(biāo)志
-ceq
-cne
不僅僅上述的運(yùn)算符,其他也都可以加c
當(dāng)然還有l(wèi)ike也可以用來區(qū)分大小寫去匹配,因為-like 運(yùn)算符類似于 -eq
-clike
其他更高級的運(yùn)算符存包括:
- -in 和 -contains 運(yùn)算符,用于測試集合中是否存在對象。
- -as 運(yùn)算符,用于測試對象是否為指定類型。
- 將字符串與正則表達(dá)式進(jìn)行比較的 -match 和 -cmatch 運(yùn)算符。
- 還包含許多運(yùn)算符來反轉(zhuǎn)比較的邏輯,例如 -notlike 和 -notin。
簡單案例:
PS C:\> 100 -gt 10
True
PS C:\> 'hello' -eq 'HELLO'
True
PS C:\> 'hello' -ceq 'HELLO'
False
基本篩選器語法
Where-Object 命令及其別名 Where
- 僅顯示正在運(yùn)行的服務(wù)的列表
Get-Service | Where Status –eq Running
基本語法的限制
只能對單個比較使用基本語法。 例如,無法顯示已停止且具有“自動”啟動模式的服務(wù)列表,因為需要兩個比較。
不能將基本語法用于復(fù)雜表達(dá)式。 例如,服務(wù)對象的 Name 屬性由一串字符組成。 PowerShell 使用 System.String 對象包含該串字符,而 System.String 對象具有 Length 屬性。 以下命令不適用于基本篩選語法:
Get-Service | Where Name.Length –gt 5
目的是顯示名稱超過五個字符的所有服務(wù)。 但是,此命令永遠(yuǎn)不會生成輸出。 一旦超過基本語法的能力,必須改用高級篩選語法。
高級篩選器語法
高級語法使用篩選器腳本
使用 -FilterScript 參數(shù)傳遞該腳本塊
對于通過管道傳遞到命令的每個對象,篩選器腳本都會運(yùn)行一次。 當(dāng)篩選器腳本返回 True 時,該對象將作為輸出傳遞到管道中,當(dāng)篩選器腳本返回 False 時,將從管道中刪除該對象。
以下兩個命令具有相同的功能。 第一個命令使用基本語法,第二個命令使用高級語法執(zhí)行相同的操作:
Get-Service | Where Status –eq Running
Get-Service | Where-Object –FilterScript { $PSItem.Status –eq 'Running' }
-FilterScript 參數(shù)是位置參數(shù),大多數(shù)用戶會省略它。 大多數(shù)用戶還會使用 Where 別名或 ? 別名,此名稱長度更短。
推薦使用 $_ 變量而不是 $PSItem,因為在 Windows PowerShell 1.0 和 Windows PowerShell 2.0 中只允許使用 $_。
以下命令執(zhí)行與前兩個命令相同的任務(wù):
Get-Service | Where {$PSItem.Status –eq 'Running'}
Get-Service | ? {$_.Status –eq 'Running'}
組合多個條件
高級語法允許通過使用 -and 和 -or 布爾值或邏輯運(yùn)算符來組合多個條件。 下面是一個示例:
Get-EventLog –LogName Security –Newest 100 |
Where { $PSItem.EventID –eq 4672 –and $PSItem.EntryType –eq 'SuccessAudit' }
邏輯運(yùn)算符的任意一側(cè)都必須是一個完整的比較式子,下面給幾個錯誤示范,請不要犯錯:
Get-Process | Where { $PSItem.CPU –gt 30 –and VM –lt 10000 }
Get-Service | Where { $PSItem.Status –eq 'Running' –or 'Starting' }
True 或 False 的屬性篩選使用技巧
Get-Process 生成的對象具有名為“Responding”的屬性,此屬性包含 True 或 False。
獲取正在響應(yīng)的進(jìn)程的列表,可以使用以下命令之一:
Get-Process | Where { $PSItem.Responding –eq $True }
Get-Process | Where { $PSItem.Responding }
在第一個命令中,特殊 shell 變量 $True 用于表示布爾值 True。 第二個命令未包含任何比較,但它是有效的,因為 Responding 屬性已包含 True 或 False
這類似于反向邏輯,僅列出未響應(yīng)的進(jìn)程:
Get-Process | Where { -not $PSItem.Responding }
在前面的示例中,-not 邏輯運(yùn)算符將 True 更改為 False,并將 False 更改為 True。 因此,如果進(jìn)程未響應(yīng),則其 Responding 屬性為 False。 -not 運(yùn)算符將結(jié)果更改為 True,這會使進(jìn)程被傳遞到管道中,并包含在命令的最終輸出中。
高級篩選不受簡單篩選限制
現(xiàn)在再去根據(jù)字符長度來篩選就沒問題了
Get-Service | Where {$PSItem.Name.Length –gt 8}

優(yōu)化篩選器性能
說是優(yōu)化,但其實(shí)都是靠編寫腳本自己的功底
Get-隨便 對于下面兩個示例,你認(rèn)為哪一個速度更快?
Get-隨便 | Sort-Object –Property Letter | Where-Object –FilterScript { $PSItem.Color –eq 'Red' }
Get-隨便 | Where-Object –FilterScript { $PSItem.Color –eq 'Red' } | Sort-Object –Property Letter
第二個命令速度更快,因為他先是移除了不要的再進(jìn)行排序,這加速了排序,但是如果你排序了再移除就表示你排序排了沒用的東西,然后還要移除,那就慢了。
再比如下面這個查找文件,一看就知道是第二個塊了,內(nèi)置的直接使用更快
Get-ChildItem | Where { -not $PSItem.PSIsContainer }
Get-ChildItem -File
枚舉
這里的枚舉是說powershell取出來的對象在管道中每一個都傳遞給下一個cmdlet去操作。
比如:停止計算機(jī)上每個正在運(yùn)行的記事本進(jìn)程,則可以運(yùn)行以下兩個命令之一
Get-Process –Name Notepad | Stop-Process
Stop-Process –Name Notepad
比如Get-Process 篩選了名字為Notepad的,那就可能會出現(xiàn)很多個進(jìn)程,那給到管道后面的Stop-Process來說,他就是在枚舉每一個Notepad進(jìn)程然后執(zhí)行停止進(jìn)程操作
枚舉管道對象語法
這里官網(wǎng)分了基本語法和高級語法,但其實(shí)枚舉管道都支持
基本和高級的區(qū)分就是:基本的不用腳本,高級的用腳本塊
查看下ForEach-Object的幫助文檔:
可以看到有兩個參數(shù),一個是接腳本塊的,一看就是高級用法
基本用法應(yīng)該就是下面的-MemberName指定屬性或方法名的了

基本語法:
兩個常見別名: ForEach 和 %。 與 Where-Object 一樣, ForEach-Object 具有基本語法和高級語法。
下面三個都一樣,原理都是將Get-ChildItem取出來的對象 ([System.IO.FileInfo])進(jìn)行For枚舉出來然后參數(shù)-MemberName就是取屬性或者方法,那我們給的Encrypt就是一個方法(加密),所以我們就相當(dāng)于給當(dāng)前遍歷的對象執(zhí)行了該方法,以此類推每一個對象都會執(zhí)行一次。
Get-ChildItem –Path C:\Encrypted\ -File | ForEach-Object -MemberName Encrypt
# 使用了別名和忽略了參數(shù)
Get-ChildItem –Path C:\Encrypted\ -File | ForEach Encrypt
# 使用了別名和忽略了參數(shù)
Get-ChildItem –Path C:\Encrypted\ -File | % Encrypt
你可以特地去查看下是否有該方法:
Get-ChildItem | Get-Member -Name Encry*

高級語法:就是使用腳本塊
使用高級語法加密一組文件
Get-ChildItem –Path C:\ToEncrypt\ -File | ForEach-Object –Process { $PSItem.Encrypt() }
范圍運(yùn)算符是兩個句點(diǎn) (..),中間沒有空格,range 運(yùn)算符生成從 1 到 3 的整數(shù)對象,這 3 個對象通過管道傳遞給 ForEach-Object,迫使腳本塊運(yùn)行 3 次
1..3 | ForEach-Object { Get-Random }
寫入到文件
Out-File就相當(dāng)于cmd里面的文本重定向運(yùn)算符 > 和 >>,這些運(yùn)算符可作為 Out-File 的別名,管道末尾的大于號 (>) 將輸出定向到文件,從而覆蓋內(nèi)容,兩個連續(xù)的大于號 (>>) 將輸出定向到文件,從而將輸出附加到文件中已有的任何文本。
例如:
下面這個雖然說輸出到csv文件,但其實(shí)就是文本格式輸入進(jìn)去,沒有csv格式
Get-Service |
Sort-Object –Property Status, Name |
Select-Object –Property DisplayName,Status |
Out-File –FilePath ServiceList.csv
轉(zhuǎn)換為其他形式的數(shù)據(jù)表示形式
PowerShell 使用兩個不同的謂詞進(jìn)行轉(zhuǎn)換: ConvertTo 和 Export
Csv
使用 ConvertTo 的命令(如 ConvertTo-Csv )接受來自管道的對象作為輸入,并將轉(zhuǎn)換后的數(shù)據(jù)作為輸出生成到管道
切記:這個是將對象轉(zhuǎn)換成了csv格式,但是你直接輸入進(jìn)文件可能會存在各種問題,比如ConvertTo-Csv 生成的 CSV 包含類型信息行(如 #TYPE System.ServiceProcess.ServiceController),這不是標(biāo)準(zhǔn) CSV 的一部分,可能會干擾某些應(yīng)用程序的解析,這就需要Export-Csv解決
Get-Service | ConvertTo-Csv | Out-File Services.csv
使用 Export(如 Export-Csv)的命令執(zhí)行兩項作:它會轉(zhuǎn)換數(shù)據(jù),然后將數(shù)據(jù)寫入外部存儲,例如磁盤上的文件
Get-Service | Export-Csv Services.csv
XML
ConvertTo-Clixml 和 Export-Clixml
Json
ConvertTo-Json 命令創(chuàng)建 JSON 格式的數(shù)據(jù),必須使用 Out-File 或文本重定向運(yùn)算符之一將 JSON 數(shù)據(jù)發(fā)送到文件
HTML
ConvertTo-Html 命令支持此功能,必須使用 Out-File 或其別名之一來定向輸出。
ConvertTo-Html 創(chuàng)建編碼為 HTML 的簡單列表或表,您可以通過各種參數(shù)以有限的方式控制HTML格式,例如:
- ?Head。 指定 HTML 頭 節(jié)的內(nèi)容。
- —標(biāo)題。 設(shè)置 HTML 標(biāo)題 標(biāo)記的值。
- -PreContent。 定義應(yīng)在表或列表輸出之前顯示的任何內(nèi)容。
- -PostContent。 定義應(yīng)在表或列表輸出之后顯示的任何內(nèi)容。
其他輸出選項
Out-* 命令的核心功能、常見參數(shù)和典型使用場景:
| Cmdlet | 核心功能 | 常用參數(shù) | 典型應(yīng)用場景 |
|---|---|---|---|
Out-Host |
將輸出發(fā)送到主機(jī)(控制臺)進(jìn)行顯示 | -Paging (強(qiáng)制分頁顯示) |
逐頁查看長輸出,避免滾動過快錯過信息 |
Out-Printer |
將輸出發(fā)送到打印機(jī)進(jìn)行打印 | -Name (指定打印機(jī)名稱) |
打印命令結(jié)果、報告或配置清單 |
Out-GridView |
在交互式表格窗口中顯示輸出,支持排序、篩選和復(fù)制 | -Title (設(shè)置窗口標(biāo)題) |
可視化數(shù)據(jù)分析、快速篩選和分享信息,但無法直接保存 |
Out-Host:控制臺輸出管理
Out-Host是 PowerShell 默認(rèn)的輸出方式,即直接將結(jié)果呈現(xiàn)在控制臺。它的特殊之處在于你可以通過-Paging參數(shù)手動控制輸出分頁-Paging參數(shù):強(qiáng)制對輸出進(jìn)行分頁,顯示一頁后暫停,按空格鍵查看下一頁,按 Q 鍵退出- 與
more命令的關(guān)系:在 PowerShell 中,more是一個內(nèi)置函數(shù),它本質(zhì)上是Out-Host -Paging的別名,兩者功能相同
逐頁查看系統(tǒng)進(jìn)程列表
Get-Process | Out-Host -Paging
# 也可以使用更簡潔的more
Get-Process | more
Out-Printer:打印輸出
Out-Printer允許你將命令的輸出直接發(fā)送到打印機(jī)。- 默認(rèn)行為:不使用參數(shù)時,輸出會發(fā)送到默認(rèn)打印機(jī)
-Name參數(shù):指定目標(biāo)打印機(jī)的名稱,打印機(jī)名稱需與系統(tǒng)中安裝的打印機(jī)名稱匹配(可通過Get-Printercmdlet 查看所有可用打印機(jī))
打印當(dāng)前運(yùn)行的進(jìn)程列表到默認(rèn)打印機(jī)
Get-Process | Out-Printer
將系統(tǒng)服務(wù)狀態(tài)發(fā)送到特定打印機(jī)(假設(shè)打印機(jī)名為 "HP-LaserJet"):
Get-Service | Out-Printer -Name "HP-LaserJet"
打印到虛擬打印機(jī)(如生成PDF):如果你安裝了 Microsoft Print to PDF 這類虛擬打印機(jī),也可以使用 -Name 參數(shù)指定它來生成PDF文件。
Get-Service | Where-Object {$_.Status -eq 'Running'} | Out-Printer -Name "Microsoft Print to PDF"
Out-GridView:交互式表格輸出
Out-GridView(通常簡稱 OGV)是一個非常強(qiáng)大的工具,它會在一個新窗口中以交互式表格的形式顯示輸出。你可以:- 點(diǎn)擊列名進(jìn)行排序(升序/降序)。
- 使用頂部的篩選框?qū)θ魏瘟羞M(jìn)行篩選(支持包含、不包含等條件)。
- 選中行并復(fù)制(Ctrl+C),然后粘貼到 Excel 或其他應(yīng)用程序中。
- 多選(Ctrl+點(diǎn)擊 或 Shift+點(diǎn)擊)。
重要限制:正如你所讀到的,無法直接從 GridView 窗口保存數(shù)據(jù)。你需要先通過復(fù)制粘貼,或在命令行中就使用Export-Csv等命令保存數(shù)據(jù)。
可視化并篩選系統(tǒng)服務(wù):
# 查看所有服務(wù)
Get-Service | Out-GridView
# 僅查看正在運(yùn)行的服務(wù),并自定義窗口標(biāo)題
Get-Service | Where-Object Status -eq 'Running' | Out-GridView -Title "當(dāng)前運(yùn)行的服務(wù)"
# 結(jié)合篩選器:找出所有正在運(yùn)行且名稱中包含 "windows" 的服務(wù)
Get-Service | Where-Object { $_.Status -eq 'Running' -and $_.Name -like '*windows*' } | Out-GridView

在彈出的窗口中,你可以進(jìn)一步點(diǎn)擊“狀態(tài)”列排序,或在“名稱”列篩選器輸入更多關(guān)鍵字。
分析進(jìn)程資源占用:
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | Out-GridView -Title "CPU占用最高的10個進(jìn)程"
自定義列順序:如果你使用 Select-Object 選擇并排序了屬性,Out-GridView 會遵循這個順序顯示列
Get-Service | Select-Object Name, Status, DisplayName, StartType | Out-GridView
傳遞管道對象
管道傳遞數(shù)據(jù)可以有兩種方式:ByValue 和 ByPropertyName
它們最根本的區(qū)別在于匹配的依據(jù):
- ByValue:依據(jù)管道對象的整體類型進(jìn)行匹配。
- ByPropertyName:依據(jù)管道對象的屬性名稱進(jìn)行匹配。
例如運(yùn)行:Get-Help Stop-Process -Full
必須看輸入支持哪種類型:那我們只能輸入下面的這幾種了

那既然我們要傳數(shù)據(jù)給Stop-Process的話那我們就需要知道左邊的那個輸出符不符合這里面的輸入,下面詳細(xì)講一下這個!
ByValue 傳遞數(shù)據(jù)
直接將String類型傳給Get-Service
'BITS','WinRM' | Get-Service
是否成功前可以看下Get-Service接受哪些類型的管道輸入
Get-Help Get-Service -Full

包含string那就可以傳入了
但是這種就不行:
Get-LocalUser | Stop-Process
首先我們看下Stop-Process的接受類型
Get-Help Stop-Process -Full

接著再看Get-LocalUser的輸出是否符合Stop-Process的輸入類型
Get-Help Get-LocalUser -Full
下圖可以看到明顯不符合,輸出的是Object,傳到Stop-Process的時候就肯定報錯了

如何解決?那就交給ByPropertyName,指定輸出一個屬性內(nèi)容即可
ByPropertyName 傳遞數(shù)據(jù)
這里感覺沒啥好說的,就是在ByValue不成立的時候,我們就需要特別指定某個屬性給到下一個要執(zhí)行的命令,但是前提是左邊和右邊的屬性名字要相同,否則在匹配的時候就不知道該屬性給哪個。
(有一個特殊情況就是希望將左邊的A屬性值傳遞給右邊的B屬性,兩個名字不一樣的時候就需要重命名)
重命名方式,這種就比較特殊
Get-Process有一個參數(shù)-ComputerName,它支持通過 ByPropertyName 接收輸入。- 但
Get-ADComputer返回的計算機(jī)對象有一個叫Name的屬性,沒有叫ComputerName的屬性。 - 因此,
Name屬性無法自動傳遞給-ComputerName參數(shù)
這樣就需要重命名了:
Get-ADComputer -Filter * | Select-Object @{Name='ComputerName'; Expression={$_.Name}} | Get-Process
若是說在 ByPropertyName 的時候,兩邊的屬性名相同那就會自動匹配去執(zhí)行操作了(這種就不詳細(xì)說了)
展開屬性值
先看一個動作:
Get-Process –ComputerName (Get-LocalUser –Filter *)
這個是想要將Get-LocalUser給到Get-Process的ComputerName參數(shù)
先看Get-Process的ComputerName接受什么輸入
Get-Help Get-Process -Full
可以看到只接受string類型,那我們直接將整個Get-LocalUser東西穿進(jìn)去肯定不行

再看看這樣行不行
回答:看似可以,其實(shí)也不行
Get-Process –ComputerName (Get-LocalUser –Filter * | Select-Object –Property Name)
我們要看這個–Property Name輸出的到底是不是string
$(Get-LocalUser | Select-Object –Property Name -First 1).GetType()
查看后發(fā)現(xiàn)還是不是string,那這時候就需要用到展開屬性的操作了

其實(shí)就是改了個參數(shù)名:
將Property改為ExpandProperty,下面這樣就可以了
$(Get-LocalUser | Select-Object –ExpandProperty Name -First 1).GetType()
為什么可以,我們直接看下取出來的Name是不是string即可

復(fù)習(xí)提問:
在命令行接口將對象從一個命令傳遞到管道中的另一個命令時,Windows PowerShell 總是優(yōu)先嘗試使用哪種技術(shù)?
ByValue
深入了解Powershell腳本
開發(fā)生命周期與安全強(qiáng)化
PowerShellGet 模塊
| Cmdlet | 說明 |
|---|---|
| Find-Module | 使用此 cmdlet 在 PowerShell 庫中搜索 Windows PowerShell 模塊。 最簡單的用法是根據(jù)模塊名進(jìn)行搜索,但也可以根據(jù)命令名、版本、DscResource 和 RoleCapability 進(jìn)行搜索。 |
| Find-Script | 使用此 cmdlet 在 PowerShell 庫中搜索 Windows PowerShell 腳本。 最簡單的用法是根據(jù)腳本名進(jìn)行搜索,但也可以根據(jù)版本進(jìn)行搜索。 |
| PowerShell 庫需要使用傳輸層安全性 (TLS) 1.2 來幫助保護(hù)通信。 默認(rèn)情況下,Windows 10 和 Windows Server 2016 不支持在 Windows PowerShell 中使用 TLS 1.2。 因此,需要啟用 TLS 1.2 才能下載 PowerShell 庫內(nèi)容。 |
若要為當(dāng)前 PowerShell 提示啟用 TLS 1.2,請運(yùn)行以下命令:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
若要在計算機(jī)上永久解決此問題,需要創(chuàng)建注冊表項。 可以運(yùn)行以下兩個命令來創(chuàng)建必要的密鑰:
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319'-Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319' -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
執(zhí)行策略
確保當(dāng)前配置,可以使用:Get-ExecutionPolicy
執(zhí)行策略的選項包括:
- Restricted:不允許運(yùn)行任何腳本。
- AllSigned:僅當(dāng)腳本經(jīng)過數(shù)字簽名后才能運(yùn)行。
- RemoteSigned:下載的腳本只有在經(jīng)過數(shù)字簽名后才能運(yùn)行。
- Unrestricted:可以運(yùn)行所有腳本,但在運(yùn)行下載但未簽名的腳本時會顯示確認(rèn)提示。
- Bypass:運(yùn)行所有腳本且不顯示提示。
以數(shù)字方式對腳本進(jìn)行簽名
使用現(xiàn)有的代碼簽名證書(如果你有)
如果你已經(jīng)從公共證書頒發(fā)機(jī)構(gòu)(CA)或企業(yè)的內(nèi)部CA獲取并安裝了代碼簽名證書,可以用以下命令查找:
# 在當(dāng)前用戶的證書存儲中查找所有可用于代碼簽名的證書
$certs = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert
# 如果你確定只有一個,可以直接賦值
$cert = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert
Cert:\CurrentUser\My是 PowerShell 證書驅(qū)動器(PSDrive)中的一個路徑,指向當(dāng)前用戶的“個人”證書存儲區(qū)域。-CodeSigningCert參數(shù)是Get-ChildItem在證書驅(qū)動器中專用的,用于篩選出具有“代碼簽名”用途的證書。
創(chuàng)建自簽名證書(用于測試和學(xué)習(xí))
在生產(chǎn)環(huán)境中,你需要一個受信任的CA頒發(fā)的證書。但在測試和學(xué)習(xí)時,可以快速創(chuàng)建一個自簽名證書
# 以管理員身份運(yùn)行 PowerShell 執(zhí)行以下命令
$certParams = @{
Type = 'CodeSigningCert'
Subject = 'CN=PowerShell Scripting Test' # 證書主題,CN是通用名
KeyUsage = 'DigitalSignature' # 密鑰用法:數(shù)字簽名
KeyExportPolicy = 'Exportable' # 密鑰可導(dǎo)出,方便備份和轉(zhuǎn)移
CertStoreLocation = 'Cert:\CurrentUser\My' # 證書存儲位置
HashAlgorithm = 'sha256' # 哈希算法
# FriendlyName 是可選的,便于在證書管理中識別
FriendlyName = 'My PowerShell Test Signing Certificate'
}
$cert = New-SelfSignedCertificate @certParams
重要提示:自簽名證書僅用于測試。因為它不是由受信任的根證書頒發(fā)機(jī)構(gòu)頒發(fā)的,所以其他計算機(jī)默認(rèn)不會信任它。
(你自己創(chuàng)建的,你自己使用的時候就導(dǎo)入即可,不用設(shè)置密碼啥的,因為是你自己創(chuàng)建你自己用,除非你導(dǎo)出的時候就要設(shè)置密碼,因為你導(dǎo)出肯定是要給其他計算機(jī)使用)
從證書文件導(dǎo)入
如果你有 .pfx 或 .p12 格式的證書文件(通常包含私鑰),可以使用 Get-PfxCertificate cmdlet 來加載它:
# 會彈窗提示輸入密碼
$cert = Get-PfxCertificate -FilePath "C:\Path\To\Your\CodeSigningCert.pfx"
# 或者使用SecureString自動輸入密碼(注意密碼安全)
$securePassword = ConvertTo-SecureString -String "YourCertificatePassword" -Force -AsPlainText
$cert = Get-PfxCertificate -FilePath "C:\Path\To\Your\CodeSigningCert.pfx" -Password $securePassword
加載的時候需要密碼,這需要在證書持有者導(dǎo)出證書的時候設(shè)置的那個密碼,然而這個pdx或者p12文件是用來簽名的,不是用來驗證的,用來驗證的那個是cert,這也是為啥要輸入密碼的原因了,這個證書是拿來公章簽名的。
拿到證書對象($cert)后,就可以用它來簽名腳本了。官網(wǎng)的例子是基礎(chǔ),但強(qiáng)烈建議添加時間戳服務(wù)器參數(shù)。
# 基礎(chǔ)簽名(官網(wǎng)示例)
Set-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1" -Certificate $cert
# 推薦的簽名方式(添加時間戳)
$signParams = @{
FilePath = "C:\Scripts\MyScript.ps1" # 要簽名的腳本路徑
Certificate = $cert # 之前獲取的證書對象
HashAlgorithm = 'Sha256' # 哈希算法,建議使用Sha256
# 添加時間戳至關(guān)重要!即使證書過期,時間戳也能證明簽名時證書是有效的。
TimestampServer = 'http://timestamp.digicert.com'
# -IncludeChain 參數(shù)可選,默認(rèn)是 'NotRoot'(包含除根CA以外的所有證書)
# -Force 參數(shù)可選,如果腳本已有簽名,強(qiáng)制替換
}
Set-AuthenticodeSignature @signParams
簽名完成后,務(wù)必檢查一下:
Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"
查看輸出中的 Status 屬性:
Valid:簽名有效且受信任。UnknownError:簽名無效或證書不受信任(常見于自簽名證書)。NotSigned:腳本未簽名。
讓系統(tǒng)信任你的簽名
!!!!!記住這里是驗證,不是用來簽名,前面說的都是pxf和p12證書,這里講的是cer文件!!!!!!!!
對于自簽名證書,由于它不是公共CA頒發(fā)的,你需要將你的自簽名證書**導(dǎo)入到“受信任的根證書頒發(fā)機(jī)構(gòu)”或“受信任的發(fā)布者”存儲區(qū)。否則,在其他計算機(jī)上運(yùn)行時會顯示 UnknownError。
- 將你的證書導(dǎo)出為
.cer文件(只包含公鑰)。 - 在需要運(yùn)行此腳本的計算機(jī)上,將這個
.cer文件導(dǎo)入到“受信任的根證書頒發(fā)機(jī)構(gòu)”或“受信任的發(fā)布者”(對于代碼簽名證書,通常是“受信任的發(fā)布者”)。
你可以使用 PowerShell 自動化導(dǎo)入信任證書的過程
$certPath = "C:\Path\To\Exported\Certificate.cer"
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("TrustedPublisher", "LocalMachine")
$store.Open("ReadWrite")
$store.Add((New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath)))
$store.Close()
進(jìn)階語法
ForEach 循環(huán)
在某些情況下,可能需要使用 ForEach-Object cmdlet 來處理管道中的數(shù)據(jù)。 將數(shù)據(jù)存儲在數(shù)組中時,F(xiàn)orEach 構(gòu)造支持處理數(shù)組中的每個項。
powershell ForEach ($user in $users) { Set-ADUser $user -Department "Marketing" }
在 PowerShell 7 中,已將 -Parallel 參數(shù)添加到 ForEach-Object cmdlet。 這樣,管道就可以同時處理多個對象。 相較于標(biāo)準(zhǔn) ForEach 循環(huán),同時處理多個對象所提供的性能更佳。 如果使用的是 PowerShell 7,應(yīng)考慮這一點(diǎn)。 以下示例說明了如何將 ForEach-Object 與 -Parallel 參數(shù)配合使用。
$users | ForEach-Object -Parallel { Set-ADUser $user -Department "Marketing" }
默認(rèn)情況下,-Parallel 參數(shù)支持一次處理五個項,可以使用 -ThrottleLimit 參數(shù)將其修改為更大或更小的值。
If 構(gòu)造
舉例子:如果可用磁盤空間不足,則可以使用 If 語句顯示警告
If ($freeSpace -le 5GB) {
Write-Host "Free disk space is less than 5 GB"
} ElseIf ($freeSpace -le 10GB) {
Write-Host "Free disk space is less than 10 GB"
} Else {
Write-Host "Free disk space is more than 10 GB"
}
同時也學(xué)到大小是可以直接使用MB、GB等單位直接比較
Switch 構(gòu)造
Switch ($choice) {
1 { Write-Host "You selected menu item 1" }
2 { Write-Host "You selected menu item 2" }
3 { Write-Host "You selected menu item 3" }
Default { Write-Host "You did not select a valid option" }
}
可以使用 -wildcard 參數(shù),以與 -like 運(yùn)算符相同的語法來執(zhí)行模式匹配。 或者,可以使用 -regex 參數(shù)通過正則表達(dá)式執(zhí)行匹配。
Switch -WildCard ($ip) {
"10.*" { Write-Host "This computer is on the internal network" }
"10.1.*" { Write-Host "This computer is in London" }
"10.2.*" { Write-Host "This computer is in Vancouver" }
Default { Write-Host "This computer is not on the internal network" }
}
For 構(gòu)造
For($i=1; $i -le 10; $i++) {
Write-Host "Creating User $i"
}
處理對象數(shù)組時,最好使用 ForEach 構(gòu)造,因為在處理之前不需要計算數(shù)組中的項數(shù)。
其他循環(huán)構(gòu)造
Do..While
Do..While 構(gòu)造運(yùn)行腳本塊,直到指定條件為false
此構(gòu)造保證腳本塊至少運(yùn)行一次
Do {
Write-Host "Script block to process"
} While ($answer -eq "go")
Do..Until
Do..Until 構(gòu)造運(yùn)行腳本塊,直到指定條件為 true
此構(gòu)造保證腳本塊至少運(yùn)行一次
Do {
Write-Host "Script block to process"
} Until ($answer -eq "stop")
While
While 構(gòu)造運(yùn)行腳本塊,直到指定條件為 false
雖然它類似于 Do..While 構(gòu)造,但它不能保證腳本塊的運(yùn)行
While ($answer -eq "go") {
Write-Host "Script block to process"
}
Break 和 Continue
使用 Continue 可阻止修改要修改的用戶列表中的管理員用戶帳戶:
ForEach ($user in $users) {
If ($user.Name -eq "Administrator") {Continue}
Write-Host "Modify user object"
}
Break 用于在最大帳戶數(shù)已修改時結(jié)束循環(huán):
ForEach ($user in $users) {
$number++
Write-Host "Modify User object $number"
If ($number -ge $max) {Break}
}
導(dǎo)入數(shù)據(jù)
Get-Content
直接讀取文件內(nèi)容進(jìn)來
$computers = Get-Content C:\Scripts\computers.txt
可在 Get-Content 的路徑中使用通配符,以便一次獲得多個文件的數(shù)據(jù)
可使用 -Include 和 -Exclude 參數(shù)修改所選文件
Get-Content -Path "C:\Scripts\*" -Include "*.txt","*.log"
可以使用 -TotalCount 和 -Tail 參數(shù)限制使用 Get-Content 檢索的數(shù)據(jù)量
- -TotalCount 參數(shù)指定應(yīng)從文件開頭檢索多少行
- -Tail 參數(shù)指定從文件末尾檢索多少行
例如:
Get-Content C:\Scripts\computers.txt -TotalCount 10
Import-Csv
$users = Import-Csv C:\Scripts\Users.csv
輸出示例:
First,Last,UserID,Department
Amelie,Garner,AGarner,Sales
Evan,Norman,ENorman,Sales
Siu,Robben,SRobben,Sales
當(dāng)我們存進(jìn)一個變量后,也可以通過變量訪問某個數(shù)據(jù)
$users[2].UserID
Import-Csv 默認(rèn)分隔符是逗號,有的文件不是以逗號進(jìn)行分割的話你也可以使用Import-Csv,只要格式相同分隔符不同也可以用這個,前提是你要自己加參數(shù)去修改分隔符:
比如說分隔符是分號
Import-Csv -Path .\1.csv -Header h1,h2,h3 -Delimiter ';'

Import-Clixml
$users = Import-Clixml C:\Scripts\Users.xml
使用 -First 和 -Skip 參數(shù)來限制 Import-Clixml 檢索的數(shù)據(jù)
- -First 參數(shù)指定僅從 XML 文件的開頭檢索指定數(shù)量的對象
- -Skip 參數(shù)指定從 XML 文件開頭忽略指定數(shù)量的對象,并檢索所有剩余的對象。
ConvertFrom-Json
$users = Get-Content C:\Scripts\Users.json | ConvertFrom-Json
Invoke-RestMethod
Invoke-RestMethod 能夠處理JSON、 XML、RSS 源和 ATOM 源。
$users = Invoke-RestMethod "https://hr.adatum.com/api/staff"
接受用戶輸入
Read-Host
這種會在How many das后加上冒號然后提示用戶輸入:
$answer = Read-Host "How many days"
下面這種會先打印How many days? ,-NoNewline就是不換行,然后也是等待用戶輸入
這種就沒有冒號
Write-Host "How many days? " -NoNewline
$answer = Read-Host
-MaskInput 或 -AsSecureString 參數(shù)在提示符處屏蔽輸入用戶,這種偏向于輸入密碼的時候不會直接顯示在終端上
$answer = Read-Host "How many days" -AsSecureString
具體使用哪個看情況了,我的電腦使用AsSecureString才行
Credential憑證使用
Get-Credential
它的核心作用就是安全地彈窗收集用戶憑據(jù)(用戶名和密碼),并將其封裝在一個 PSCredential 對象中,供其他需要憑據(jù)的 cmdlet 使用。
基礎(chǔ)用法:
這會彈出一個標(biāo)準(zhǔn)對話框,讓你輸入用戶名和密碼。
$cred = Get-Credential
高級用法(自定義提示和用戶名):
-Message:讓提示更清晰,指導(dǎo)用戶輸入什么憑據(jù)。-UserName:預(yù)填用戶名字段,用戶只需要輸入密碼即可。$env:COMPUTERNAME是環(huán)境變量,代表本機(jī)計算機(jī)名,這在工作組環(huán)境下至關(guān)重要。
# 自定義提示信息并預(yù)填用戶名
$cred = Get-Credential -Message "請輸入本地管理員權(quán)限憑據(jù)" -UserName "$env:COMPUTERNAME\Administrator"
遠(yuǎn)程管理另一臺工作組計算機(jī)
假設(shè)你想從計算機(jī) CLIENT-A 遠(yuǎn)程管理計算機(jī) CLIENT-B
# 在 CLIENT-A 上運(yùn)行
# 1. 獲取 CLIENT-B 的本地管理員憑據(jù)
$cred = Get-Credential -Message "請輸入CLIENT-B的本地管理員憑據(jù)" -UserName "CLIENT-B\Administrator"
# 2. 建立遠(yuǎn)程會話 (PSRemoting)
$session = New-PSSession -ComputerName "CLIENT-B" -Credential $cred
# 3. 在遠(yuǎn)程會話中執(zhí)行命令(例如:檢查磁盤空間)
Invoke-Command -Session $session -ScriptBlock { Get-Volume }
# 4. 關(guān)閉會話
Remove-PSSession $session
本地腳本臨時提權(quán)
你用自己的標(biāo)準(zhǔn)用戶賬戶登錄,但腳本中的某些操作(如修改系統(tǒng)設(shè)置)需要管理員權(quán)限。
# 檢查當(dāng)前用戶權(quán)限,如果不是管理員則請求憑據(jù)
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Warning "此操作需要管理員權(quán)限。"
$adminCred = Get-Credential -Message "請?zhí)峁┍镜毓芾韱T密碼以繼續(xù)" -UserName "$env:COMPUTERNAME\Administrator"
# 使用 Start-Process 以管理員身份啟動一個新進(jìn)程來運(yùn)行命令
$scriptBlock = {
# 這里放需要提權(quán)的命令,例如安裝Windows功能
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
}
Start-Process "pwsh" -ArgumentList "-Command", $scriptBlock -Credential $adminCred -Wait -NoNewWindow
} else {
# 如果已經(jīng)是管理員,直接執(zhí)行命令
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
}
訪問受保護(hù)的網(wǎng)絡(luò)共享
掛載一個需要特定用戶名和密碼才能訪問的局域網(wǎng)共享文件夾。
$netCred = Get-Credential -Message "請輸入訪問共享\\FileServer\Data$的憑據(jù)" -UserName "FileServer\SomeUser"
# 將憑據(jù)映射到驅(qū)動器號
New-PSDrive -Name "Z" -PSProvider "FileSystem" -Root "\\FileServer\Data$" -Credential $netCred -Persist
# 現(xiàn)在可以像訪問本地磁盤一樣訪問 Z:\
Get-ChildItem Z:\
# 使用完畢后斷開
Remove-PSDrive -Name "Z"
Export-Clixml
首次保存憑據(jù)(在一臺電腦上):
# 彈窗輸入一次憑據(jù)
$cred = Get-Credential -Message "輸入要保存的憑據(jù)" -UserName "MyPC\Admin"
# 將加密后的憑據(jù)保存到文件(只能由你在本機(jī)解密)
$cred | Export-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"
后續(xù)腳本中自動使用保存的憑據(jù):
# 無需彈窗,直接讀取加密文件獲取憑據(jù)對象
$savedCred = Import-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"
# 使用憑據(jù)執(zhí)行需要權(quán)限的操作,例如重啟遠(yuǎn)程計算機(jī)
Restart-Computer -ComputerName "192.168.1.100" -Credential $savedCred -Force
腳本故障排除與錯誤處理
錯誤發(fā)生時,它們將存儲在 $Error 數(shù)組中。 最近的錯誤始終在索引零處。 新錯誤生成時,會插入到 $Error[0] 處,其他錯誤的索引將增加一。 每當(dāng)需要查看以前的錯誤消息時,查看 $Error 中的錯誤會很有幫助。 例如,如果清除屏幕,則可以通過 $Error 查看最近的錯誤消息。
輸出命令的層次與用途
PowerShell 的輸出命令不是一個簡單的“打印”功能,而是一個完整的信息流系統(tǒng)。理解不同命令的定位是關(guān)鍵。
| 命令 | 用途 | 輸出位置 | 是否受 *Preference 變量影響 |
適用場景 |
|---|---|---|---|---|
Write-Host |
直接與用戶交互 | 控制臺 (主機(jī)) | 否 | 顯示進(jìn)度、美觀的標(biāo)題、即時提示。謹(jǐn)慎使用。 |
Write-Output |
將對象放入輸出管道 | 管道 / 控制臺 | 否 | 腳本的主要輸出結(jié)果。通常隱式使用(如 "Hello")。 |
Write-Verbose |
輸出詳細(xì)信息 | 控制臺 ( verbose流) | 是 | 調(diào)試、記錄腳本執(zhí)行的詳細(xì)步驟。 |
Write-Debug |
輸出調(diào)試信息 | 控制臺 (debug流) | 是 | 更深入的調(diào)試,可在運(yùn)行時暫停腳本。 |
Write-Warning |
輸出警告信息 | 控制臺 (warning流) | 是 | 提示用戶潛在的問題,但腳本會繼續(xù)執(zhí)行。 |
Write-Error |
輸出錯誤信息 | 控制臺 (error流) | 是 | 報告錯誤,但不終止腳本執(zhí)行。 |
Throw |
拋出終止錯誤 | 控制臺 (error流) | - | 報告嚴(yán)重錯誤,并立即終止當(dāng)前函數(shù)/腳本。 |
Write-Verbose 和 Write-Debug:真正的調(diào)試?yán)?/p>
這兩個命令的強(qiáng)大之處在于它們的可控性。默認(rèn)情況下它們是靜默的,只在需要時通過參數(shù)開啟。
示例腳本 (Test-Service.ps1):
[CmdletBinding()] # 啟用高級功能,支持 -Verbose 和 -Debug 參數(shù)
param (
[Parameter(Mandatory=$true)]
[string]$ServiceName
)
Write-Verbose "腳本開始執(zhí)行,傳入的服務(wù)名參數(shù)為: $ServiceName"
# 檢查服務(wù)是否存在
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
Write-Debug "Get-Service 查詢結(jié)果: $($service | Out-String)"
if (-not $service) {
Write-Error "錯誤: 找不到名為 '$ServiceName' 的服務(wù)。"
exit 1
}
Write-Verbose "服務(wù)狀態(tài): $($service.Status)"
if ($service.Status -ne 'Running') {
Write-Warning "服務(wù) '$ServiceName' 當(dāng)前未運(yùn)行。"
# 嘗試啟動服務(wù)
try {
Start-Service -Name $ServiceName
Write-Host "服務(wù)已成功啟動。" -ForegroundColor Green
}
catch {
Throw "啟動服務(wù)失敗: $($_.Exception.Message)"
}
} else {
Write-Output "服務(wù) '$ServiceName' 正在運(yùn)行。"
}
Write-Verbose "腳本執(zhí)行完畢。"
如何使用這個腳本:
- 默認(rèn)運(yùn)行(只看到基本輸出):
.\Test-Service -ServiceName "WinRM"
# 輸出: 服務(wù) 'WinRM' 正在運(yùn)行。
- 查看詳細(xì)信息(使用
-Verbose):
.\Test-Service -ServiceName "WinRM" -Verbose
# 輸出:
# 詳細(xì): 腳本開始執(zhí)行,傳入的服務(wù)名參數(shù)為: WinRM
# 詳細(xì): 服務(wù)狀態(tài): Running
# 服務(wù) 'WinRM' 正在運(yùn)行。
# 詳細(xì): 腳本執(zhí)行完畢。
- 進(jìn)行深度調(diào)試(使用
-Debug):
.\Test-Service -ServiceName "SomeService" -Debug
運(yùn)行后會首先顯示 Write-Debug 的信息,并暫停,提示你:
調(diào)試: Get-Service 查詢結(jié)果:
(這里會顯示Get-Service返回的詳細(xì)對象信息)
繼續(xù)執(zhí)行?
[Y] 是(Y) [A] 全是(A) [N] 否(N) [L] 全否(L) [S] 暫停(S) [?] 幫助 (默認(rèn)值為“Y”):
按 `Y` 繼續(xù)執(zhí)行每一步,按 `A` 讓它自動執(zhí)行完所有調(diào)試步驟。這讓你可以一步步觀察腳本的執(zhí)行流程。
使用 $VerbosePreference 和 $DebugPreference 進(jìn)行全局控制
在當(dāng)前會話中開啟所有Verbose輸出:
$VerbosePreference = "Continue" # 默認(rèn)是 "SilentlyContinue"
.\Test-Service -ServiceName "WinRM"
# 現(xiàn)在即使不加 -Verbose,也會輸出Verbose信息
在腳本開頭強(qiáng)制開啟調(diào)試(常用于日志記錄):
[CmdletBinding()]
param()
# 在腳本內(nèi)部設(shè)置,強(qiáng)制記錄詳細(xì)信息到日志文件
$VerbosePreference = "Continue"
Write-Verbose "$(Get-Date): 腳本啟動..."
# ... 腳本邏輯 ...
腳本中使用斷點(diǎn)
根據(jù)行進(jìn)行斷點(diǎn)
可使用 Set-PSBreakPoint cmdlet 設(shè)置斷點(diǎn)
可以基于腳本行、正在使用的特定命令或正在使用的特定變量來設(shè)置斷點(diǎn)
以下示例描述如何在腳本的特定行處設(shè)置斷點(diǎn):
Set-PSBreakPoint -Script "MyScript.ps1" -Line 23
根據(jù)命令進(jìn)行斷點(diǎn)
Set-PSBreakPoint -Command "Set-ADUser" -Script "MyScript.ps1"
基于命令設(shè)置斷點(diǎn)時,可以包含通配符。 例如,可以使用值 *-ADUser 為 Get-ADUser、Set-ADUser、New-ADUser 和 Remove-ADUser 觸發(fā)斷點(diǎn)。
根據(jù)特定變量進(jìn)行斷點(diǎn)
Set-PSBreakPoint -Variable "computer" -Script "MyScript.ps1" -Mode ReadWrite
可以使用變量的 -Mode 參數(shù)來確定是否要在讀取和/或?qū)懭胱兞恐禃r中斷。 有效值為 Read、Write 和 ReadWrite。
以上是終端中運(yùn)行腳本的時候設(shè)置的斷點(diǎn),其實(shí)我們可以用:
- Powershell ISE 圖形化工具進(jìn)行根據(jù)行去斷點(diǎn)
- VScode 中也能夠進(jìn)行更多高級的斷點(diǎn)方式
錯誤操作
$ErrorActionPreference
內(nèi)置全局變量。 當(dāng)命令生成非終止錯誤時,命令會檢查此變量來決定該執(zhí)行的操作
變量可具有下面 4 個可能值之一:
- Continue 是默認(rèn)值,它告知命令顯示錯誤消息并繼續(xù)運(yùn)行。
- SilentlyContinue 告知命令不顯示錯誤消息,但要繼續(xù)運(yùn)行。
- Inquire 告知命令顯示提示,詢問用戶要做什么。
- Stop 告知命令將錯誤視為終止錯誤并停止運(yùn)行。
若要設(shè)置 $ErrorActionPreference 變量,請使用以下語法:
$ErrorActionPreference = 'Inquire'
-ErrorAction
所有 Windows PowerShell 命令都有 –ErrorAction 參數(shù)。 此參數(shù)具有別名 –EA
當(dāng)你使用他的時候,會覆蓋$ErrorActionPreference但可以設(shè)置一樣的類型,該參數(shù)僅針對當(dāng)前使用的cmdlet
函數(shù)與模塊
有參函數(shù):
Function Get-SecurityEvent {
Param (
[string]$ComputerName
) #end Param
Get-EventLog -LogName Security -ComputerName $ComputerName -Newest 10
}
無參函數(shù)就很簡單了,不寫接受參數(shù)的變量即可
函數(shù)調(diào)用如下:
Get-SecurityEvent -ComputerName LON-DC1
變量范圍
使用范圍修飾符 (Scope Modifiers) 指定目標(biāo)作用域
這是修改其他作用域中變量的關(guān)鍵方法。通過在變量名前加修飾符來指定目標(biāo)作用域
| 修飾符 | 作用 | 語法示例 | 說明 |
|---|---|---|---|
$global: |
修改全局作用域中的變量。 | $global:MyVariable = "新值" |
在任何地方(函數(shù)、腳本)都能訪問和修改這個全局變量。慎用,容易造成污染。 |
$script: |
修改腳本作用域中的變量。 | $script:MyVariable = "新值" |
在當(dāng)前腳本文件的任何函數(shù)內(nèi)部修改在腳本頂層定義的變量。這是最常用、最安全的方式。 |
$using: |
在遠(yuǎn)程命令或腳本塊中引用當(dāng)前局部作用域的變量。 | Invoke-Command { ... -Name $using:LocalVar } |
用于將本地變量的值傳遞到遠(yuǎn)程會話或新腳本塊中,而不是在遠(yuǎn)程會話中修改它。 |
$private: |
在當(dāng)前作用域創(chuàng)建變量,且該變量不會傳遞到更高級的作用域。 | $private:TempVar = "值" |
用于限制變量范圍,確保其不會影響父作用域。較少用。 |
示例:
假設(shè)您在腳本頂層定義了 $configPath,現(xiàn)在需要在一個函數(shù)里修改它:
Set-Variable指定作用域
Set-Variable -Name "MyVariable" -Value "新的值" -Scope <ScopeName>
-Scope 參數(shù)值:
'Global': 修改全局作用域。'Script': 修改腳本作用域。'Local': 修改當(dāng)前局部作用域(默認(rèn)值)。'Private': 修改為私有作用域。
絕大多數(shù)情況下,您應(yīng)該使用 $script: 修飾符
這是在函數(shù)內(nèi)修改腳本級變量的最標(biāo)準(zhǔn)、最可讀且副作用最小的方式。
類似指針修改
使用[ref]去拿到真實(shí)的那個變量在函數(shù)里面去修改,而不是說每次修改的都是函數(shù)內(nèi)部接受到的值,他會直接影響到函數(shù)外部那個傳進(jìn)來的變量的值
function Modify-ByReference {
param (
[ref]$RefValue
)
$RefValue.Value = "在函數(shù)內(nèi)部被修改了" # 注意:是修改 .Value 屬性
}
$OriginalVariable = "原始值"
Modify-ByReference -RefValue ([ref]$OriginalVariable)
Write-Host $OriginalVariable # 輸出:在函數(shù)內(nèi)部被修改了
但是我們是避免這樣去修改變量的,要改的話最好是通過return返回值,然后在函數(shù)外部去改變某個變量
return
好像沒啥好說的,就是return值
function xxx{
xxx
return($var) # return "xxx" return $var
}
$ch = xxx()
創(chuàng)建模塊
你必須創(chuàng)建與該文件同名的子文件夾,并將文件放在該子文件夾中
例如,如果你有一個名為 AdatumFunctions.psm1 的模塊,
則將其放置在 C:\Program Files\WindowsPowerShell\Modules\AdatumFunctions 中。
本文來自博客園,作者:竹等寒,轉(zhuǎn)載請注明原文鏈接。

浙公網(wǎng)安備 33010602011771號