动态

详情 返回 返回

Powershell 進階語(三) - 动态 详情

目錄
  • PowerShell 管道
    • 管道輸出
    • 控制管道輸出的格式設置
      • Format-List
      • Format-Table
      • Format-Wide
    • 管道選擇、排序和度量對象
      • 排序和分組
        • Sort-Object
        • Format 的 GroupBy分組
      • 度量管道中的對象
      • Select-Object
      • Unique去重
      • Property
      • 自定義屬性並設置表達式與格式
        • 計算
    • 從管道中篩選對象
      • 比較運算符
      • 基本篩選器語法
      • 高級篩選器語法
        • 組合多個條件
        • True 或 False 的屬性篩選使用技巧
        • 高級篩選不受簡單篩選限制
      • 優化篩選器性能
    • 枚舉
      • 枚舉管道對象語法
      • 寫入到文件
        • 轉換為其他形式的數據表示形式
          • Csv
          • XML
          • Json
          • HTML
          • 其他輸出選項
    • 傳遞管道對象
      • ByValue 傳遞數據
      • ByPropertyName 傳遞數據
      • 展開屬性值
  • 深入瞭解Powershell腳本
    • 開發生命週期與安全強化
      • PowerShellGet 模塊
      • 執行策略
      • 以數字方式對腳本進行簽名
    • 進階語法
      • ForEach 循環
      • If 構造
      • Switch 構造
      • For 構造
      • 其他循環構造
        • Do..While
        • Do..Until
        • While
      • Break 和 Continue
      • 導入數據
        • Get-Content
        • Import-Csv
        • Import-Clixml
        • ConvertFrom-Json
        • Invoke-RestMethod
      • 接受用户輸入
        • Read-Host
      • Credential憑證使用
        • Get-Credential
        • Export-Clixml
    • 腳本故障排除與錯誤處理
      • 輸出命令的層次與用途
      • 腳本中使用斷點
        • 根據行進行斷點
        • 根據命令進行斷點
        • 根據特定變量進行斷點
      • 錯誤操作
        • $ErrorActionPreference
          • -ErrorAction
    • 函數與模塊
      • 變量範圍
          • Set-Variable指定作用域
        • 類似指針修改
        • return
      • 創建模塊

PowerShell 管道

管道輸出

PowerShell 命令不會生成文本作為輸出,而是會生成對象,對象是描述內存中數據結構的通用詞。

運行 Get-Service 命令時,它會返回服務對象的集合,每個對象都包含 Name、DisplayName 和 Status 等名稱的屬性。

控制管道輸出的格式設置

格式設置 cmdlet 為:

  • Format-List
  • Format-Table
  • Format-Wide
  • Format-Custom
Format-Custom cmdlet 需要創建定義格式的自定義 XML 配置文件。 該 cmdlet 不經常使用。

Format-List

Format-List cmdlet 將命令的輸出格式化為一個簡單的屬性列表,其中每個屬性顯示在一個新行上。
 如果將輸出傳遞給 Format-List 的命令返回多個對象,則會為每個對象顯示單獨屬性列表。
 當命令返回大量很難以表格格式查看的屬性時,列表格式尤其有用。

Format-List cmdlet 的別名是 fl。

Format-Table

Format-Table cmdlet 將輸出格式化為表格,其中每一行表示一個對象,每一列表示一個屬性。

這個輸出的效果和默認的沒啥效果,多了一個就是你可以選擇參數來進行定義你輸出的效果,下面介紹參數↓↓↓
可使用多種參數修改此格式,例如:

  • -AutoSize。 此參數可根據數據的寬度來調整列的大小和數量。 在 Windows PowerShell 5.0 及更高版本中,-AutoSize 默認設置為 true。 在更低版本的 Windows PowerShell 中,默認值可能會截斷表中的數據。

  • -HideTableHeaders。 此參數會從輸出中移除表標頭。

  • -Wrap。 此參數會使超出列寬的文本換行到下一行。

    Format-Table cmdlet 的別名是 ft。

Format-Wide

Format-Wide cmdlet 的輸出是單個列表中分多列顯示的單個屬性。

這個其實只需要知道:使用 -Property 參數,指定一個屬性去進行多個列展示,不用單個列展示這麼難看
下面展示的就是服務的所有名字,但是我們是用3列進行展示

Get-Service | fw -Property Name -Column 3

管道選擇、排序和度量對象

排序和分組

Sort-Object

Sort-Object 命令接受一個或多個屬性名作為排序依據, 默認情況下,命令按升序排序

Get-Service | Sort-Object –Property Name –Descending
Get-Service | Sort Name –Desc 
Get-Service | Sort Status,Name

默認情況下,字符串屬性的排序不考慮大小寫。
(但是Sort-Object 也有參數去支持指定區分大小寫的排序、特定區域性的排序規則和其他選項)

Format 的 GroupBy分組

Format-List、Format-Table 和 Format-Wide 格式設置 cmdlet 具有接受屬性名的 -GroupBy 參數。 通過使用 -GroupBy 參數,可以按指定屬性對輸出進行分組。
注意:這裏説的是Format的幾個格式設置的分組,所以要用格式cmdlet然後再使用這個GroupBy參數

Get-Service | Sort-Object Status,Name | fw -GroupBy Status

-GroupBy 參數的運行方式與 Group-Object 命令類似。 Group-Object 命令接受管道輸入,讓你可以更好地控制對象分組。 Group-Object 具有別名 group。

度量管道中的對象

Measure-Object 默認情況下,該命令會對集合中的對象數進行計數,並生成包含計數的測量對象。

使用 Measure-Object 的 -Property 參數可指定單個屬性,該屬性必須包含數值。 隨後,可以添加 -Sum、-Average、-Minimum 和 -Maximum 參數,以計算指定屬性的這些聚合值。
(通常可注意到 -Sum、-Average、-Minimum 和 -Maximum 參數被截斷為 -Sum、-Ave、-Min 和 -Max)

