繁体   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