-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathManage-UserPath-BasicOpt.ps1
More file actions
377 lines (332 loc) · 13.9 KB
/
Manage-UserPath-BasicOpt.ps1
File metadata and controls
377 lines (332 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
<#
.SYNOPSIS
交互式PATH管理器(最终兼容版):彻底解决PS5.1数组拼接问题
.DESCRIPTION
适配Windows默认PowerShell 5.1,修复所有已知错误,包含历史记录/批量添加/无效路径清理
.NOTES
无需管理员权限,UTF-8 with BOM编码保存,兼容所有Windows 10/11版本
#>
# -------------------------- 初始化配置 --------------------------
function Write-Color {
param(
[Parameter(Mandatory=$true)][string]$Message,
[Parameter(Mandatory=$false)][ConsoleColor]$Color = [ConsoleColor]::White
)
$originalColor = $Host.UI.RawUI.ForegroundColor
$Host.UI.RawUI.ForegroundColor = $Color
Write-Host $Message
$Host.UI.RawUI.ForegroundColor = $originalColor
}
# 历史记录文件/最大条数
$historyFile = "$env:APPDATA\PathHistory.json"
$maxHistory = 20
# -------------------------- 核心函数(彻底修复数组问题) --------------------------
function Get-UserPathArray {
try {
$rawPath = [Environment]::GetEnvironmentVariable("PATH", "User")
if ([string]::IsNullOrEmpty($rawPath)) { return @() }
$pathArray = $rawPath -split ';' | Where-Object { $_ -ne "" } | Select-Object -Unique | Sort-Object
return $pathArray
}
catch {
Write-Color "❌ 获取PATH失败:$($_.Exception.Message)" -Color Red
return @()
}
}
function Save-UserPath {
param(
[array]$PathArray,
[string]$ActionType
)
try {
$cleanPaths = $PathArray | Select-Object -Unique | Where-Object { $_ -ne "" }
$pathString = $cleanPaths -join ';'
$beforePath = Get-UserPathArray
# 保存PATH并刷新会话
[Environment]::SetEnvironmentVariable("PATH", $pathString, "User")
$systemPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
$env:PATH = "$pathString;$systemPath"
# 记录历史(改用ArrayList)
Record-PathHistory -Action $ActionType -Before $beforePath -After $cleanPaths
return $true
}
catch {
Write-Color "❌ 保存PATH失败:$($_.Exception.Message)" -Color Red
return $false
}
}
# 核心修复:改用ArrayList处理历史记录,彻底避免+拼接问题
function Record-PathHistory {
param(
[Parameter(Mandatory=$true)][string]$Action,
[Parameter(Mandatory=$true)][array]$Before,
[Parameter(Mandatory=$true)][array]$After
)
# 1. 构造历史条目
$historyEntry = [PSCustomObject]@{
Time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Action = $Action
Before = $Before.Count
After = $After.Count
Change = if ($After.Count -gt $Before.Count) { "+$($After.Count - $Before.Count)" }
elseif ($After.Count -lt $Before.Count) { "-$($Before.Count - $After.Count)" }
else { "0" }
}
# 2. 初始化ArrayList(关键:避免PSObject拼接问题)
$historyList = New-Object -TypeName System.Collections.ArrayList
# 3. 读取现有历史(兼容空文件/解析失败)
if (Test-Path $historyFile) {
try {
$rawHistory = Get-Content $historyFile -Encoding utf8 -ErrorAction Stop
if (-not [string]::IsNullOrEmpty($rawHistory)) {
# 读取后强制转为数组,再添加到ArrayList
$parsedHistory = @(ConvertFrom-Json -InputObject $rawHistory -ErrorAction Stop)
foreach ($item in $parsedHistory) {
if ($item -ne $null) { [void]$historyList.Add($item) }
}
}
}
catch {
Write-Color "⚠️ 读取历史记录失败,将新建历史文件" -Color Yellow
}
}
# 4. 添加新条目到ArrayList(安全无冲突)
[void]$historyList.Add($historyEntry)
# 5. 保留最近20条(截取后重新转为ArrayList)
if ($historyList.Count -gt $maxHistory) {
$historyList = New-Object -TypeName System.Collections.ArrayList(($historyList | Select-Object -Last $maxHistory))
}
# 6. 写入文件(PS5.1兼容,无Indent参数)
$historyList | ConvertTo-Json | Out-File $historyFile -Encoding utf8 -Force
}
function Show-PathHistory {
Write-Color "`n==================== PATH 操作历史(最近$maxHistory条) ====================" -Color Cyan
if (-not (Test-Path $historyFile)) {
Write-Color "📌 暂无操作历史" -Color Yellow
return
}
# 用ArrayList读取,避免单条记录问题
$historyList = New-Object -TypeName System.Collections.ArrayList
try {
$rawHistory = Get-Content $historyFile -Encoding utf8
if (-not [string]::IsNullOrEmpty($rawHistory)) {
$parsedHistory = @(ConvertFrom-Json -InputObject $rawHistory)
foreach ($item in $parsedHistory) {
if ($item -ne $null) { [void]$historyList.Add($item) }
}
}
}
catch {
Write-Color "⚠️ 读取历史记录失败,文件可能损坏" -Color Yellow
return
}
if ($historyList.Count -eq 0) {
Write-Color "📌 暂无操作历史" -Color Yellow
return
}
# 格式化显示
for ($i=0; $i -lt $historyList.Count; $i++) {
$entry = $historyList[$i]
Write-Color "[$($i+1)] $($entry.Time) | 操作:$($entry.Action) | 路径数变化:$($entry.Change)" -Color Green
}
Write-Color "==========================================================================`n" -Color Cyan
}
function Clean-InvalidPath {
Write-Color "`n📌 正在检测无效路径(不存在/非文件夹)..." -Color Cyan
$pathArray = Get-UserPathArray
if ($pathArray.Count -eq 0) {
Write-Color "⚠️ 当前用户PATH为空,无需清理" -Color Yellow
return
}
$invalidPaths = @()
foreach ($path in $pathArray) {
if (-not (Test-Path -Path $path -PathType Container)) {
$invalidPaths += $path
}
}
if ($invalidPaths.Count -eq 0) {
Write-Color "✅ 未检测到无效路径,PATH已清理" -Color Green
return
}
Write-Color "⚠️ 检测到 $($invalidPaths.Count) 条无效路径:" -Color Yellow
$invalidPaths | ForEach-Object { Write-Color " - $_" -Color Red }
$confirm = Read-Host "`n是否一键清理所有无效路径?(Y/N 默认N)"
if ($confirm -in "Y","y") {
$newPaths = $pathArray | Where-Object { $_ -notin $invalidPaths }
if (Save-UserPath -PathArray $newPaths -ActionType "Clean") {
Write-Color "✅ 已清理 $($invalidPaths.Count) 条无效路径" -Color Green
}
}
else {
Write-Color "✅ 清理操作已取消" -Color Green
}
}
function Add-BatchPath {
Write-Color "`n📌 批量添加路径(每行输入1个路径,输入空行结束)" -Color Cyan
Write-Color "提示:输入路径时按Tab可自动补全文件夹路径`n" -Color Gray
$batchPaths = @()
$lineNum = 1
while ($true) {
$inputLine = Read-Host "请输入第 $lineNum 个路径(空行结束)"
if ([string]::IsNullOrEmpty($inputLine)) { break }
$cleanPath = $inputLine.Trim().Trim('"').Trim("'")
$batchPaths += $cleanPath
$lineNum++
}
if ($batchPaths.Count -eq 0) {
Write-Color "⚠️ 未输入任何路径,批量添加取消" -Color Yellow
return
}
$currentPaths = Get-UserPathArray
$newPaths = $currentPaths + $batchPaths
if (Save-UserPath -PathArray $newPaths -ActionType "BatchAdd") {
Write-Color "✅ 批量添加完成!共处理 $($batchPaths.Count) 条路径(自动去重)" -Color Green
}
}
# -------------------------- 原有功能 --------------------------
function Show-PathMenu {
Write-Color "`n==================== 当前用户 PATH 环境变量 ====================" -Color Cyan
$pathArray = Get-UserPathArray
if ($pathArray.Count -eq 0) {
Write-Color "📌 当前用户 PATH 为空" -Color Yellow
return
}
for ($i=0; $i -lt $pathArray.Count; $i++) {
Write-Color "[$($i+1)] $($pathArray[$i])" -Color Green
}
Write-Color "==============================================================`n" -Color Cyan
}
function Add-PathMenu {
Write-Color "`n📌 添加路径到当前用户 PATH(自动去重)" -Color Cyan
Write-Color "提示:输入路径后按回车,按Ctrl+C取消`n" -Color Gray
$newPath = Read-Host "请输入要添加的完整路径"
if ([string]::IsNullOrEmpty($newPath)) {
Write-Color "⚠️ 路径不能为空,添加操作取消" -Color Yellow
return
}
$newPath = $newPath.Trim().Trim('"').Trim("'")
if (-not (Test-Path -Path $newPath)) {
$confirm = Read-Host "⚠️ 路径 [$newPath] 不存在,是否仍添加?(Y/N 默认N)"
if ($confirm -notin "Y","y") {
Write-Color "✅ 添加操作取消" -Color Green
return
}
}
$pathArray = Get-UserPathArray
if ($pathArray -contains $newPath) {
Write-Color "⚠️ 路径 [$newPath] 已存在,无需重复添加" -Color Yellow
return
}
$pathArray += $newPath
if (Save-UserPath -PathArray $pathArray -ActionType "Add") {
Write-Color "✅ 路径 [$newPath] 已成功添加" -Color Green
}
}
function Remove-PathMenu {
$pathArray = Get-UserPathArray
if ($pathArray.Count -eq 0) {
Write-Color "⚠️ 当前用户PATH为空,无需删除" -Color Yellow
return
}
Write-Color "`n📌 删除PATH中的路径(输入序号/完整路径)" -Color Cyan
Show-PathMenu
$inputVal = Read-Host "请输入要删除的序号/完整路径"
if ([string]::IsNullOrEmpty($inputVal)) {
Write-Color "⚠️ 输入不能为空,删除操作取消" -Color Yellow
return
}
$targetPath = $null
if ($inputVal -match '^\d+$') {
$index = [int]$inputVal - 1
if ($index -ge 0 -and $index -lt $pathArray.Count) {
$targetPath = $pathArray[$index]
}
else {
Write-Color "❌ 序号超出范围(有效范围:1-$($pathArray.Count))" -Color Red
return
}
}
else {
$inputVal = $inputVal.Trim().Trim('"').Trim("'")
$matchPath = $pathArray | Where-Object { $_.ToLower() -eq $inputVal.ToLower() }
if (-not $matchPath) {
Write-Color "❌ 未找到路径 [$inputVal]" -Color Red
return
}
$targetPath = $matchPath
}
$confirm = Read-Host "⚠️ 确认删除 [$targetPath] 吗?(Y/N 默认N)"
if ($confirm -in "Y","y") {
$newPaths = $pathArray | Where-Object { $_.ToLower() -ne $targetPath.ToLower() }
if (Save-UserPath -PathArray $newPaths -ActionType "Remove") {
Write-Color "✅ 已删除路径 [$targetPath]" -Color Green
}
}
else {
Write-Color "✅ 删除操作已取消" -Color Green
}
}
function Reset-PathMenu {
Write-Color "`n⚠️ 警告:此操作会清空当前用户的所有PATH条目!" -Color Red
$confirm1 = Read-Host "请输入 '确认重置' 四个字以继续(输入其他内容取消)"
if ($confirm1 -ne "确认重置") {
Write-Color "✅ 重置操作已取消" -Color Green
return
}
$confirm2 = Read-Host "最后确认:是否清空?(Y/N 默认N)"
if ($confirm2 -in "Y","y") {
if (Save-UserPath -PathArray @() -ActionType "Reset") {
Write-Color "✅ 当前用户PATH已清空" -Color Green
}
}
else {
Write-Color "✅ 重置操作已取消" -Color Green
}
}
# -------------------------- 主菜单 --------------------------
Clear-Host
Write-Color "==============================================================" -Color Magenta
Write-Color " 🚀 PATH管理器(最终兼容版) 🚀 " -Color Magenta
Write-Color "==============================================================" -Color Magenta
Write-Color "✨ 适配PowerShell 5.1,修复所有数组拼接错误`n" -Color Gray
while ($true) {
Write-Color "请选择操作(输入数字后回车):" -Color Cyan
Write-Color "1. 查看PATH列表(排序+序号)" -Color White
Write-Color "2. 添加单个路径(自动去重)" -Color White
Write-Color "3. 批量添加路径(多行输入)" -Color White
Write-Color "4. 删除路径(序号/路径均可)" -Color White
Write-Color "5. 清理无效路径(自动检测)" -Color White
Write-Color "6. 查看操作历史(最近20条)" -Color White
Write-Color "7. 重置PATH(清空,谨慎!)" -Color White
Write-Color "8. 退出程序" -Color White
$choice = Read-Host "`n请输入操作序号"
if ([string]::IsNullOrEmpty($choice)) {
Write-Color "`n❌ 输入不能为空!`n" -Color Red
Read-Host "按任意键返回主菜单" | Out-Null
Clear-Host
continue
}
Write-Color "`n--------------------------------------------------------------`n" -Color DarkGray
switch ($choice) {
"1" { Show-PathMenu }
"2" { Add-PathMenu }
"3" { Add-BatchPath }
"4" { Remove-PathMenu }
"5" { Clean-InvalidPath }
"6" { Show-PathHistory }
"7" { Reset-PathMenu }
"8" {
Write-Color "👋 感谢使用,再见!" -Color Magenta
exit 0
}
default {
Write-Color "❌ 无效输入!请输入 1-8 之间的数字" -Color Red
}
}
Write-Color "`n--------------------------------------------------------------" -Color DarkGray
Read-Host "按任意键返回主菜单(按Ctrl+C直接退出)" | Out-Null
Clear-Host
Write-Color "==============================================================" -Color Magenta
Write-Color " 🚀 PATH管理器(最终兼容版) 🚀 " -Color Magenta
Write-Color "==============================================================`n" -Color Magenta
}