以下命令計算文件夾中的文件數,並顯示文件大小的最小、最大和平均值:
(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
  • 選擇最少虛擬內存使用量排名前 10 的進程
Get-Process | Sort-Object –Property VM | Select-Object –First 10
  • 選擇最後 10 個正在運行的服務並按名稱排序
Get-Service | Sort-Object –Property Name | Select-Object –Last 10
  • 選擇 CPU 用量最少的五個進程,並跳過使用最少 CPU 的那一個進程
Get-Process | Sort-Object –Property CPU –Descending | Select-Object –First 5 –Skip 1

Unique去重

只需要在指定對象後添加多一個-Unique參數即可

  • 顯示某個用户在每個部門中的用户信息
Get-ADUser -Filter * -Property Department | Sort-Object -Property Department | Select-Object Department -Unique

Property

沒啥好説的,就是select-object 的 參數Property 指定顯示的進程屬性即可

  • 顯示一個表,其中包含本地計算機上運行的所有進程的名稱、進程 ID、虛擬內存大小、分頁內存大小和 CPU 使用率:
Get-Process | Select-Object –Property Name,ID,VM,PM,CPU | Format-Table
  • -Property 參數適用於 -First 或 -Last 參數。 以下命令返回具有最大 CPU 使用率的 10 個進程的名稱和 CPU 使用率:
Get-Process | Sort-Object –Property CPU –Descending | Select-Object –Property Name,CPU –First 10

自定義屬性並設置表達式與格式

  • 定義屬性的名字:
    • label、l、name 或 n:這指定計算屬性的標籤或名稱。 由於小寫字母 l 在某些字體中類似於數字 1,因此請嘗試使用 name、n 或 label。
  • 設置屬性計算的式子:
    • expression 或 e:這將指定設置計算屬性值的表達式。
Get-Process |
Select-Object Name,ID,@{n='VirtualMemory';e={$PSItem.VM}},@{n='PagedMemory';e={$PSItem.PM}}

$PSItem 是由 Windows PowerShell 創建的特殊變量。 它表示通過管道傳輸到 Select-Object 命令中的任何對象。 在上一個示例中,這是一個 Process 對象。 $PSItem 之後的句點允許訪問對象的單個成員。 在此示例中,一個計算屬性使用 VM 屬性,另一個使用 PM 屬性。
當我們輸入正常的Get-Process 並獲取他的所有屬性的時候你會看到VM這個屬性,所以我們$PSItem.VM是能夠獲取到的

檢查一下是否有VM

Get-Process | Get-Member | Select-Object -Property Name | Format-Wide -Column 5

下圖可以看到確實有VM屬性


  • 為什麼用@{}
    解釋:還記不記得之前創建空數組是用@(),這裏是創建hash表,所以用@{},n是屬性名,對應鍵,e是計算式子相當於值,所以説我們還能知道在自定義的時候不能定義同一個名字的屬性

計算

你可能想要修改前面的命令以顯示內存值(以兆字節 (MB) 為單位)。 PowerShell 將縮寫 KB、MB、GB、TB 和 PB 分別表示千字節、兆字節、千兆字節、兆兆字節和拍字節。 因此,可以按如下所示修改命令:
($PSItem是接收傳過來的對象,$_也是一樣的, 用的比較多的是$_,所以説我們可以在Get-Process出來的對象中一個個用$PSItem去取你想要的屬性或者激活方法)

Get-Process |
Select-Object Name,
              ID,
              @{n='VirtualMemory(MB)';e={$PSItem.VM / 1MB}},
              @{n='PagedMemory(MB)';e={$PSItem.PM / 1MB}}

生成的值有幾個小數位,這在視覺上是不理想的。
若要改進輸出,請進行以下更改:

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] }}

上一個示例中的語法可能看起來令人困惑,因為它包含許多標點符號。 從基本表達式開始:

'{0:N2}' –f ($PSItem.VM / 1MB)

上一個表達式將 VM 屬性除以 1 MB,然後將結果格式化為最多兩個小數位的數字。 然後將該表達式放入哈希表中:
該哈希表創建名為 VirtualMemory(MB) 的自定義屬性。

@{n='VirtualMemory(MB)';e={'{0:N2}' –f ($PSItem.VM / 1MB) }}

從管道中篩選對象

比較運算符

操作 DESCRIPTION
-eq 等於
-ne 不等於
-gt 大於
-lt 小於
-le 小於或等於
-ge 大於或等於

在powershell中默認是不區分大小寫,但是在比較的時候難免希望對大小寫的區分
所以我們可以在操作中添加一個前綴c作為比較區分大小寫的標誌

-ceq
-cne

不僅僅上述的運算符,其他也都可以加c

當然還有like也可以用來區分大小寫去匹配,因為-like 運算符類似於 -eq
-clike

其他更高級的運算符存包括:

  • -in 和 -contains 運算符,用於測試集合中是否存在對象。
  • -as 運算符,用於測試對象是否為指定類型。
  • 將字符串與正則表達式進行比較的 -match 和 -cmatch 運算符。
  • 還包含許多運算符來反轉比較的邏輯,例如 -notlike 和 -notin

簡單案例:

PS C:\> 100 -gt 10 
True 
PS C:\> 'hello' -eq 'HELLO' 
True 
PS C:\> 'hello' -ceq 'HELLO' 
False

基本篩選器語法

Where-Object 命令及其別名 Where

  • 僅顯示正在運行的服務的列表
Get-Service | Where Status –eq Running

基本語法的限制

只能對單個比較使用基本語法。 例如,無法顯示已停止且具有“自動”啓動模式的服務列表,因為需要兩個比較。
不能將基本語法用於複雜表達式。 例如,服務對象的 Name 屬性由一串字符組成。 PowerShell 使用 System.String 對象包含該串字符,而 System.String 對象具有 Length 屬性。 以下命令不適用於基本篩選語法:

Get-Service | Where Name.Length –gt 5

目的是顯示名稱超過五個字符的所有服務。 但是,此命令永遠不會生成輸出。 一旦超過基本語法的能力,必須改用高級篩選語法。

高級篩選器語法

高級語法使用篩選器腳本
使用 -FilterScript 參數傳遞該腳本塊
對於通過管道傳遞到命令的每個對象,篩選器腳本都會運行一次。 當篩選器腳本返回 True 時,該對象將作為輸出傳遞到管道中,當篩選器腳本返回 False 時,將從管道中刪除該對象。

