2015-07-21 12 views
5

Tôi đang viết kịch bản PowerShell để chuyển đổi tên thư mục thành tên viết tắt trong biến môi trường PATH và lưu các thay đổi. Nó hoạt động chính xác cho đường dẫn rõ ràng, nhưng nó mở rộng mã thông báo, vì vậy khi tôi lưu thay đổi của tôi, mã thông báo được thay thế bằng đường dẫn rõ ràng. Tôi muốn giữ lại các thẻ.Cách lấy giá trị của biến môi trường PATH mà không cần mở rộng mã thông báo?

Ví dụ, nếu PATH của tôi là thế này: %SystemRoot%;%SystemRoot%\system32;C:\Program Files\TortoiseSVN\bin;C:\ProgramData\chocolatey\bin

Tôi muốn kết quả này: %SystemRoot%;%SystemRoot%\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Nhưng thay vào đó tôi có được điều này: C:\Windows;C:\Windows\system32;C:\PROGRA~1\TORTOI~1\bin;C:\PROGRA~3\CHOCOL~1\bin

Dưới đây là kịch bản đầy đủ để minh họa vấn đề.

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

Dường như nó cũng đủ dễ dàng nếu tôi chỉ nhận được giá trị chuỗi ký tự từ sổ đăng ký, nhưng tôi vẫn chưa thể tìm ra cách thực hiện điều đó.

Trả lời

6

Đây không phải là PowerShell trên mỗi tiện ích, mà là "tính năng" của đăng ký Windows cơ bản. Biến Path có kiểu REG_EXPAND_SZ tự động mở rộng các biến môi trường khi truy xuất. Tôi không nghĩ rằng bạn có thể nhận được xung quanh nó với các lệnh ghép ngắn sẵn có, nhưng bạn có thể thực hiện với các API .NET Microsoft.Win32.Registry. Sử dụng quá tải RegistryKey.GetValue với RegistryValueOptions.DoNotExpandEnvironmentNames:

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

khi đó là thời gian để lưu các thay đổi, sử dụng sự quá tải của SetValue với RegistryValueKind.ExpandString để lưu nó với đúng loại:

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

tôi phải thêm một tham số để gọi OpenSubkey(), giống như vậy 'OpenSubKey ('SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Environment', 'ReadWriteSubTree')', trước khi nó cho phép tôi ghi lại sổ đăng ký bằng SetValue(), nhưng ngược lại chính xác là những gì tôi đang tìm kiếm. Cảm ơn nhiều! – Matt

+0

@Matt Oh yea các khóa registry không thể ghi theo mặc định. Bạn cần phải gọi đó là quá tải hoặc một trong đó có một bool (như trong chỉnh sửa của tôi). –

+0

Đã sử dụng câu trả lời của bạn để tạo tập lệnh PowerShell tự động bổ sung idempotent đường dẫn chưa được mở rộng: https://gist.github.com/CMCDragonkai/a02d77c2d7c0799dd42fd2aab26a3cd5 – CMCDragonkai

Các vấn đề liên quan