about_Scopes
主題
about_Scopes
簡短描述
說明 Windows PowerShell 中範圍 (Scope) 的概念並且示範如何設定與變更元素的
範圍。
完整描述
Windows PowerShell 會限制可以讀取與變更變數、別名、函數與
Windows PowerShell 磁碟機 (PSDrives) 的情況,藉此保護對這些項目的存取。
Windows PowerShell 會強制使用幾個簡單的範圍規則,以免您不慎變更不應該更
動的項目。
下列是基本的範圍規則:
- 除非您明確將其設為私用 (Private) 項目,否則在任一範圍及其子範圍中,
都可以看見您加入該範圍 (項目建立的區域) 的項目。您可以在一個或多個
範圍中放置變數、別名、函數或 Windows PowerShell 磁碟機。
- 除非您明確指定不同的範圍,否則於某一範圍中所建立的項目,只能在建立
該項目的範圍中進行變更。
如果您在某一範圍中建立項目,而該項目與其他範圍中的另一項目具有相同的名稱,
那麼原始項目可能會在使用新項目的情況下被隱藏,但是這並不表示原始項目被覆寫
或變更。
Windows PowerShell 範圍
Windows PowerShell 中的範圍有名稱與編號,具名範圍會指定絕對範圍。而編號具
有相對性,能夠反映範圍之間的關係。
全域 (Global):
Windows PowerShell 啟動時即會發生作用的範圍Windows PowerShell 啟動時便
出現的變數與函數會在全域範圍中建立。這包含自動變數與偏好設定變數,也包
括 Windows PowerShell 設定檔中的變數、別名和函數。
區域 (Local):
表示目前的範圍。區域範圍可以是全域範圍或是其他任一範圍。
指令碼 (Script):
指令碼檔案執行時所建立的範圍。只有指令碼中的命令才會在指令碼範圍中執
行。對於指令碼中的命令而言,指令碼範圍為區域範圍。
私用 (Private):
私用範圍中的項目在目前範圍外是看不到的。您可以使用私用範圍針對另一個範
圍中的項目,建立其私用版本且名稱相同。
編號範圍:
您可以利用名稱或描述某一範圍與另一範圍之相對位置的編號來表示範圍。
範圍 0 表示目前或區域範圍。範圍 1 表示直屬父範圍。範圍 2 表示父範圍的
父範圍,並以此類推。如果您已建立了許多遞迴範圍,則編號範圍會相當實用。
父範圍與子範圍
您可以執行指令碼或函數、建立工作階段或是啟動新的 Windows PowerShell 執行個
體,藉此建立新範圍。建立新範圍時,結果會產生一個父範圍 (原始範圍) 與一個子
範圍 (所建立的範圍)。
在 Windows PowerShell 中,所有範圍都是全域範圍的子範圍,但是您可以建立多個
範圍與多個遞迴範圍。
除非明確將其設為私用項目,否則在子範圍中一定可以存取父範圍中的項目。然而,
除非在建立項目時明確指定範圍,否則您在子範圍中建立與變更的項目並不會影響父
範圍。
繼承
子範圍繼承父範圍中的變數、別名與函數。除非是私用項目,否則子範圍可以檢視父
範圍中的項目。此外,可以藉由明確指定父範圍的方式變更項目,但是該項目並不屬
於子範圍的一部分。
不過,子範圍會連同一組項目一併建立,一般而言,這包含具有 AllScope 選項的所
有別名。這個選項將會稍後於本主題中討論。它包含具有 AllScope 選項的所有變數
與某些可以用於自訂範圍的變數,例如 MaximumFunctionCount。
若要尋找特定範圍中的項目,請使用 Get-Variable 或 Get-Alias 的 Scope 參數。
例如,若要取得區域範圍中的所有變數,請輸入:
get-variable -scope local
若要取得全域範圍中的所有變數,請輸入:
get-variable -scope global
範圍修飾詞
若要指定新變數、別名或函數的範圍,請使用範圍修飾詞。修飾詞的有效值為 Global
與 Script。
變數中範圍修飾詞的語法為:
$[<scope-modifier>]:<名稱> = <值>
函數中範圍修飾詞的語法為:
function [<範圍修飾詞>]:<名稱> {<函數主體>}
指令碼的預設範圍為指令碼範圍。函數與別名的預設範圍為區域範圍,即使這些函數
與別名已於指令碼中定義也是如此。
下列不使用範圍修飾詞的命令會建立目前或區域範圍中的變數。
$a = "one"
若要建立全域範圍中的相同變數,請使用 Global 範圍修飾詞:
$global:a = "one"
若要建立指令碼範圍中的相同變數,請使用 Script 範圍修飾詞:
$script:a = "one"
也可以使用函數中的範圍修飾詞。下列函數定義全建立全域範圍中的函數:
function global:Hello
{
write-host "Hello, World"
}
也可以使用範圍修飾詞表示不同範圍中的變數。下列命令表示 $test 變數,第一個
位於區域範圍、接著位於全域範圍:
$test
$global:test
AllScope 選項
變數與別名都有一個可以接受 AllScope 之值的 Option 屬性。具有 AllScope 屬性
的項目會變成您所建立之子範圍的任何一部分 (雖然這些項目並不會由父範圍回溯繼
承)。
具有 AllScope 屬性的項目會顯示在子範圍中,且它屬於該範圍的一部分。在任一範
圍變更該項目會影響變數於其中定義的所有範圍。
管理範圍
有幾個 Cmdlet 具有 Scope 參數,可以讓您取得或設定 (建立和變更) 特定範圍中的
項目。請使用下列命令尋找工作階段中的所有具有 Scope 參數的 Cmdlet:
get-help * -parameter scope
若要尋找顯示於特定範圍中的變數,請使用 Get-Variable 的 Scope 參數。顯示的變
數包括全域參數、父範圍中的參數以及目前範圍中的參數。
例如,下列命令會取得可以在區域範圍中看見的變數:
get-variable -scope local
若要建立特定範圍中的變數,請使用範圍修飾詞或 Set-Variable 的 Scope 參數。
下列命令會於全域範圍中建立變數:
new-variable -scope global -name a -value "One"
也可以使用 New-Alias、Set-Alias 或 Get-Alias Cmdlet 的 Scope 參數指定範
圍。下列命令會於全域範圍中建立別名:
new-alias -scope global -name np -value Notepad.exe
若要取得特定範圍中的函數,請在您處於該範圍中時使用 Get-Item Cmdlet。
Get-Item Cmdlet 沒有範圍參數。
搭配範圍使用點執行標記法
指令碼與函數遵照所有範圍規則。您可以在任一特定範圍中建立這些指令碼與函數,
而且除非使用 Cmdlet 參數或範圍修飾詞變更該範圍,否則它們只會影響該特定範
圍。
但是,您可以使用點執行標記法,在目前範圍中加入指令碼或函數。接著,當指令碼
於目前範圍中執行時,可以在目前範圍中使用該指令碼所建立的函數、別名和變數。
若要在目前範圍中加入函數,請在函數呼叫中的函數路徑與名稱之前輸入一個點 (.)
與一個空格。
例如,若要在指令碼範圍 (指令碼的預設值) 中從 C:\Scripts 目錄執行 Sample.ps1
指令碼,請使用下列命令:
c:\scripts\sample.ps1
若要在目前範圍中執行 Sample.ps1 指令碼,請使用下列命令:
. c:\scripts.sample.ps1
當您使用呼叫運算子 (&) 執行函數或指令碼時,運算子會加入目前的範圍。下列範
例會使用呼叫運算子:
& c:\scripts.sample.ps1
無法在目前範圍中使用 Sample.ps1 指令碼所建立的任一別名、函數或變數。
限制但不使用範圍
有一些 Windows PowerShell 概念與範圍或與範圍互動類似,這些概念可能會與範圍
或範圍的行為混淆。
工作階段、模組與巢狀提示都是獨立 (Self-contained) 的環境,但是它們並不是工
作階段中全域範圍的子範圍。
工作階段:
工作階段是指 Windows PowerShell 在其中執行的環境。
在遠端電腦上建立工作階段時,Windows PowerShell 會建立與遠端電腦之間的
固定連線。固定連線可以讓您使用多個相關命令的工作階段。
因為工作階段是獨立的環境,所以它有自己的範圍,但是工作階段並不是該工作
階段 (於其中建立的位置) 的子範圍。工作階段會以其本身的全域範圍開始,這
個範圍與工作階段的全域範圍並沒有關聯。
您可以在該工作階段中建立子範圍,例如,您可以執行指令碼以便在工作階段中
建立子範圍。
模組:
您可以使用 Windows PowerShell 模組以共用並提供 Windows PowerShell 工
具。模組是一個包含 Cmdlet、指令碼、函數、變數、別名與其他實用工具的單
元。除非明確定義,否則無法在模組之外存取模組中的項目。因此,您可以將
模組加入工作階段並且使用公用項目,而不需要擔心其他項目可能會覆寫工作
階段中的 Cmdlet、指令碼、函數和其他項目。
模組的隱密性行為與範圍類似,但是在工作階段中加入模組並不會變更範圍。
此外,雖然模組中的指令碼 (如同其他所有 Windows PowerShell 指令碼) 擁
有其本身的範圍,但是模組並沒有自己的範圍。
巢狀提示:
同樣的,巢狀提示也沒有自己的範圍。當您輸入巢狀提示時,該巢狀提示為環
境的子集,但是您的所在位置仍然在區域範圍內。
指令碼有自己的範圍;如果您對指令碼進入偵錯,同時到達指碼的中斷點時,
即表示您進入指令碼範圍。
私用選項:
別名與變數都有一個可以接受 Private 之值的 Option 屬性。具有 Private
選項的項目可以在建立項目的範圍中檢視與變更,但是無法在該範圍之外檢
視或變更這些項目。
例如,如果在全域範圍中建立具有私用選項的變數,那麼指令碼中的
Get-Variable 命令並不會顯示私用變數。即使您使範圍修飾詞也是如此。
您可以使用 New-Variable、Set-Variable、New-Alias 與 Set-Alias Cmdlet
的 Option 參數,將 Option 屬性的值設定為 Private。
可見度:
變數或別名的 Visibility 屬性能夠決定您是否可以在於其中建立項目的容器
(例如模組) 之外看到項目。Visibility 是專為容器所設計的,設計的原理與
Option 屬性的 Private 值相同。
Visibility 屬性接受 Public 與 Private 值。具有私用可見度的項目只能夠在
建立項目的容器中檢視與變更。如果容器已加入或匯入,那麼便無法檢視或變更
具有私用可見度的項目。
因為 Visibility 是專為容器所設計的,所以運作方式與在範圍中不同。如果您
在全域範圍中建立具有私用可見度的項目,則無法在任一範圍中檢視或變更該項
目。如果嘗試檢視或變更具有私用可見度的變數值,則 Windows PowerShell 會
傳回錯誤訊息。
您可以使用 New-Variable 與 Set-Variable Cmdlet 建立具有私用可見度的變
數。
範例
範例 1:只在指令碼中變更變數值
下列命令會變更指令碼中的 $ConfirmPreference 變數值,而這項變更並不會影響
全域範圍。
首先,若要顯示區域範圍中 $ConfirmPreference 變數的值,請使用下列命令:
C:\PS> $ConfirmPreference
High
建立包含下列命令的 Scope.ps1 指令碼:
$ConfirmPreference = "Low"
"`$ConfirmPreference 的值為 $ConfirmPreference。"
執行指令碼。該指令碼會變更 $ConfirmPreference 變數的值,然後回報它在指令
碼範圍中的值。其輸出應該與下列輸出類似:
$ConfirmPreference 的值為 Low。
接下來,在目前範圍中測試 $ConfirmPreference 變數的值。
C:\PS> $ConfirmPreference
High
這個範圍示範變更指令碼範圍中的變數值並不影響該變數在父範圍中的值。
範例 2:在不同範圍中檢視變數值
您可以使用範圍修飾詞,在區域範圍與父範圍中檢視變數的值。
首先,在全域範圍中定義 $test 變數。
$test = "Global"
接下來,建立定義 $test 變數的 Sample.ps1 指令碼。在指令碼中,使用範圍修
飾詞指出 $test 變數的全域或區域版本。
# In Sample.ps1
$test = "Local"
"`$test 的區域值為 $test。""`$test 的全域值為 $global:test。"
執行 Sample.ps1 時,其輸出應該與下列輸出類似:
$test 的區域值為 Local。
$test 的全域值為 Global。
指令碼完成時,工作階段中只有定義 $test 的全域值。
C:\PS> $test
Global
範例 3:在父範圍中變更變數值
除非使用 Private 選項或其他方法保護項目,否則您可以在父範圍中檢視並
變更變數的值。
首先,在全域範圍中定義 $test 變數。
$test = "Global"
接下來,建立定義 $test 變數的 Sample.ps1 指令碼。在指令碼中,使用範圍修
飾詞指出 $test 變數的全域或區域版本。
# In Sample.ps1
$global:test = "Local"
"`$test 的全域值為 $global:test。"
指令碼完成時,只會變更 $test 的全域值。
C:\PS> $test
Local
範例 4:變更私用變數
私用變數為具有值為 Private 之 Option 屬性的變值。私用變數會由子範圍繼
承,但是只能夠在建立這些變數的範圍中,檢視或變更這些變數。
下列命令會在區域範圍中建立稱為 $ptest 的私用變數。
new-variable -name ptest -value 1 -option private
您可以在區域範圍中顯示並變更 $ptest 的值。
C:\PS> $ptest
1
C:\PS> $ptest = 2
C:\PS> $ptest
2
接下來,建立包含下列命令的 Sample.ps1 指令碼。
該命令嘗試顯示並變更 $ptest 的值。
# In Sample.ps1
"`$Ptest 的值為 $Ptest。"
"`$Ptest 的值為 $global:Ptest。"
因為在指令碼範圍中看不見 $ptest 變數,所以輸出為空白。
"$Ptest 的值為。"
"$Ptest 的值為。"
請參閱
about_Variables
about_Environment_Variables
about_Functions
about_Script_Blocks