以下兩個命令具有相同的功能。 第一個命令使用基本語法,第二個命令使用高級語法執行相同的操作:

Get-Service | Where Status –eq Running

Get-Service | Where-Object –FilterScript { $PSItem.Status –eq 'Running' }

-FilterScript 參數是位置參數,大多數用户會省略它。 大多數用户還會使用 Where 別名或 ? 別名,此名稱長度更短。
推薦使用 $_ 變量而不是 $PSItem,因為在 Windows PowerShell 1.0 和 Windows PowerShell 2.0 中只允許使用 $_

以下命令執行與前兩個命令相同的任務:

Get-Service | Where {$PSItem.Status –eq 'Running'}

Get-Service | ? {$_.Status –eq 'Running'}

組合多個條件

高級語法允許通過使用 -and 和 -or 布爾值或邏輯運算符來組合多個條件。 下面是一個示例:

Get-EventLog –LogName Security –Newest 100 |
Where { $PSItem.EventID –eq 4672 –and $PSItem.EntryType –eq 'SuccessAudit' }

邏輯運算符的任意一側都必須是一個完整的比較式子,下面給幾個錯誤示範,請不要犯錯:

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。

獲取正在響應的進程的列表,可以使用以下命令之一:

Get-Process | Where { $PSItem.Responding –eq $True }

Get-Process | Where { $PSItem.Responding }

在第一個命令中,特殊 shell 變量 $True 用於表示布爾值 True。 第二個命令未包含任何比較,但它是有效的,因為 Responding 屬性已包含 True 或 False
這類似於反向邏輯,僅列出未響應的進程:

Get-Process | Where { -not $PSItem.Responding }

在前面的示例中,-not 邏輯運算符將 True 更改為 False,並將 False 更改為 True。 因此,如果進程未響應,則其 Responding 屬性為 False。 -not 運算符將結果更改為 True,這會使進程被傳遞到管道中,幷包含在命令的最終輸出中。

高級篩選不受簡單篩選限制

現在再去根據字符長度來篩選就沒問題了

Get-Service | Where {$PSItem.Name.Length –gt 8}

優化篩選器性能


説是優化,但其實都是靠編寫腳本自己的功底


Get-隨便 對於下面兩個示例,你認為哪一個速度更快?

Get-隨便 | Sort-Object –Property Letter | Where-Object –FilterScript { $PSItem.Color –eq 'Red' }

Get-隨便 | Where-Object –FilterScript { $PSItem.Color –eq 'Red' } | Sort-Object –Property Letter

第二個命令速度更快,因為他先是移除了不要的再進行排序,這加速了排序,但是如果你排序了再移除就表示你排序排了沒用的東西,然後還要移除,那就慢了。

再比如下面這個查找文件,一看就知道是第二個塊了,內置的直接使用更快

Get-ChildItem | Where { -not $PSItem.PSIsContainer }

Get-ChildItem -File

枚舉

這裏的枚舉是説powershell取出來的對象在管道中每一個都傳遞給下一個cmdlet去操作。
比如:停止計算機上每個正在運行的記事本進程,則可以運行以下兩個命令之一

Get-Process –Name Notepad | Stop-Process

Stop-Process –Name Notepad

比如Get-Process 篩選了名字為Notepad的,那就可能會出現很多個進程,那給到管道後面的Stop-Process來説,他就是在枚舉每一個Notepad進程然後執行停止進程操作

枚舉管道對象語法

這裏官網分了基本語法和高級語法,但其實枚舉管道都支持
基本和高級的區分就是:基本的不用腳本,高級的用腳本塊

查看下ForEach-Object的幫助文檔:
可以看到有兩個參數,一個是接腳本塊的,一看就是高級用法
基本用法應該就是下面的-MemberName指定屬性或方法名的了


基本語法:
兩個常見別名: ForEach 和 %。 與 Where-Object 一樣, ForEach-Object 具有基本語法和高級語法。
下面三個都一樣,原理都是將Get-ChildItem取出來的對象 ([System.IO.FileInfo])進行For枚舉出來然後參數-MemberName就是取屬性或者方法,那我們給的Encrypt就是一個方法(加密),所以我們就相當於給當前遍歷的對象執行了該方法,以此類推每一個對象都會執行一次。

Get-ChildItem –Path C:\Encrypted\  -File | ForEach-Object  -MemberName Encrypt

# 使用了別名和忽略了參數
Get-ChildItem –Path C:\Encrypted\ -File | ForEach Encrypt

# 使用了別名和忽略了參數
Get-ChildItem –Path C:\Encrypted\ -File | % Encrypt

你可以特地去查看下是否有該方法:

 Get-ChildItem | Get-Member -Name Encry*


高級語法:就是使用腳本塊

使用高級語法加密一組文件

Get-ChildItem –Path C:\ToEncrypt\ -File | ForEach-Object –Process { $PSItem.Encrypt() }

範圍運算符是兩個句點 (..),中間沒有空格,range 運算符生成從 1 到 3 的整數對象,這 3 個對象通過管道傳遞給 ForEach-Object,迫使腳本塊運行 3 次

1..3 | ForEach-Object { Get-Random }

寫入到文件

Out-File就相當於cmd裏面的文本重定向運算符 >>>,這些運算符可作為 Out-File 的別名,管道末尾的大於號 (>) 將輸出定向到文件,從而覆蓋內容,兩個連續的大於號 (>>) 將輸出定向到文件,從而將輸出附加到文件中已有的任何文本。

例如:
下面這個雖然説輸出到csv文件,但其實就是文本格式輸入進去,沒有csv格式

Get-Service |
Sort-Object –Property Status, Name |
Select-Object –Property DisplayName,Status |
Out-File –FilePath ServiceList.csv

轉換為其他形式的數據表示形式

PowerShell 使用兩個不同的謂詞進行轉換: ConvertTo 和 Export

Csv

