2015-07-21 11 views
5

Sto scrivendo uno script PowerShell per convertire i nomi delle cartelle in nomi brevi nella variabile di ambiente PATH e salvare le modifiche. Funziona correttamente per i percorsi espliciti, ma espande i token, quindi quando salvi le modifiche i token vengono sostituiti con percorsi espliciti. Mi piacerebbe conservare i token.Come ottenere il valore della variabile di ambiente PATH senza token espandibili?

Per esempio, se il mio PATH è questo: %SystemRoot%;%SystemRoot%\system32;C:\Program Files\TortoiseSVN\bin;C:\ProgramData\chocolatey\bin

voglio che questo risultato: %SystemRoot%;%SystemRoot%\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Ma invece ottengo questo: C:\Windows;C:\Windows\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Ecco lo script completo che illustra il problema.

# get the current path. 
# I ended up not using either of these approaches because they appear to 
# be contextual; on my system, at least, they include paths that aren't 
# seen when I view the PATH value from the System Properties -> Environment 
# Variables dialog box. 
$current_path = $env:Path 
$current_path = [System.Environment]::GetEnvironmentVariable("Path") 

# Instead, I get the PATH value directly from the registry, like so: 
$current_path = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name Path).Path 

# The problem is that PowerShell expands the tokens even when reading from the 
# registry, so I can't detect the tokens and ignore them. What I really want 
# is just the literal string value, with no token evaluation. 
# Here's a sample value; this is what I see in regedt32 and the system dialogs, 
# but it's not what I get from the line above. 
$current_path = '%SystemRoot%;%SystemRoot%\system32;C:\Program Files\TortoiseSVN\bin;C:\ProgramData\chocolatey\bin' 

$new_path = '' 

# the FileSystemObject has a method to convert the path using short names for the folders. 
$fso = New-Object -ComObject Scripting.FileSystemObject 

# Individual paths are delimited by a semicolon. Skip paths with tokens, 
# and preserve trailing slashes in each path. 
$current_path.Split(';') | 
    ForEach-Object { 
     if ($_.StartsWith('%')) 
      { $_ } 
     elseif ($_.EndsWith('\')) 
      { "$($fso.GetFolder($_).ShortPath)\" } 
     else 
      { "$($fso.GetFolder($_).ShortPath)" } 
    } | 
    ForEach-Object { $new_path += "$_;" } 

# remove the extra semicolon from the end the new PATH. 
$new_path = $new_path.TrimEnd(";") 

"Current PATH length: $($current_path.Length)" 
"New PATH length: $($new_path.Length)" 

$new_path 

# commented out so you don't accidentally update your path if you try out this script 
#[System.Environment]::SetEnvironmentVariable("Path", $new_path, "Machine") 

sembra che dovrebbe essere abbastanza facile se solo potessi ottenere il valore stringa letterale dal Registro di sistema, ma finora non sono stati in grado di capire come fare.

risposta

6

Questo non è PowerShell di per sé, ma una "funzionalità" del registro di Windows sottostante. La variabile Path è di tipo REG_EXPAND_SZ che espande automaticamente le variabili d'ambiente al momento del recupero. Non penso che tu possa aggirarlo con i cmdlet incorporati, ma puoi farlo con le API .NET Microsoft.Win32.Registry. Utilizzare il RegistryKey.GetValue sovraccarico RegistryValueOptions.DoNotExpandEnvironmentNames:

$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', $true) 
$regKey.GetValue('Path', $null, "DoNotExpandEnvironmentNames") 

quando è il momento di salvare la variabile, utilizzare il sovraccarico di SetValue con RegistryValueKind.ExpandString per salvarlo con il tipo corretto:

$regKey.SetValue("Path", $new_path, "ExpandString") 
+0

ho dovuto aggiungere un parametro alla chiamata a OpenSubkey(), come ad esempio 'OpenSubKey ('SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Environment', 'ReadWriteSubTree')', prima che mi permettesse di scrivere di nuovo nel registro usando SetValue(), ma altrimenti era esattamente quello che stavo cercando. Grazie molto! – Matt

+0

@Matt Oh sì le chiavi del Registro di sistema non sono modificabili per impostazione predefinita. Devi chiamare quel sovraccarico o quello che prende un bool (come nella mia modifica). –

+0

Utilizzato la risposta per creare uno script PowerShell che ha automatizzato l'aggiunta idempotente di percorsi non espansi: https://gist.github.com/CMCDragonkai/a02d77c2d7c0799dd42fd2aab26a3cd5 – CMCDragonkai

Problemi correlati