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.
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
@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). –
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