使用 ConvertTo 的命令(如 ConvertTo-Csv )接受來自管道的對象作為輸入,並將轉換後的數據作為輸出生成到管道
切記:這個是將對象轉換成了csv格式,但是你直接輸入進文件可能會存在各種問題,比如ConvertTo-Csv 生成的 CSV 包含類型信息行(如 #TYPE System.ServiceProcess.ServiceController),這不是標準 CSV 的一部分,可能會干擾某些應用程序的解析,這就需要Export-Csv解決

Get-Service | ConvertTo-Csv | Out-File Services.csv

使用 Export(如 Export-Csv)的命令執行兩項作:它會轉換數據,然後將數據寫入外部存儲,例如磁盤上的文件

Get-Service | Export-Csv Services.csv
XML

ConvertTo-Clixml 和 Export-Clixml

Json

ConvertTo-Json 命令創建 JSON 格式的數據,必須使用 Out-File 或文本重定向運算符之一將 JSON 數據發送到文件

HTML

ConvertTo-Html 命令支持此功能,必須使用 Out-File 或其別名之一來定向輸出。

ConvertTo-Html 創建編碼為 HTML 的簡單列表或表,您可以通過各種參數以有限的方式控制HTML格式,例如:

  • ‑Head。 指定 HTML  節的內容。
  • —標題。 設置 HTML 標題 標記的值。
  • -PreContent。 定義應在表或列表輸出之前顯示的任何內容。
  • -PostContent。 定義應在表或列表輸出之後顯示的任何內容。
其他輸出選項

Out-* 命令的核心功能、常見參數和典型使用場景:

Cmdlet 核心功能 常用參數 典型應用場景
Out-Host 將輸出發送到主機(控制枱)進行顯示 -Paging (強制分頁顯示) 逐頁查看長輸出,避免滾動過快錯過信息
Out-Printer 將輸出發送到打印機進行打印 -Name (指定打印機名稱) 打印命令結果、報告或配置清單
Out-GridView 在交互式表格窗口中顯示輸出,支持排序、篩選和複製 -Title (設置窗口標題) 可視化數據分析、快速篩選和分享信息,但無法直接保存

Out-Host:控制枱輸出管理

  • Out-Host 是 PowerShell 默認的輸出方式,即直接將結果呈現在控制枱。它的特殊之處在於你可以通過 -Paging 參數手動控制輸出分頁
    • -Paging 參數:強制對輸出進行分頁,顯示一頁後暫停,按空格鍵查看下一頁,按 Q 鍵退出
    • 與 more 命令的關係:在 PowerShell 中,more 是一個內置函數,它本質上是 Out-Host -Paging 的別名,兩者功能相同

逐頁查看系統進程列表

Get-Process | Out-Host -Paging

# 也可以使用更簡潔的more
Get-Process | more

Out-Printer:打印輸出

  • Out-Printer 允許你將命令的輸出直接發送到打印機。
    • 默認行為:不使用參數時,輸出會發送到默認打印機
    • -Name 參數:指定目標打印機的名稱,打印機名稱需與系統中安裝的打印機名稱匹配(可通過 Get-Printer cmdlet 查看所有可用打印機)

打印當前運行的進程列表到默認打印機

Get-Process | Out-Printer

將系統服務狀態發送到特定打印機(假設打印機名為 "HP-LaserJet"):

Get-Service | Out-Printer -Name "HP-LaserJet"

打印到虛擬打印機(如生成PDF):如果你安裝了 Microsoft Print to PDF 這類虛擬打印機,也可以使用 -Name 參數指定它來生成PDF文件。

Get-Service | Where-Object {$_.Status -eq 'Running'} | Out-Printer -Name "Microsoft Print to PDF"

Out-GridView:交互式表格輸出

  • Out-GridView(通常簡稱 OGV)是一個非常強大的工具,它會在一個新窗口中以交互式表格的形式顯示輸出。你可以:
    • 點擊列名進行排序(升序/降序)。
    • 使用頂部的篩選框對任何列進行篩選(支持包含、不包含等條件)。
    • 選中行並複製(Ctrl+C),然後粘貼到 Excel 或其他應用程序中。
    • 多選(Ctrl+點擊 或 Shift+點擊)。
      重要限制:正如你所讀到的,無法直接從 GridView 窗口保存數據。你需要先通過複製粘貼,或在命令行中就使用 Export-Csv 等命令保存數據。

可視化並篩選系統服務

# 查看所有服務
Get-Service | Out-GridView

# 僅查看正在運行的服務,並自定義窗口標題
Get-Service | Where-Object Status -eq 'Running' | Out-GridView -Title "當前運行的服務"

# 結合篩選器:找出所有正在運行且名稱中包含 "windows" 的服務
Get-Service | Where-Object { $_.Status -eq 'Running' -and $_.Name -like '*windows*' } | Out-GridView

在彈出的窗口中,你可以進一步點擊“狀態”列排序,或在“名稱”列篩選器輸入更多關鍵字。

分析進程資源佔用

Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | Out-GridView -Title "CPU佔用最高的10個進程"

自定義列順序:如果你使用 Select-Object 選擇並排序了屬性,Out-GridView 會遵循這個順序顯示列

Get-Service | Select-Object Name, Status, DisplayName, StartType | Out-GridView

傳遞管道對象

管道傳遞數據可以有兩種方式:ByValue 和 ByPropertyName
它們最根本的區別在於匹配的依據

  • ByValue:依據管道對象的整體類型進行匹配。
  • ByPropertyName:依據管道對象的屬性名稱進行匹配。
    例如運行:Get-Help Stop-Process -Full
    必須看輸入支持哪種類型:那我們只能輸入下面的這幾種了

    那既然我們要傳數據給Stop-Process的話那我們就需要知道左邊的那個輸出符不符合這裏面的輸入,下面詳細講一下這個!

ByValue 傳遞數據


直接將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,指定輸出一個屬性內容即可


ByPropertyName 傳遞數據

這裏感覺沒啥好説的,就是在ByValue不成立的時候,我們就需要特別指定某個屬性給到下一個要執行的命令,但是前提是左邊和右邊的屬性名字要相同,否則在匹配的時候就不知道該屬性給哪個。
(有一個特殊情況就是希望將左邊的A屬性值傳遞給右邊的B屬性,兩個名字不一樣的時候就需要重命名)


重命名方式,這種就比較特殊

  • Get-Process 有一個參數 -ComputerName,它支持通過 ByPropertyName 接收輸入。
  • 但 Get-ADComputer 返回的計算機對象有一個叫 Name 的屬性,沒有叫 ComputerName 的屬性。
  • 因此,Name 屬性無法自動傳遞給 -ComputerName 參數
    這樣就需要重命名了:
Get-ADComputer -Filter * | Select-Object @{Name='ComputerName'; Expression={$_.Name}} | Get-Process

若是説在 ByPropertyName 的時候,兩邊的屬性名相同那就會自動匹配去執行操作了(這種就不詳細説了)

展開屬性值

先看一個動作:

Get-Process –ComputerName (Get-LocalUser –Filter *)

這個是想要將Get-LocalUser給到Get-Process的ComputerName參數
先看Get-Process的ComputerName接受什麼輸入

Get-Help Get-Process -Full 

可以看到只接受string類型,那我們直接將整個Get-LocalUser東西穿進去肯定不行

再看看這樣行不行
回答:看似可以,其實也不行

Get-Process –ComputerName (Get-LocalUser –Filter * | Select-Object –Property Name)

我們要看這個–Property Name輸出的到底是不是string

$(Get-LocalUser | Select-Object –Property Name -First 1).GetType()

查看後發現還是不是string,那這時候就需要用到展開屬性的操作了

其實就是改了個參數名:
將Property改為ExpandProperty,下面這樣就可以了

$(Get-LocalUser | Select-Object –ExpandProperty Name -First 1).GetType()

為什麼可以,我們直接看下取出來的Name是不是string即可


複習提問:
在命令行接口將對象從一個命令傳遞到管道中的另一個命令時,Windows PowerShell 總是優先嚐試使用哪種技術?

ByValue

深入瞭解Powershell腳本

開發生命週期與安全強化

PowerShellGet 模塊

Cmdlet 説明
Find-Module 使用此 cmdlet 在 PowerShell 庫中搜索 Windows PowerShell 模塊。 最簡單的用法是根據模塊名進行搜索,但也可以根據命令名、版本、DscResource 和 RoleCapability 進行搜索。
Find-Script 使用此 cmdlet 在 PowerShell 庫中搜索 Windows PowerShell 腳本。 最簡單的用法是根據腳本名進行搜索,但也可以根據版本進行搜索。
PowerShell 庫需要使用傳輸層安全性 (TLS) 1.2 來幫助保護通信。 默認情況下,Windows 10 和 Windows Server 2016 不支持在 Windows PowerShell 中使用 TLS 1.2。 因此,需要啓用 TLS 1.2 才能下載 PowerShell 庫內容。

若要為當前 PowerShell 提示啓用 TLS 1.2,請運行以下命令:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

若要在計算機上永久解決此問題,需要創建註冊表項。 可以運行以下兩個命令來創建必要的密鑰:

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

執行策略

確保當前配置,可以使用:Get-ExecutionPolicy

執行策略的選項包括:

  • Restricted:不允許運行任何腳本。
  • AllSigned:僅當腳本經過數字簽名後才能運行。
  • RemoteSigned:下載的腳本只有在經過數字簽名後才能運行。
  • Unrestricted:可以運行所有腳本,但在運行下載但未簽名的腳本時會顯示確認提示。
  • Bypass:運行所有腳本且不顯示提示。

以數字方式對腳本進行簽名

使用現有的代碼簽名證書(如果你有)
如果你已經從公共證書頒發機構(CA)或企業的內部CA獲取並安裝了代碼簽名證書,可以用以下命令查找:

# 在當前用户的證書存儲中查找所有可用於代碼簽名的證書
$certs = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert

# 如果你確定只有一個,可以直接賦值
$cert = Get-ChildItem -Path "Cert:\CurrentUser\My" -CodeSigningCert
  • Cert:\CurrentUser\My 是 PowerShell 證書驅動器(PSDrive)中的一個路徑,指向當前用户的“個人”證書存儲區域。
  • -CodeSigningCert 參數是 Get-ChildItem 在證書驅動器中專用的,用於篩選出具有“代碼簽名”用途的證書。

創建自簽名證書(用於測試和學習)
在生產環境中,你需要一個受信任的CA頒發的證書。但在測試和學習時,可以快速創建一個自簽名證書

# 以管理員身份運行 PowerShell 執行以下命令
$certParams = @{
    Type = 'CodeSigningCert'
    Subject = 'CN=PowerShell Scripting Test' # 證書主題,CN是通用名
    KeyUsage = 'DigitalSignature' # 密鑰用法:數字簽名
    KeyExportPolicy = 'Exportable' # 密鑰可導出,方便備份和轉移
    CertStoreLocation = 'Cert:\CurrentUser\My' # 證書存儲位置
    HashAlgorithm = 'sha256' # 哈希算法
    # FriendlyName 是可選的,便於在證書管理中識別
    FriendlyName = 'My PowerShell Test Signing Certificate'
}
$cert = New-SelfSignedCertificate @certParams

重要提示:自簽名證書僅用於測試。因為它不是由受信任的根證書頒發機構頒發的,所以其他計算機默認不會信任它。
(你自己創建的,你自己使用的時候就導入即可,不用設置密碼啥的,因為是你自己創建你自己用,除非你導出的時候就要設置密碼,因為你導出肯定是要給其他計算機使用)


從證書文件導入
如果你有 .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

加載的時候需要密碼,這需要在證書持有者導出證書的時候設置的那個密碼,然而這個pdx或者p12文件是用來簽名的,不是用來驗證的,用來驗證的那個是cert,這也是為啥要輸入密碼的原因了,這個證書是拿來公章簽名的。


拿到證書對象($cert)後,就可以用它來簽名腳本了。官網的例子是基礎,但強烈建議添加時間戳服務器參數。

# 基礎簽名(官網示例)
Set-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1" -Certificate $cert

# 推薦的簽名方式(添加時間戳)
$signParams = @{
    FilePath = "C:\Scripts\MyScript.ps1" # 要簽名的腳本路徑
    Certificate = $cert # 之前獲取的證書對象
    HashAlgorithm = 'Sha256' # 哈希算法,建議使用Sha256
    # 添加時間戳至關重要!即使證書過期,時間戳也能證明簽名時證書是有效的。
    TimestampServer = 'http://timestamp.digicert.com' 
    # -IncludeChain 參數可選,默認是 'NotRoot'(包含除根CA以外的所有證書)
    # -Force 參數可選,如果腳本已有簽名,強制替換
}
Set-AuthenticodeSignature @signParams

簽名完成後,務必檢查一下:

Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"

查看輸出中的 Status 屬性:

  • Valid:簽名有效且受信任。
  • UnknownError:簽名無效或證書不受信任(常見於自簽名證書)。
  • NotSigned:腳本未簽名。

讓系統信任你的簽名
!!!!!記住這裏是驗證,不是用來簽名,前面説的都是pxf和p12證書,這裏講的是cer文件!!!!!!!!

對於自簽名證書,由於它不是公共CA頒發的,你需要將你的自簽名證書**導入到“受信任的根證書頒發機構”或“受信任的發佈者”存儲區。否則,在其他計算機上運行時會顯示 UnknownError

  1. 將你的證書導出為 .cer 文件(只包含公鑰)。
  2. 在需要運行此腳本的計算機上,將這個 .cer 文件導入到“受信任的根證書頒發機構”或“受信任的發佈者”(對於代碼簽名證書,通常是“受信任的發佈者”)。
    你可以使用 PowerShell 自動化導入信任證書的過程
$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()

進階語法

ForEach 循環

在某些情況下,可能需要使用 ForEach-Object cmdlet 來處理管道中的數據。 將數據存儲在數組中時,ForEach 構造支持處理數組中的每個項。
 powershell  ForEach ($user in $users) { Set-ADUser $user -Department "Marketing" }  

在 PowerShell 7 中,已將 -Parallel 參數添加到 ForEach-Object cmdlet。 這樣,管道就可以同時處理多個對象。 相較於標準 ForEach 循環,同時處理多個對象所提供的性能更佳。 如果使用的是 PowerShell 7,應考慮這一點。 以下示例説明了如何將 ForEach-Object 與 -Parallel 參數配合使用。

$users | ForEach-Object -Parallel { Set-ADUser $user -Department "Marketing" }

默認情況下,-Parallel 參數支持一次處理五個項,可以使用 -ThrottleLimit 參數將其修改為更大或更小的值。

If 構造

舉例子:如果可用磁盤空間不足,則可以使用 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"
}

