【问题标题】:PSModulePath variable requirements before PowerShell startsPowerShell 启动前的 PSModulePath 变量要求
【发布时间】:2019-10-30 01:53:03
【问题描述】:

WPS = Windows PowerShell
PSC = PowerShell 核心

当我开始时,我有三 (3) 个路径作为系统环境变量 PSModulePath 的一部分。

%ProgramFiles%\WindowsPowerShell\Modules
%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules
C:\Program Files (x86)\Microsoft SQL Server\140\Tools\PowerShell\Modules\

我假设 SQL Server 的安装创建了最后一个。但是,我删除了前两个,看看 PowerShell 是否可以找到自己的方式,或者他们是否需要它们?

WPS 5.1 64-bit appears to start ok, but ISE reports an error finding `ISE`.
PSC 6.2 starts ok. There is no ISE.
PSC 7.0 starts ok. There is no ISE.

我不得不将%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules 目录放回系统环境变量PSModulePath。之后,WPS 5.1 和 ISE 正常启动。

WPS 5 在启动之前是否需要PSModulePath 中的 System32 目录?我想删除它。而且,实际上,我想将 SQL Server 目录移动到更合适的位置。有更好的地方吗?我经常从 .bat 文件脚本运行powershell -NoProfile,所以我认为六 (6) 个配置文件脚本(如果添加 32 位,则为 12 个)中的任何一个都不是一个好地方。你有什么建议?

更新

=== 启动 cmd.exe

C:>echo %PSModulePath%
C:\Program Files (x86)\Microsoft SQL Server\140\Tools\PowerShell\Modules\;

=== 运行 powershell.exe 5.1.18362.145

C:>$Env:PSModulePath
C:\Users\lit\Documents\WindowsPowerShell\Modules;C:\Program Files (x86)\Microsoft SQL Server\140\Tools\PowerShell\Modules\;C:\Program Files\WindowsPowerShell\Modules

=== 运行 ise

ipmo : The specified module 'ISE' was not loaded because no valid module file was found in any module directory.
At line:1 char:1
+ ipmo ISE
+ ~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (ISE:String) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand

【问题讨论】:

  • system32 位置包含许多重要模块(包括关键的 PowerShell 模块),PsModulePath 是 PowerShell 找到它们的方式。我可以理解 SQL 模块,因为它位于非标准位置,但您为什么要删除其他位置?

标签: powershell powershell-5.0


【解决方案1】:

顺便说一句,回复:

PSC 6.2 [7.0] 启动正常。没有 ISE。

ISE 是一个独立的可执行文件,托管 PowerShell,而不是相反。它只能托管 Windows PowerShell,不能托管 PowerShell Core,因此您不能使用它来开发 PowerShell Core 代码。

关于您的后续问题,“我应该期望有一个用于 PSC 的 ISE,还是我应该认为 VS Code 是可以使用的东西?”

确实,Visual Studio Code 及其 PowerShell extension 是未来使用的编辑器:它能够同时针对 Windows PowerShell 和 PowerShell Core,并且所有未来的开发工作都将用于那里。

相比之下,仅 Windows PowerShell 的 ISE 将看不到新功能。 (虽然 .NET Core 3.0假设为将基于 WPF 的 ISE 移植到 .NET Core 铺平了道路,但我认为这不会发生。)


WPS 5.1 64 位似乎可以启动,但 ISE 报告错误发现 ISE

$env:PSModulePath 中省略目录$env:SYSTEMROOT\system32\WindowsPowerShell\v1.0\Modules 是不明智的,会导致以下症状:

  • 位于该位置的重要系统(Windows PowerShell 随附)模块的命令仍可执行,因为 PowerShell 显然隐式参考了该位置。 p>

  • 但是,命令发现、制表符补全和 显式 通过模块 name 调用 Import-Module(而不是完整路径)然后停止工作:

    • 以 ISE 的启动行为为例,它尝试显式使用ipmo ISE (Import- Module) 加载ISE 模块(以及其他),但失败了。李>
    • 隐式加载模块仍然可以通过简单地直接调用其中一个命令来验证,例如,New-ISESnippet -?

在确定有效的$env:PSModulePath 值时,PS 版本有根本的不同:​​

