2015-07-21 3 views
5

Ich schreibe ein PowerShell-Skript, um Ordnernamen in kurze Namen in der PATH-Umgebungsvariablen zu konvertieren und die Änderungen zu speichern. Es funktioniert korrekt für explizite Pfade, aber es erweitert Tokens. Wenn ich also meine Änderungen speichere, werden die Token durch explizite Pfade ersetzt. Ich möchte die Token bewahren.Wie erhält man den Wert der PATH-Umgebungsvariablen, ohne Tokens zu erweitern?

Zum Beispiel, wenn mein PATH dies: %SystemRoot%;%SystemRoot%\system32;C:\Program Files\TortoiseSVN\bin;C:\ProgramData\chocolatey\bin

Ich möchte dieses Ergebnis: %SystemRoot%;%SystemRoot%\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Aber stattdessen bekomme ich dies: C:\Windows;C:\Windows\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Hier ist das vollständige Skript ist, das das Problem veranschaulicht.

# 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") 

Es scheint, wie es einfach genug sein soll, wenn ich nur den Zeichenkette Wert aus der Registrierung bekommen konnte, aber ich habe bisher nicht in der Lage gewesen, um herauszufinden, wie das zu tun.

Antwort

6

Dies ist nicht PowerShell per se, sondern ein "Feature" der zugrunde liegenden Windows-Registrierung. Die Path-Variable ist vom Typ REG_EXPAND_SZ, die Umgebungsvariablen beim Abruf automatisch erweitert. Ich denke nicht, dass Sie es mit den integrierten Cmdlets umgehen können, aber Sie können mit den .NET Microsoft.Win32.Registry APIs. Verwenden Sie die RegistryKey.GetValue Überlastung mit RegistryValueOptions.DoNotExpandEnvironmentNames:

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

, wenn es Zeit ist, um die Variable zu speichern, verwenden Sie die Überlastung von SetValue mit RegistryValueKind.ExpandString es mit dem richtigen Typ zu speichern:

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

ich einen Parameter hinzuzufügen hatte zum Aufruf von OpenSubkey(), so wie 'OpenSubKey ('SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Environment', 'ReadWriteSubTree')', bevor ich mit SetValue() zurück in die Registry schreiben könnte, aber ansonsten das war genau das, wonach ich suchte. Danke vielmals! – Matt

+0

@Matt Oh ja, die Registrierungsschlüssel sind standardmäßig nicht beschreibbar. Sie müssen diese Überladung oder die, die ein bool (wie in meiner Bearbeitung) nimmt. –

+0

Ihre Antwort wurde verwendet, um ein Powershell-Skript zu erstellen, das das idempotente Hinzufügen von nicht erweiterten Pfaden automatisiert: https://gist.github.com/CMCDragonkai/a02d77c2d7c0799dd42fd2aab26a3cd5 – CMCDragonkai

Verwandte Themen