同時也學到大小是可以直接使用MB、GB等單位直接比較

Switch 構造

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 參數,以與 -like 運算符相同的語法來執行模式匹配。 或者,可以使用 -regex 參數通過正則表達式執行匹配。

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 構造

For($i=1; $i -le 10; $i++) {
   Write-Host "Creating User $i"
}
處理對象數組時,最好使用 ForEach 構造,因為在處理之前不需要計算數組中的項數。

其他循環構造

Do..While

Do..While 構造運行腳本塊,直到指定條件為false
此構造保證腳本塊至少運行一次

Do {
   Write-Host "Script block to process"
} While ($answer -eq "go")

Do..Until

Do..Until 構造運行腳本塊,直到指定條件為 true
此構造保證腳本塊至少運行一次

Do {
   Write-Host "Script block to process"
} Until ($answer -eq "stop")

While

While 構造運行腳本塊,直到指定條件為 false
雖然它類似於 Do..While 構造,但它不能保證腳本塊的運行

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 用於在最大帳户數已修改時結束循環:

ForEach ($user in $users) {
   $number++
   Write-Host "Modify User object $number"
   If ($number -ge $max) {Break}
}

導入數據

Get-Content

直接讀取文件內容進來

$computers = Get-Content C:\Scripts\computers.txt

