簡體   English   中英

Powershell Profile腳本是否源點源?

[英]Are Powershell Profile scripts dot-sourced?

我正在使用的Microsoft.PowerShell_profile.ps1腳本在運行時會創建很多變量。 我已將所有變量的范圍設置為“腳本”,但腳本中使用的變量永遠不會超出范圍。

一旦腳本完成運行並且控制權移交給我,我希望變量超出范圍。

如果我比較全局,本地和腳本變量的數量,我會得到相同的數字。

例:

# Profile script does what it does.

Get-Variable -Scope Global | Measure-Object
Get-Variable -Scope Local  | Measure-Object
Get-Variable -Scope Script | Measure-Object

Output:
60
60
60

目前,我正在我的配置文件腳本的開頭捕獲變量的快照,然后在最后刪除任何新變量。

例:

$snapshotBefore = Get-Variable
$profileVar1 = 'some value'
$profileVar2 = 'some other value'
$snapshotAfter = Get-Variable

# Compare before and after, and create list of new variables.

Remove-Variable $variablesToRemove

是的, PowerShell配置文件是按設計點源 ,因為這是允許它們中包含的定義(別名,函數,...) 默認 全局可用 - 畢竟這是配置文件的主要用途。

遺憾的是, 沒有范圍修飾符允許您為加載配置文件時只想存在的變量創建臨時范圍 - 即使范圍local在配置文件腳本中實際上是全局的; 類似地,使用范圍private也不是一個選項,因為配置文件的腳本范圍 - 由於是點源的 - 全局范圍。

一般來說,您可以使用& (調用運算符)和腳本塊在該塊中創建作用於該塊的變量,但這通常與在配置文件中創建全局可用定義不一致,至少在默認情況下是這樣。
同樣,調用另一個沒有點源的腳本,就像你自己的答案一樣,默認情況下不會使其定義全局可用。
可以 ,但是, 創建通過明確指定全球范圍內 -dot來源的腳本塊/腳本全局元素 ; 例如: & { $global:foo = 'Going global' } ,或& { function global:bar { 'global func' } }

也就是說, 點源配置文件背后的基本原理可能是,默認情況下更容易使所有定義全局化 ,使得配置文件的典型元素的定義 - 別名,函數,驅動器映射,模塊加載 - 更簡單(無需指定)明確的范圍)。
相比之下,全局變量不太常見,並且為了定義上面列出的典型元素,您通常不需要在配置文件中使用腳本級(以及全局)變量。


如果您仍需要在配置文件中創建(概念上)臨時變量(這不是創建全局可用別名,函數等的要求):

一個簡單的解決方法是在配置文件腳本中使用外來變量名稱前綴 (如__來降低意外引用它們的風險(例如, $__profileVar1 = ... )。
換句話說:變量仍然存在於全局,但它們的外來名稱通常不會引起問題。

然而, 你的方法 ,即使它需要一些額外的工作,聽起來像一個強大的解決方法 ,這是它看起來完整(使用PSv3 +語法):

# Save a snapshot of current variables.
# * If there are variables that you DO want to exist globally, 
# define them ABOVE this command.
# * Also, load MODULE and dot-source OTHER SCRIPTS ABOVE this command,
#   because they may create variables that *should* be available globally.
$varsBefore = (Get-Variable).Name

# ... define and use temporary variables

# Remove all variables that were created since the 
# snapshot was taken, including $varsBefore.
Remove-Variable (Compare-Object $varsBefore (Get-Variable).Name).InputObject

請注意,我依賴於Compare-Object的默認行為,即僅報告對象之間的差異 ,並且假設您沒有嘗試刪除任何變量,則僅報告添加的變量。


請注意,盡管可以從配置文件的實際行為推斷它們確實是點源的 - 但是,點源是將元素添加到當前范圍的唯一方法(全局范圍,在配置文件的情況下) -這個事實沒有明確記錄

以下是各種幫助主題(從PSv5開始)的片段,提供線索(強調我的):

來自Get-Help about_Profiles

Windows PowerShell配置文件是在Windows PowerShell啟動時運行的腳本。 您可以使用配置文件作為登錄腳本來自定義環境。 您可以添加命令,別名,函數,變量,管理單元,模塊和Windows PowerShell驅動器。 您還可以向配置文件添加其他特定於會話的元素,以便它們在每個會話中都可用,而無需導入或重新創建它們。

來自Get-Help about_Variables

默認情況下,變量僅在創建它們的范圍內可用。

例如,您在函數中創建的變量僅在函數內可用。 您在腳本中創建的變量僅在腳本中可用( 除非您點源腳本,將腳本添加到當前作用域 )。

來自Get-Help about_Operators

點源運算符在當前作用域中運行腳本,以便腳本創建的任何函數,別名和變量都添加到當前作用域。

來自Get-Help about_Scopes

但是, 您可以使用點源表示法將腳本或函數添加到當前作用域。 然后,當腳本在當前作用域中運行時,腳本創建的任何函數,別名和變量在當前作用域中都可用

要向當前作用域添加函數,請在函數調用中鍵入函數的路徑和名稱前的點(。)和空格。

所以它聽起來像Powershell點源的配置文件。 我找不到具體說明的資源,或其他提出此問題的論壇。

我找到了答案,並希望在此發布。

我已將我的個人資料更改為僅調用腳本文件。 該腳本現在有自己的范圍,只要變量不是全局變量,一旦配置文件完成加載,它們就會超出范圍。

所以現在我的個人資料有一行:

& (Split-Path $Path $profile -Parent | Join-Path "Microsoft.PowerShell_profile_v2.ps1")

Microsoft.PowerShell_profile_v2.ps1現在可以包含適當的范圍:

$Global:myGlobalVar = "A variable that will be available during the current session"
$Script:myVar = "A variable that will disappear after script finishes."
$myVar2 = "Another variable that will disappear after script finishes."

這允許配置文件腳本導入包含全局變量的模塊。 這些變量將在當前會話期間繼續存在。

我仍然很好奇為什么微軟決定以這種方式調用這個配置文件。 如果有人知道,並想分享。 我很樂意在這里看到答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM