使用 powershell 将路径永久添加到 Windows 似乎不起作用

2023-11-23

我跟着这个程序为了使用 powershell 永久添加 SumatraPDF 的路径。链接中的最后几个命令旨在检查路径是否确实已添加。

当我使用以下命令访问路径时,

(get-itemproperty -path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path.split(';')

结果包括 SumatraPDF 的路径

C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\OpenSSH\
C:\ProgramData\chocolatey\bin
C:\texlive\2021\bin\win32
C:\Users\921479\AppData\Local\SumatraPDF

但是,当我使用以下命令访问它时,

($env:path).split(';')

结果不包含 SumatraPDF 的路径:

C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\OpenSSH\
C:\ProgramData\chocolatey\bin
C:\texlive\2021\bin\win32
C:\Users\921479\AppData\Local\Microsoft\WindowsApps

终于真正通过了sumatrapdf不起作用,这向我表明真正的路径是使用get-itemproperty命令。

为什么注册表中设置的路径与中设置的路径不对应$env:path?图中所示的程序是否有错误link我跟着?我怎样才能纠正它?

我应该提到我已经尝试重新启动外壳,但它没有帮助。


Note:

  • 请参阅中间部分辅助函数Add-Path

  • 请参阅底部部分为什么使用setx.exe应避免更新Path环境变量.


The 程序中的链接的博客文章是有效的原则,但缺少一条关键信息/附加步骤:

如果直接修改环境变量通过注册表- 不幸的是,is the right这样做的方法REG_EXPAND_SZ基于环境变量,例如Path - 你需要广播一个WM_SETTINGCHANGE message这样 Windows (GUI) shell(及其组件、文件资源管理器、任务栏、桌面、开始菜单,全部通过explorer.exe进程)收到环境变化的通知,并且reloads来自注册表的环境变量。随后启动的应用程序将继承更新后的环境。

  • 如果这条消息是not发送后,未来的 PowerShell 会话(和其他应用程序)在下次登录/重新启动之前不会看到修改。

不幸的是,有没有直接的方法可以从 PowerShell 执行此操作, 但是这里有解决方法:

  • 暴力破解解决方法-简单,但是造成视觉干扰并关闭所有打开的文件资源管理器窗口:

    # Kills all explorer.exe processes, which restarts the Windows shell
    # components, forcing a reload of the environment from the registry.
    Stop-Process -Name explorer
    
  • 解决方法通过.NET API:

    # Create a random name assumed to be unique
    [string] $dummyName = New-Guid
    # Set an environment variable by that name, which makes .NET
    # send a WM_SETTINGCHANGE broadcast
    [Environment]::SetEnvironmentVariable($dummyName, 'foo', 'User')
    # Now that the dummy variable has served its purpose, remove it again.
    # (This will trigger another broadcast, but its performance impact is negligible.)
    [Environment]::SetEnvironmentVariable($dummyName, [NullString]::value, 'User')
    
    • Note: 这个答案解释原因using [Environment]::SetEnvironmentVariable() to directly更新PATH变量是not一个选项从 .NET 8 开始。
  • 解决方法调用Windows API通过临时编译的 P/Invoke 调用SendMessageTimeout()在 C# 中,通过Add-Type:

    • 虽然这是一个正确的解决方案,但总是会导致明显的性能损失由于第一次在会话中运行时进行了临时编译。

    • 详细信息请参见这篇博文.

博客文章中的方法有另一个有问题的方面:

  • It 检索expanded来自注册表的环境变量值,因为这就是Get-ItemProperty and Get-ItemPropertyValue总是这样做。也就是说,如果值中的目录是根据以下定义的其他环境变量 (e.g., %SystemRoot% or %JAVADIR%),返回值不再包含这些变量,而是它们的当前值。请参阅底部部分了解为什么这可能会出现问题。

下一节中讨论的辅助函数可以解决所有问题,同时还确保修改对当前会话 too.


下列Add-Path辅助函数:

  • 添加(附加)给定的单个目录路径到持久用户级 Path默认环境变量;使用-Scope Machine以针对机器级定义,这需要海拔(以管理员身份运行)。

    • 如果目标变量中已存在该目录,则不执行任何操作。

    • 相关的注册表值为updated,这保留了其REG_EXPAND_SZ数据类型,基于现有的未展开的value - 也就是说,对其他环境变量的引用被保留(例如,%SystemRoot%),也可以在添加的新条目中使用。

  • 触发一个WM_SETTINGCHANGE消息广播以通知 Windows shell 有关更改。

  • 还更新了当前会话的 $env:Path变量值。

  • It is unfortunate that PowerShell doesn't ship with this functionality; a previous discussion about providing a cmdlet for robustly and selectively updating $env:PATH has gone nowhere - see the abandoned GitHub RFC #92 (which covered providing cmdlets for managing persistent environment variables in general).[1]

注意:根据定义(由于使用注册表),该函数是仅限 Windows.

通过定义下面的函数,您想要的Path添加可以执行如下,修改当前用户的执着的Path定义:

Add-Path C:\Users\921479\AppData\Local\SumatraPDF

如果您确实想更新机器级定义(在HKEY_LOCAL_MACHINE注册表配置单元,这对于用户特定路径), add -Scope Machine,但并不是说你必须运行有海拔(作为管理员)。

Add-Path源代码:

function Add-Path {

  param(
    [Parameter(Mandatory, Position=0)]
    [string] $LiteralPath,
    [ValidateSet('User', 'CurrentUser', 'Machine', 'LocalMachine')]
    [string] $Scope 
  )

  Set-StrictMode -Version 1; $ErrorActionPreference = 'Stop'

  $isMachineLevel = $Scope -in 'Machine', 'LocalMachine'
  if ($isMachineLevel -and -not $($ErrorActionPreference = 'Continue'; net session 2>$null)) { throw "You must run AS ADMIN to update the machine-level Path environment variable." }  

  $regPath = 'registry::' + ('HKEY_CURRENT_USER\Environment', 'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment')[$isMachineLevel]

  # Note the use of the .GetValue() method to ensure that the *unexpanded* value is returned.
  $currDirs = (Get-Item -LiteralPath $regPath).GetValue('Path', '', 'DoNotExpandEnvironmentNames') -split ';' -ne ''

  if ($LiteralPath -in $currDirs) {
    Write-Verbose "Already present in the persistent $(('user', 'machine')[$isMachineLevel])-level Path: $LiteralPath"
    return
  }

  $newValue = ($currDirs + $LiteralPath) -join ';'

  # Update the registry.
  Set-ItemProperty -Type ExpandString -LiteralPath $regPath Path $newValue

  # Broadcast WM_SETTINGCHANGE to get the Windows shell to reload the
  # updated environment, via a dummy [Environment]::SetEnvironmentVariable() operation.
  $dummyName = [guid]::NewGuid().ToString()
  [Environment]::SetEnvironmentVariable($dummyName, 'foo', 'User')
  [Environment]::SetEnvironmentVariable($dummyName, [NullString]::value, 'User')

  # Finally, also update the current session's `$env:Path` definition.
  # Note: For simplicity, we always append to the in-process *composite* value,
  #        even though for a -Scope Machine update this isn't strictly the same.
  $env:Path = ($env:Path -replace ';$') + ';' + $LiteralPath

  Write-Verbose "`"$LiteralPath`" successfully appended to the persistent $(('user', 'machine')[$isMachineLevel])-level Path and also the current-process value."

}

的局限性setx.exe以及为什么不应该使用它来更新Path环境变量:

setx.exe具有使其成为问题的基本限制,特别是对于更新基于的环境变量REG_EXPAND_SZ-键入的注册表值,例如Path:

  • 值为限制为 1024 个字符,还有其他的得到被截断的,尽管有一个warning(至少从 Windows 10 开始)。

  • The environment variable that is (re)created is with type REG_SZ if the new value happens NOT to contain environment-variable references such as %SystemRoot%.[2] However, Path is originally of type REG_EXPAND_SZ and indeed contains directory paths based on other environment variables, such as %SystemRoot% and %JAVADIR%.

    • 如果新值仅包含literal可能没有的路径(没有环境变量引用)即时不良影响,但是,例如,最初依赖于的条目%JAVADIR%将停止工作,如果%JAVADIR%是后来改变的。同样,如果您稍后添加一个以其他环境变量表示的条目,则此类条目将not被扩大。
  • 此外,如果您根据当前会话的更新值$env:Path值,你最终会得到复制条目,因为过程级 $env:Path值是一个合成的机器级别和当前用户级别值。

    • 这会增加遇到 1024 个字符限制的风险,特别是在使用该技术的情况下反复。它还承担重复值的风险挥之不去原始条目从原始范围中删除后。

    • 虽然您可以通过直接从注册表检索特定于范围的值来避免此特定问题,或者总是在expanded形式-通过[Environment]::GetEnvironmentVariable('Path', 'User') or [Environment]::GetEnvironmentVariable('Path', 'Machine'),仍然没有解决REG_EXPAND_SZ上面讨论的问题。


[1] A prototype implementation of new cmdlets for managing persistent environment variables is available via the PowerShell Gallery, though it seems to languish and, crucially, lacks support for expandable environment variables (REG_EXPAND_SZ) as of this writing, which makes it unsuitable for PATH updates.

[2] That is, setx.exe decides whether to (re)create the underlying registry value as REG_SZ (static) or REG_EXPAND_SZ purely based on the presence of environment-variable references such as %SystemRoot% in the new value - irrespective of a preexisting registry value's current type.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 powershell 将路径永久添加到 Windows 似乎不起作用 的相关文章

  • C++ 使用 Windows 命名管道

    由于某种原因 桅杆和从属装置都失败了 但是我可以找到任何关于它们如何工作的好例子 所以我不确定我哪里出了问题 在 ConnectNamedPipe 之后 主设备永远不会退出 WaitForSingleObject 并且从设备在第一个 boo
  • 如何在 Ubuntu VirtualBox 中运行 Meteor 应用程序并使用 Windows 主机上的编辑器进行编辑?

    我希望在运行 Ubuntu 的 virtualbox 来宾中运行一个用于开发目的的流星服务器 该项目将位于主机上的一个文件夹内 该文件夹将共享给来宾 该文件夹本身位于 Dropbox 文件夹内 这样我可以在多个虚拟机和工作站之间共享开发 但
  • 无法加载 JNI 共享库 (JDK)

    当我尝试打开时Eclipse http www eclipse org 弹出对话框指出 无法加载 JNI 共享库 C JDK bin client jvm dll 此后 Eclipse 强制关闭 我想提出以下几点 我检查了这条路径上是否存在
  • 使用 sed 更新 xml 属性(Windows + cygwin 和 Linux)?

    我需要使用 sed 命令对 xml 文件进行更新 但我在这方面遇到了麻烦 它需要在 Windows 使用 cygwin 和 Linux 上运行 XML 具有以下元素
  • conio.h 不包含 textcolor()?

    我一直在考虑在我用 C 编写的 DOS 程序中使用颜色 有人告诉我conio h有textcolor 函数 但是当我在代码中使用它时 编译器 链接器会向我抛出错误 说我对该函数有未定义的引用 Does conio h真的有这个功能还是有人告
  • Linux 中的动态环境变量?

    Linux 中是否可以通过某种方式拥有动态环境变量 我有一个网络服务器 网站遵循以下布局 site qa production 我想要一个环境变量 例如 APPLICATION ENV 当我在 qa 目录中时设置为 qa 当我在生产目录中时
  • netsh 结果到 PowerShell 对象

    我正在尝试与NETSH https ss64 com nt netsh html来自 PowerShell 我想看到这个命令的结果 例如一个对象 但是netsh返回一个字符串 netsh wlan show hostednetwork Ge
  • 仅在单个端口 8080 上转发到本地主机(Windows)可能吗? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我知道如何在 Windows 上使用 xampp 设置本地网络服务器 我在主机文件 c windows system32 drivers etc ho
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • Windows 窗体中的标准 Windows 菜单栏

    我注意到添加了一个MenuStrip 来自工具箱 我的表单设计不会产生像许多本机 Windows 应用程序中那样的菜单栏 相反 我得到了一个像 Visual Studio 自己的菜单栏 没有任何样式设置MenuStrip似乎模仿了更常见的本
  • PowerShell中有解析TOML文件的模块吗?

    我正在尝试寻找一个TOML https toml ioPowerShell 的文件解析器 我也找不到任何有关它的信息PowerShell 画廊 https www powershellgallery com 或在预安装的 PowerShel
  • 从命令提示符/批处理文件添加环境变量

    我正在尝试在批处理文件中添加环境变量 系统 以下命令显示错误 语法无效 有人可以帮忙吗 对我来说它看起来不错 reg add HKLM SYSTEM CurrentControlSet Control Session Manager Env
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • 从其可执行文件的路径获取服务名称

    我有一个可执行文件的路径 它是一个正在运行的服务应用程序 例如 C Program Files x86 Someapp somesvc exe 我想停止并启动它 为此我想我需要获取服务的名称 如下所示 this https stackove
  • sqlite3-ruby gem:无法构建 gem 本机扩展

    Update 看看这个后续问题 Windows 上的 Gem 更新 它坏了吗 https stackoverflow com questions 134581 gem update on windows is it broken 在 Win
  • 将带有星号的注册表项传递给测试路径

    我想通过以下方式运行此注册表路径Test Path在 PowerShell 中 但它包含一个星号 该星号在注册表中有效 但在 Windows 路径中无效 问题是 当我通过它时 Test Path将星号视为通配符 因此这需要非常非常长的时间
  • PowerShell FTP 下载文件和子文件夹

    我喜欢写一个PowerShell脚本来下载全部文件 and 子文件夹从我的 FTP 服务器 我找到了一个脚本来下载一个特定文件夹中的所有文件 但我也喜欢下载子文件夹及其文件 FTP Server Information SET VARIAB
  • 如何在 Eclipse .classpath 文件中使用环境变量?

    在 Windows 中 我有一个环境变量 EXTERNAL LIB ROOT 指向 C Program Files MyExternalLibRoot 在另一台计算机上 它可能指向 C ExternalLibs 在 ant build xm
  • 如何为 Windows toast 注册协议?

    如何注册 Windows toast 协议 样本中来自https blogs msdn microsoft com tiles and toasts 2015 07 02 adaptive and interactive toast not

随机推荐

  • Hash::make('password') 每次调用返回不同的结果

    所以 标题基本上描述了我的问题 我的 Hash make 疯了 我已经创建了一个带有哈希密码的用户表 但我无法让 Laravel 接受我的凭据 我认为问题出在 Hash make 中 因此 测试这段代码 Route get function
  • 如何复制word文档的内容?

    我想编写一个程序 从 Word 文档复制文本并将其粘贴到另一个文档 我正在尝试使用python docx图书馆 我可以使用以下代码来做到这一点 但它不会复制bold italic 下划线或彩色部分原样 仅包含其文本 from docx im
  • Rails 5 db:重置不起作用

    我想重置 Rails 5 项目的数据库 但是rails db reset命令不起作用 错误信息 Permission denied unlink internal C sites5 dawnrebirth db development sq
  • 在 div 中包围希伯来语和英语文本

    我正在尝试在段落中的希伯来语和英语句子周围添加跨度标签 例如 那么 到底怎么样了 会变成 span so span span span span all whats up span span span 我一直在尝试使用正则表达式 但它只是删
  • 将html模板文件合并到一个JS文件中

    我有 HTML 模板文件 下划线模板语法 这些文件以 HTML 格式保存 因此很容易编辑 IDE 语法突出显示 我不想用ajax获取它们 而是将它们全部组合起来并将它们包含为js file 使用 GULP 作为我的任务运行程序 我希望它能以
  • 如何限制通过 cin 输入的字符数?

    我希望限制用户可以输入的字符数 使用cin 例如 我可能希望将其限制为两个字符 我该怎么做 我的代码如下所示 cin gt gt var 您可以使用setw cin gt gt setw 2 gt gt var http www cplus
  • NSPredicate iPhone 3.2 SDK核心数据“IN子句”NSInvalidArgumentException异常

    我有一个收藏Calendar对象并希望通过它们来查询它们service id财产 我在 iPhone 3 2 SDK 上使用 Core Data 和 sqlite calendars是一个 NSArray 结果NSFetchRequest
  • 谁最终决定什么是通用类型?

    我有这个功能 public static T2 MyFunc
  • 在 Plone 构建设置中查找需求规格

    我有一个 Plone 网站 大约 4 2 4 从version txt在根目录中 我想更新到最新版本 我发现这个操作方法 截至目前 4 3 4 我继承了过多的固定版本 这些版本没有记录并且可能已经过时 当评论我的versions cfg u
  • 如何设置 JSplitPane-Divider 折叠/展开状态?

    我有一个带有 JSplitPane 的 JFrame 它是 OneTouchExpandable 我想记住 JFrame 上 JSplitPane 的最后一个分隔符位置 并在重新打开 JFrame 时恢复位置 它工作得很好 但如果用户通过
  • 使用存储库的工作单元模式中的依赖项注入

    我想创建一个工作单元类 以类似的方式包装存储库this 我遇到的问题是尝试通过用 IRepository 接口替换示例中的通用存储库来实现依赖项注入 在链接文章的 uow 中 他们使用 getter 来检查存储库是否已实例化 如果没有则实例
  • npm install puppeteer 显示权限被拒绝错误

    我无法安装puppeteer作为项目依赖项 我尝试重新安装节点 有人知道如何解决这个问题吗 运行 Ubuntu 17 10 x64 sudo apt get purge nodejs curl sL https deb nodesource
  • 新手势 - 从左向右滑动 - 作为旧应用程序中 UINavigationController 中“后退”按钮的快捷方式

    iOS 7 采用了一种新手势 即在屏幕上从左向右滑动作为 UINavigationController 中 后退 按钮的快捷方式 我的应用程序似乎没有免费获取此行为 我需要做什么才能让我的 iOS 应用程序 在 Xcode 4 6 3 中为
  • Android Camera2 API 显示处理后的预览图像

    新的 Camera 2 API 与旧的有很大不同 向管道的用户部分显示操纵的相机帧让我感到困惑 我知道有很好的解释使用 Android L 和 Camera2 API 处理相机预览图像数据但显示帧仍然不清楚 我的问题是 在经过一些处理后 在
  • 用传单绘制特定国家的地图

    我想使用该包leaflet用R绘制特定国家的地图 如意大利 西班牙等 我用函数检查了基本示例setView 我尝试为纬度和经度的 arg 给出两个值的向量 m lt leaflet gt addTiles gt Add default Op
  • NUMA 获取当前节点/核心

    我在 Linux 上使用 libnuma 我的线程应该知道它们正在运行的节点 核心 是否有可能以某种方式获取当前线程的节点 核心 我已经浏览了文档 但没有找到这样的功能 我找到了这个解决方案 include
  • 限制完成时的 IntelliJ IDEA 导入建议

    当我输入需要导入的类的名称时 IntelliJ 会亲切地弹出一个建议列表 然而 大多数时候 这些建议是我永远不想导入的东西 尤其是偶然的 比如java awt 有没有办法防止我永远不会导入的包出现在完成列表中 我已经搜索了这些选项 但没有找
  • 使用 MPI_Bcast 进行 MPI 通信

    我正在尝试使用 MPI Bcast 将消息从根节点广播到所有其他节点 然而 每当我运行这个程序时 它总是在开始时挂起 有人知道这是怎么回事吗 include
  • Cassandra 中的高基数和低基数

    我不断遇到这些术语 high cardinality and low cardinality in Cassandra 我不明白它们到底是什么意思 它们对查询有什么影响以及首选是什么 请举例说明 因为这样很容易理解 X 的基数只不过是组成
  • 使用 powershell 将路径永久添加到 Windows 似乎不起作用

    我跟着这个程序为了使用 powershell 永久添加 SumatraPDF 的路径 链接中的最后几个命令旨在检查路径是否确实已添加 当我使用以下命令访问路径时 get itemproperty path Registry HKEY LOC