当前位置: 首页 > article >正文

windows@命令行中获取环境变量取值不展开取值(原值)

文章目录

    • 命令行中获取环境变量取值
      • 获取不展开的值
      • 具体实现
      • 注解
    • 封装为函数
      • 版本1
      • 版本2

命令行中获取环境变量取值

  • 这里主要讨论获取未展开的值
  • 本来获取未展开的值应该作为默认选项,至少有合适的api方便直接调用,但是不知道微软怎么想的,让这个任务变得不直接

获取不展开的值

  • 为了便于讨论和实验,下面假设环境变量都讨论的是当前用户级别的环境变量

  • 意思是假设你的环境变量中有一个 exes变量,并假设对应的取值为 C:\exes

  • 现在某个变量比如 Path,或者其他任何引用了 exes的环境变量(例如 创建环境变量 testx,可以通过语句 setx testx %exes%)

  • 在使用命令行查询 testx时查询到的值不是 %exes%,而是其展开值 C:\exes,这会造成许多间接引用的路径发生更改后无法自动更新,造成灵活性下降,特别是通过命令行修改(尤其是添加)多取值环境变量的部分值的时候

    • 比如 %exes%被改为 C:/new/exes,但是由于添加新值前需要获取旧值,旧值中的 %exes%如果被替换为 C:\exes,那么在为 testx添加新值时丢失 %exes%,取而代之的是 C:\exes ,然而这个值不是我们想要的,因为它是死板的,不会随着 %exes%的更新而自动更新
  • 此外,这里的不展开环境变量主要值的是记录着路径的环境变量)

  • 总之,我们需要解决的问题是命令行获取不展开的值

  • 目前的方法是通过访问注册表来获取不展开的值

  • 相关注册表

    • 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' #系统级
      'HKCU:\Environment' #当前用户级
      
  • 相关命令

    • reg query
    • Get-item

具体实现

推荐powershell的Get-item,即(gi)命令来获取

#以'HKCU:\Environment'为例
# 准备用语测试的一对值
setx exes 'C:\exes1'
setx testx %exes1%


#为了获取非展开的原值,可以直接用Get-Item访问'HKCU:\Environment',也可以分为两部分访问路径
#考虑到全局/用户级别环境变量路径都是以environment结尾,这样可以更灵活和选择判断全局还是用户级别
$Name='testx'
#$registerKeyParent=Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
$registerKeyParent=Get-Item -Path 'HKCU:'#获取目标路径的父路径
$RegisterKey = $registerKeyParent.OpenSubKey('Environment')  #打开指定子键


$registryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames

$RegisterKey.GetValue($Name, $null, $registryValueOption)

相关api如下

RegistryKey.GetValue 方法 (Microsoft.Win32) | Microsoft Learn

PS> $envRegisterKey.GetValue

OverloadDefinitions
-------------------
System.Object GetValue(string name)
System.Object GetValue(string name, System.Object defaultValue)
System.Object GetValue(string name, System.Object defaultValue,
Microsoft.Win32.RegistryValueOptions options)

注解

使用此重载指定检索到的值的特殊处理。 例如,可以在检索类型的RegistryValueKind.ExpandString注册表值时指定RegistryValueOptions.DoNotExpandEnvironmentNames检索字符串,而无需展开嵌入的环境变量。

defaultValue使用 参数指定要返回的值(如果name不存在)。

封装为函数

  • 下面两个版本实现方式不同,注意参数不同,根据需要调整

版本1

来源于scoop中的函数Get-EnvVar