可在 Get-Content 的路徑中使用通配符,以便一次獲得多個文件的數據
可使用 -Include 和 -Exclude 參數修改所選文件

Get-Content -Path "C:\Scripts\*" -Include "*.txt","*.log"

可以使用 -TotalCount 和 -Tail 參數限制使用 Get-Content 檢索的數據量

  • -TotalCount 參數指定應從文件開頭檢索多少行
  • -Tail 參數指定從文件末尾檢索多少行
    例如:
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

當我們存進一個變量後,也可以通過變量訪問某個數據

$users[2].UserID

Import-Csv 默認分隔符是逗號,有的文件不是以逗號進行分割的話你也可以使用Import-Csv,只要格式相同分隔符不同也可以用這個,前提是你要自己加參數去修改分隔符:
比如説分隔符是分號

Import-Csv -Path .\1.csv -Header h1,h2,h3 -Delimiter ';'

Import-Clixml

$users = Import-Clixml C:\Scripts\Users.xml

使用 -First 和 -Skip 參數來限制 Import-Clixml 檢索的數據

  • -First 參數指定僅從 XML 文件的開頭檢索指定數量的對象
  • -Skip 參數指定從 XML 文件開頭忽略指定數量的對象,並檢索所有剩餘的對象。

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 參數在提示符處屏蔽輸入用户,這種偏向於輸入密碼的時候不會直接顯示在終端上

$answer = Read-Host "How many days" -AsSecureString

具體使用哪個看情況了,我的電腦使用AsSecureString才行

Credential憑證使用

Get-Credential

它的核心作用就是安全地彈窗收集用户憑據(用户名和密碼),並將其封裝在一個 PSCredential 對象中,供其他需要憑據的 cmdlet 使用。

基礎用法:
這會彈出一個標準對話框,讓你輸入用户名和密碼。

$cred = Get-Credential

高級用法(自定義提示和用户名):

  • -Message:讓提示更清晰,指導用户輸入什麼憑據。
  • -UserName:預填用户名字段,用户只需要輸入密碼即可。$env:COMPUTERNAME 是環境變量,代表本機計算機名,這在工作組環境下至關重要。
# 自定義提示信息並預填用户名
$cred = Get-Credential -Message "請輸入本地管理員權限憑據" -UserName "$env:COMPUTERNAME\Administrator"

遠程管理另一台工作組計算機
假設你想從計算機 CLIENT-A 遠程管理計算機 CLIENT-B

