Reutilização de variáveis de ambiente no Path

1

É possível reutilizar variáveis de ambiente na variável de ambiente Path do PowerShell?

Existem algumas variáveis de ambiente como %SystemRoot% definidas e são usadas na variável de caminho ...;%SystemRoot%\system32;... visualizada nas Configurações avançadas do sistema.

No PowerShell, eles são definidos como $Env:SystemRoot e $Env:Path parte desse caminho é resolvido com ...;c:\windows\system32;...

Como criar e usar essa variável personalizada no caminho? por exemplo. $Env:MyPath = 'c:\mypath' adicionando-o ao caminho como ...;%MyPath%\documents;... e obtendo o mesmo efeito nas configurações avançadas do sistema e na resolução $Env:Path do PowerShell?

    
por Chesnokov Yuriy 26.02.2015 / 10:15

1 resposta

2

Meu deus, está cheio de variáveis

Existem três tipos de variáveis de ambiente :

  1. Máquina

    The environment variable is stored or retrieved from the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment key in the Windows operating system registry. When a user creates the environment variable in a set operation, the operating system stores the environment variable in the system registry, but not in the current process. If any user on the local machine starts a new process, the operating system copies the environment variable from the registry to that process. When the process terminates, the operating system destroys the environment variable in that process. However, the environment variable in the registry persists until a user removes it programmatically or by means of an operating system tool.

  2. Usuário

    The environment variable is stored or retrieved from the HKEY_CURRENT_USER\Environment key in the Windows operating system registry. When the user creates the environment variable in a set operation, the operating system stores the environment variable in the system registry, but not in the current process. If the user starts a new process, the operating system copies the environment variable from the registry to that process. When the process terminates, the operating system destroys the environment variable in that process. However, the environment variable in the registry persists until the user removes it programmatically or by means of an operating system tool.

  3. Processo

    The environment variable is stored or retrieved from the environment block associated with the current process. The user creates the environment variable in a set operation. When the process terminates, the operating system destroys the environment variable in that process.

Recém-criadas com variáveis de ambiente $env: no PowerShell são do tipo Process . Para a variável a ser exibida na Advanced System Settings , ela é a variável de nível Machine ou User . Para criar variáveis com nível específico, use o método Environment.SetEnvironmentVariable :

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'User')

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')

Note que a configuração de variáveis de ambiente Machine level requer elevação.

Você me lê, HAL?

Então você quer incorporar uma variável de ambiente dentro de outra e expandi-la? Afinal, a Microsoft faz todo o caminho, por exemplo, as variáveis TEMP e TMP por usuário contêm USERPROFILE env.var. Infelizmente, há várias peculiaridades associadas:

  1. A entrada de registro subjacente para essa variável precisa ser REG_EXPAND_SZ type
  2. O env recipiente. variável tem que ser alfabeticamente menos que o env de recipiente. variável:

    If the definition of an environment variable var1 contains another environment variable var2 and the name of var1 is alphabetically less than the name of var2 (i.e. strcmp(var1, var2) < 0), then var2 won't get expanded. This seems to be because when Windows first sets up the environment variables, they are created in alphabetical order, so var2 does not exist until after var1 has already been created (and so the expansion can't be done).

  3. Para a variável PATH , deve haver sem espaços entre as entradas :

    Incorreto: c:\path1; c:\Maven\bin\; c:\path2\
    Correto: c:\path1;c:\Maven\bin\;c:\path2\

Além disso, se você tentar usar o método Environment.SetEnvironmentVariable desta forma:

$Path = [Environment]::GetEnvironmentVariable('Path', 'Machine')

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')
[Environment]::SetEnvironmentVariable('Path', "%MyPath%;$Path", 'Machine')

Ele não renderá a um resultado desejado, porque uma variável PATH recém-criada não terá o tipo REG_EXPAND_SZ , mas REG_SZ .

Abra as portas do compartimento do casulo, HAL

Dado que SetEnvironmentVariable não tem meios para controlar o tipo de entrada de registro resultante, você tem que empregar alternativa: modificar diretamente o registro para criar uma entrada do tipo REG_EXPAND_SZ .

$Path = [Environment]::GetEnvironmentVariable('Path','Machine')

[Environment]::SetEnvironmentVariable('MyPath', 'c:\mypath', 'Machine')

[Microsoft.Win32.Registry]::SetValue(
    'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
    'Path',
    "%MyPath%;$Path",
    [Microsoft.Win32.RegistryValueKind]::ExpandString
)

As desvantagens desse método é que ele não exibe uma mensagem WM_SETTINGCHANGE em todas as janelas do sistema , para que quaisquer aplicativos interessados (como o Windows Explorer, o Gerenciador de Programas, o Gerenciador de Tarefas, o Painel de Controle e assim por diante) possam executar uma atualização.

Para atenuar isso, você pode transmitir a mensagem :

if (-not ('Win32.NativeMethods' -as [type])) {
    # import SendMessageTimeout from Win32
    Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @'

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr hWnd,
            uint Msg,
            UIntPtr wParam,
            string lParam,
            uint fuFlags,
            uint uTimeout,
            out UIntPtr lpdwResult);
'@
}

$HWND_BROADCAST = [System.IntPtr]0xffff
$WM_SETTINGCHANGE = 0x1a
$result = [System.UIntPtr]::Zero

# Notify all windows of environment block change
[Win32.NativeMethods]::SendMessageTimeout(
    $HWND_BROADCAST, $WM_SETTINGCHANGE,
    [System.UIntPtr]::Zero,
    'Environment',
    2,
    5000,
    [ref]$result
);
    
por 28.02.2015 / 23:47