function Get-EnvVarRawValue
{
    <#
    .SYNOPSIS
    Retrieve an environment variable value.

    .DESCRIPTION
    This function retrieves the value of the specified environment variable 
    from the registry. It can fetch both user-specific and system-wide variables.

    .PARAMETER Name
    The name of the environment variable.

    .PARAMETER Global
    Switch to indicate if the environment variable is global (system-wide).

    .EXAMPLE
    Get-EnvVar -Name "Path"
    #>
    param(
        [string]$Name,
        [switch]$Global
    )

    # Determine the appropriate registry key to use based on the Global flag
    # User scope uses the HKCU hive, while global (system-wide) uses the HKLM hive
    $registerKey = if ($Global)
    {
        # HKLM hive is used for system-wide environment variables
        # This is the same key used by the system Configuration Manager
        # when setting environment variables through the System Properties
        # control panel
        Get-Item -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
    }
    else
    {
        # HKCU hive is used for user-specific environment variables
        Get-Item -Path 'HKCU:'
    }

    # Open the Environment sub-key off the selected registry key
    $envRegisterKey = $registerKey.OpenSubKey('Environment')

    # Retrieve the value of the specified environment variable
    # The DoNotExpandEnvironmentNames option is used to prevent the registry
    # from expanding any environment variables it finds in the value
    # This is necessary because environment variables can be nested (e.g. %PATH%)
    # and we want to return the raw, unexpanded value
    $registryValueOption = [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
    $envRegisterKey.GetValue($Name, $null, $registryValueOption)
}

版本2

function Get-EnvVarRawValue
{
    <# 
    .SYNOPSIS
    从相应的注册表中读取指定环境变量的取值
    .DESCRIPTION

    # 不会自动转换或丢失%var%形式的Path变量提取
        # 采用reg query命令查询而不使用Get-ItemProperty 查询注册表, 因为Get-ItemProperty 会自动转换或丢失%var%形式的变量
        # 注册表这里也可以区分清楚用户级别和系统级别的环境变量
    #>
    [CmdletBinding()]
    param (
        [Alias('Name', 'Key')]$EnvVar = 'new', 
        [ValidateSet('Machine', 'User', 'Process')]
        $Scope = 'User'
    )
    $currentValue = [System.Environment]::getenvironmentvariable($EnvVar, $Scope)
    if ($CurrentValue)
    {
        if ($scope -eq 'User' -or $scope -eq 'Process')
        {

            $CurrentValueUser = reg query 'HKEY_CURRENT_USER\Environment' /v $EnvVar
            $currentValue = $CurrentValueUser
        }
        if ($scope -eq 'Machine' -or $scope -eq 'Process')
        {
            $currentValueMachine = reg query 'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' /v $EnvVar
            $currentValue = $currentValueMachine

        }
        if ($Scope -eq 'process')
        {

            #recurse
            $U = Get-EnvVarRawValue -EnvVar $EnvVar -Scope 'User'
            $M = Get-EnvVarRawValue -EnvVar $EnvVar -Scope 'Machine'
            $currentValue = (@($U , $M) -join ';') -split ';' | Select-Object -Unique | Remove-RedundantSemicolon
            return $currentValue
            # $CurrentValue = $CurrentValueUser + $currentValueMachine
        }
        $CurrentValue = @($CurrentValue) -join '' #确保$CurrentValue是一个字符串
        # $CurrentValue -match 'Path\s+REG_EXPAND_SZ\s+(.+)'
        # $mts = [regex]::Matches($CurrentValue, $pattern)
        # return $mts
        if (

            $CurrentValue -match 'REG.*SZ\s+(.+)'

        )
        {

            $CurrentValue = $Matches[1] | Remove-RedundantSemicolon
            # 规范化
        }
    }
    if ($VerbosePreference)
    {
        Write-Verbose "RawValue of [$EnvVar]:"
        Write-Host ($currentValue -split ';' | Format-DoubleColumn | Out-String)
    }
    # 返回的是一个字符串,而不是;分隔的字符串数组
    return $currentValue 
}

http://www.kler.cn/a/375286.html

相关文章:

  • 快速入门:Visual Studio 中的 Docker
  • 【网络】HTTP(超文本传输协议)详解
  • 【C++】位图详解(一文彻底搞懂位图的使用方法与底层原理)
  • 手动搭建koa+ts项目框架(node开发配置环境变量)
  • 以「JIMUMETA元宇宙体验馆」为例,探讨有哪些元宇宙场景?
  • C语言串口接收GPS数据
  • 大数据新视界 -- 大数据大厂都在用的数据目录管理秘籍大揭秘,附海量代码和案例
  • 青少年编程与数学 02-003 Go语言网络编程 03课题、网络编程协议
  • 代码随想录训练营Day09 | 150. 逆波兰表达式求值 - 239. 滑动窗口最大值 - 347.前 K 个高频元素
  • 从服务运营的阶段,进入到了精细化管理和智慧化运营的阶段的明厨亮早年开源了
  • ubuntu知识点滴积累
  • AI-基本概念-向量、矩阵、张量
  • 后台管理系统的通用权限解决方案(七)SpringBoot整合SpringEvent实现操作日志记录(基于注解和切面实现)
  • 学习虚幻C++开发日志——基础案例(持续更新中)
  • SpringSecurity框架(入门)
  • PostgreSQL的奥秘:表结构、TOAST与大对象
  • 网络一些相关术语
  • axios 如何取消请求
  • 移植 AWTK 到 纯血鸿蒙(HarmonyOS NEXT)系统 (0) - 序
  • IP 欺骗以及其他常见网络攻击手段(附hping3的实际应用)
  • Qml-Gif的显示
  • 13 实战:使用Python和Pygame实现视频运动估计播放器
  • 二维legendre多项式
  • Oracle 第10章:触发器
  • 关于校验码的算法
  • 《向量数据库指南》——解锁GenAI生态系统新纪元