# 在 CLIENT-A 上運行
# 1. 獲取 CLIENT-B 的本地管理員憑據
$cred = Get-Credential -Message "請輸入CLIENT-B的本地管理員憑據" -UserName "CLIENT-B\Administrator"

# 2. 建立遠程會話 (PSRemoting)
$session = New-PSSession -ComputerName "CLIENT-B" -Credential $cred

# 3. 在遠程會話中執行命令(例如:檢查磁盤空間)
Invoke-Command -Session $session -ScriptBlock { Get-Volume }

# 4. 關閉會話
Remove-PSSession $session

本地腳本臨時提權
你用自己的標準用户賬户登錄,但腳本中的某些操作(如修改系統設置)需要管理員權限。

# 檢查當前用户權限,如果不是管理員則請求憑據
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
    Write-Warning "此操作需要管理員權限。"
    $adminCred = Get-Credential -Message "請提供本地管理員密碼以繼續" -UserName "$env:COMPUTERNAME\Administrator"

    # 使用 Start-Process 以管理員身份啓動一個新進程來運行命令
    $scriptBlock = {
        # 這裏放需要提權的命令,例如安裝Windows功能
        Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
    }
    Start-Process "pwsh" -ArgumentList "-Command", $scriptBlock -Credential $adminCred -Wait -NoNewWindow
} else {
    # 如果已經是管理員,直接執行命令
    Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" -All
}

訪問受保護的網絡共享
掛載一個需要特定用户名和密碼才能訪問的局域網共享文件夾。

$netCred = Get-Credential -Message "請輸入訪問共享\\FileServer\Data$的憑據" -UserName "FileServer\SomeUser"

# 將憑據映射到驅動器號
New-PSDrive -Name "Z" -PSProvider "FileSystem" -Root "\\FileServer\Data$" -Credential $netCred -Persist

# 現在可以像訪問本地磁盤一樣訪問 Z:\
Get-ChildItem Z:\

# 使用完畢後斷開
Remove-PSDrive -Name "Z"

Export-Clixml

首次保存憑據(在一台電腦上):

# 彈窗輸入一次憑據
$cred = Get-Credential -Message "輸入要保存的憑據" -UserName "MyPC\Admin"
# 將加密後的憑據保存到文件(只能由你在本機解密)
$cred | Export-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"

後續腳本中自動使用保存的憑據:

# 無需彈窗,直接讀取加密文件獲取憑據對象
$savedCred = Import-Clixml -Path "C:\Users\$env:USERNAME\Documents\secureCred.xml"

# 使用憑據執行需要權限的操作,例如重啓遠程計算機
Restart-Computer -ComputerName "192.168.1.100" -Credential $savedCred -Force

腳本故障排除與錯誤處理

錯誤發生時,它們將存儲在 $Error 數組中。 最近的錯誤始終在索引零處。 新錯誤生成時,會插入到 $Error[0] 處,其他錯誤的索引將增加一。 每當需要查看以前的錯誤消息時,查看 $Error 中的錯誤會很有幫助。 例如,如果清除屏幕,則可以通過 $Error 查看最近的錯誤消息。

輸出命令的層次與用途

PowerShell 的輸出命令不是一個簡單的“打印”功能,而是一個完整的信息流系統。理解不同命令的定位是關鍵。

命令 用途 輸出位置 是否受 *Preference 變量影響 適用場景
Write-Host 直接與用户交互 控制枱 (主機) 顯示進度、美觀的標題、即時提示。謹慎使用
Write-Output 將對象放入輸出管道 管道 / 控制枱 腳本的主要輸出結果。通常隱式使用(如 "Hello")。
Write-Verbose 輸出詳細信息 控制枱 ( verbose流) 調試、記錄腳本執行的詳細步驟。
Write-Debug 輸出調試信息 控制枱 (debug流) 更深入的調試,可在運行時暫停腳本。
Write-Warning 輸出警告信息 控制枱 (warning流) 提示用户潛在的問題,但腳本會繼續執行。
Write-Error 輸出錯誤信息 控制枱 (error流) 報告錯誤,但不終止腳本執行。
Throw 拋出終止錯誤 控制枱 (error流) - 報告嚴重錯誤,並立即終止當前函數/腳本。

Write-Verbose 和 Write-Debug:真正的調試利器

這兩個命令的強大之處在於它們的可控性。默認情況下它們是靜默的,只在需要時通過參數開啓。
示例腳本 (Test-Service.ps1):

[CmdletBinding()] # 啓用高級功能,支持 -Verbose 和 -Debug 參數
param (
    [Parameter(Mandatory=$true)]
    [string]$ServiceName
)

Write-Verbose "腳本開始執行,傳入的服務名參數為: $ServiceName"

# 檢查服務是否存在
$service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
Write-Debug "Get-Service 查詢結果: $($service | Out-String)"

if (-not $service) {
    Write-Error "錯誤: 找不到名為 '$ServiceName' 的服務。"
    exit 1
}

Write-Verbose "服務狀態: $($service.Status)"
if ($service.Status -ne 'Running') {
    Write-Warning "服務 '$ServiceName' 當前未運行。"
    # 嘗試啓動服務
    try {
        Start-Service -Name $ServiceName
        Write-Host "服務已成功啓動。" -ForegroundColor Green
    }
    catch {
        Throw "啓動服務失敗: $($_.Exception.Message)"
    }
} else {
    Write-Output "服務 '$ServiceName' 正在運行。"
}

Write-Verbose "腳本執行完畢。"

如何使用這個腳本:

  • 默認運行(只看到基本輸出)