Windows PowerShell (WPS) 使用复杂的规则来确定要自动将哪些目录添加到$env:PSModulePath;简而言之:

  • all-users 模块目录,$env:ProgramFiles%\WindowsPowerShell\Modules总是自动添加,如果您的 $env:PSModulePath 值是在 注册表中预定义的(默认情况下,它预定义的,并设置为$env:SYSTEMROOT\system32\WindowsPowerShell\v1.0\Modules)。
  • 当前用户 模块目录。仅在没有用户级注册表定义时添加。

  • 您可以使用$env:PSModulePath进程级别 值覆盖所有注册表定义@ 设置临时 调用powershell.exe

PowerShell 核心 (WPC):

  • 完全忽略任何预先存在的基于注册表的$env:PSModulePath 定义,并始终定义自己的标准目录列表。启动时,包括 WPS 位置的 PSC 对应项加上 WPS 的系统模块目录$env:SYSTEMROOT\system32\WindowsPowerShell\v1.0\Modules(因为越来越多的 WPS 系统模块也可从 PSC 使用)。

    • this GitHub issue 首次报告了这种意外行为,...
    • ...导致this RFC,在撰写本文时仍悬而未决,最终解决方案尚未确定。
  • 注入 $env:PSModulePath进程级 值设置临时之前 调用powershell.exe 到其标准目录列表中,之后当前用户条目 - 假设值 与任何基于注册表的定义不同[1]

    • 如果不是基于注册表的值和不同的临时值之间的模糊区别,PSC 的行为可以说是更明智的:它只允许添加到标准目录列表。通过预先存在的 $env:PSModulePath 环境变量值,而不是替换它。

    • 忽略基于注册表的定义是有意义的,因为用户可能使用它来指向包含仅 WSM 模块的目录。但是,如果为 PSC 选择了不同的变量名称,则可以避免该问题 - 这确实是链接 RFC 中正在考虑的解决方案。


我想将 SQL Server 目录移动到更合适的位置。有更好的地方吗?我经常从 .bat 文件脚本运行powershell -NoProfile

没有修改$env:PSModulePath的基于注册表的定义:

  • 适用于两个版本的唯一目录是$env:SYSTEMROOT\system32\WindowsPowerShell\v1.0\Modules,但鉴于此目录是用于 WPS 附带的模块,因此不合适。

  • 特定版本,您可以选择:

    • WPS:$env:ProgramFiles\WindowsPowerShell\Modules
    • PSC:$env:ProgramFiles\PowerShell\Modules

使用修改$env:PSModulePath的基于注册表的定义:

  • 对于WPS,可以在\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment修改$env:PSModulePath的机器级注册表定义(也可以通过sysdm.cplAdvanced>Environment Variables...修改):添加你选择的目录到那里的现有值。

  • 很遗憾,在撰写本文时,这不适用于 PSC,因为它忽略基于注册表的定义,如前所述。


[1] 似乎差异测试实施得很草率,因为设置一个基于注册表的值是 prefix 匹配的临时值被认为是相同的;例如,如果在注册表中定义了值 c:\modules,则 c:\modules.core 的临时值会使 PowerShell Core 认为临时值确实没有不同并忽略它。
除此之外,这种根据定义方法选择性地忽略环境变量值是非常模糊的。

【讨论】:

  • 感谢您一如既往的详细而完整的回答。在启动 WPS 之前,我似乎需要 PSModulePath 变量中的 System32 目录才能使 ISE 工作。我看到 PSC 6 和 7 在启动时忽略了 PSModulePath 中的内容。运行Install-Module -Name SqlServer 后,我发现PSModulePath 没有添加任何内容。我认为不需要它,因为它位于标准用户模块目录中。对吗?
  • 我认为忽略注册表设置是好的。 PSC 运行的其他平台上没有“注册表”。
  • 我的荣幸,@lit;是的,Install-Module 只针对标准目录。:标准的所有用户目录。使用-Scope AllUsers 和标准的当前用户目录。 -Scope CurrentUser(PSC 中的默认值)。
  • 至于忽略注册表:是的,其他平台没有注册表,但是有环境变量,使用注册表是官方定义环境变量的方法持续在 Windows 中。请注意 PSC 确实如何尊重 process-level $env:PSModulePath 值,但前提是它们不同于基于注册表的定义,这是一个高度模糊的区别(这是草率地实施引导 - 请参阅我添加的脚注)。
  • @lit:抛开这个问题不谈,PSC 确实表现出明智的行为,因为它添加 目录。从预先存在的PSModulePath 环境变量到目录列表。而不是覆盖标准的。
猜你喜欢
  • 1970-01-01
  • 2016-09-07
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
相关资源
最近更新 更多