.\Test-Service -ServiceName "WinRM"
# 輸出: 服務 'WinRM' 正在運行。
  • 查看詳細信息(使用 -Verbose
.\Test-Service -ServiceName "WinRM" -Verbose
# 輸出:
# 詳細: 腳本開始執行,傳入的服務名參數為: WinRM
# 詳細: 服務狀態: Running
# 服務 'WinRM' 正在運行。
# 詳細: 腳本執行完畢。
  • 進行深度調試(使用 -Debug
.\Test-Service -ServiceName "SomeService" -Debug

運行後會首先顯示 Write-Debug 的信息,並暫停,提示你:

調試: Get-Service 查詢結果: 
(這裏會顯示Get-Service返回的詳細對象信息)
繼續執行?
[Y] 是(Y)  [A] 全是(A)  [N] 否(N)  [L] 全否(L)  [S] 暫停(S)  [?] 幫助 (默認值為“Y”):

按 `Y` 繼續執行每一步,按 `A` 讓它自動執行完所有調試步驟。這讓你可以一步步觀察腳本的執行流程。

使用 $VerbosePreference 和 $DebugPreference 進行全局控制

在當前會話中開啓所有Verbose輸出

$VerbosePreference = "Continue" # 默認是 "SilentlyContinue"
.\Test-Service -ServiceName "WinRM"
# 現在即使不加 -Verbose,也會輸出Verbose信息

在腳本開頭強制開啓調試(常用於日誌記錄):

[CmdletBinding()]
param()
# 在腳本內部設置,強制記錄詳細信息到日誌文件
$VerbosePreference = "Continue"
Write-Verbose "$(Get-Date): 腳本啓動..."
# ... 腳本邏輯 ...

腳本中使用斷點

根據行進行斷點

可使用 Set-PSBreakPoint cmdlet 設置斷點
可以基於腳本行、正在使用的特定命令或正在使用的特定變量來設置斷點
以下示例描述如何在腳本的特定行處設置斷點:

Set-PSBreakPoint -Script "MyScript.ps1" -Line 23

根據命令進行斷點

Set-PSBreakPoint -Command "Set-ADUser" -Script "MyScript.ps1"

基於命令設置斷點時,可以包含通配符。 例如,可以使用值 *-ADUser 為 Get-ADUser、Set-ADUser、New-ADUser 和 Remove-ADUser 觸發斷點。

根據特定變量進行斷點

Set-PSBreakPoint -Variable "computer" -Script "MyScript.ps1" -Mode ReadWrite

可以使用變量的 -Mode 參數來確定是否要在讀取和/或寫入變量值時中斷。 有效值為 Read、Write 和 ReadWrite。


以上是終端中運行腳本的時候設置的斷點,其實我們可以用:

  • Powershell ISE 圖形化工具進行根據行去斷點
  • VScode 中也能夠進行更多高級的斷點方式

錯誤操作

$ErrorActionPreference

內置全局變量。 當命令生成非終止錯誤時,命令會檢查此變量來決定該執行的操作
變量可具有下面 4 個可能值之一:

  • Continue 是默認值,它告知命令顯示錯誤消息並繼續運行。
  • SilentlyContinue 告知命令不顯示錯誤消息,但要繼續運行。
  • Inquire 告知命令顯示提示,詢問用户要做什麼。
  • Stop 告知命令將錯誤視為終止錯誤並停止運行。

若要設置 $ErrorActionPreference 變量,請使用以下語法:

$ErrorActionPreference = 'Inquire'
-ErrorAction

所有 Windows PowerShell 命令都有 –ErrorAction 參數。 此參數具有別名 –EA
當你使用他的時候,會覆蓋$ErrorActionPreference但可以設置一樣的類型,該參數僅針對當前使用的cmdlet

函數與模塊

有參函數:

Function Get-SecurityEvent {
   Param (
      [string]$ComputerName
   ) #end Param
   Get-EventLog -LogName Security -ComputerName $ComputerName -Newest 10
}

無參函數就很簡單了,不寫接受參數的變量即可

函數調用如下:

Get-SecurityEvent -ComputerName LON-DC1

變量範圍

使用範圍修飾符 (Scope Modifiers) 指定目標作用域
這是修改其他作用域中變量的關鍵方法。通過在變量名前加修飾符來指定目標作用域

修飾符 作用 語法示例 説明
$global: 修改全局作用域中的變量。 $global:MyVariable = "新值" 在任何地方(函數、腳本)都能訪問和修改這個全局變量。慎用,容易造成污染。
$script: 修改腳本作用域中的變量。 $script:MyVariable = "新值" 在當前腳本文件的任何函數內部修改在腳本頂層定義的變量。這是最常用、最安全的方式。
$using: 在遠程命令或腳本塊中引用當前局部作用域的變量。 Invoke-Command { ... -Name $using:LocalVar } 用於將本地變量的值傳遞到遠程會話或新腳本塊中,而不是在遠程會話中修改它。
$private: 在當前作用域創建變量,且該變量不會傳遞到更高級的作用域。 $private:TempVar = "值" 用於限制變量範圍,確保其不會影響父作用域。較少用。

示例:
假設您在腳本頂層定義了 $configPath,現在需要在一個函數裏修改它:

Set-Variable指定作用域
Set-Variable -Name "MyVariable" -Value "新的值" -Scope <ScopeName>

-Scope 參數值:

  • 'Global': 修改全局作用域。
  • 'Script': 修改腳本作用域。
  • 'Local': 修改當前局部作用域(默認值)。
  • 'Private': 修改為私有作用域。

絕大多數情況下,您應該使用 $script: 修飾符
這是在函數內修改腳本級變量的最標準、最可讀且副作用最小的方式。

類似指針修改

使用[ref]去拿到真實的那個變量在函數裏面去修改,而不是説每次修改的都是函數內部接受到的值,他會直接影響到函數外部那個傳進來的變量的值

function Modify-ByReference {
    param (
        [ref]$RefValue
    )
    $RefValue.Value = "在函數內部被修改了" # 注意:是修改 .Value 屬性
}

$OriginalVariable = "原始值"
	Modify-ByReference -RefValue ([ref]$OriginalVariable)
Write-Host $OriginalVariable # 輸出:在函數內部被修改了

但是我們是避免這樣去修改變量的,要改的話最好是通過return返回值,然後在函數外部去改變某個變量

return

好像沒啥好説的,就是return值

function xxx{
	xxx
	return($var) # return "xxx" return $var
}

$ch = xxx()

創建模塊

你必須創建與該文件同名的子文件夾,並將文件放在該子文件夾中
例如,如果你有一個名為 AdatumFunctions.psm1 的模塊,
則將其放置在 C:\Program Files\WindowsPowerShell\Modules\AdatumFunctions 中。

Add a new 评论

Some HTML is okay.