Загрузка данных
& {
$ErrorActionPreference = 'Stop'
$file = Join-Path $env:ProgramData 'NVIDIA Corporation\Drs\nvAppTimestamps'
$output = $null
$guard = $null
$reader = $null
$temporary = $null
try {
[byte[]]$data = [IO.File]::ReadAllBytes($file)
if ($data.Length -lt 2 -or $data[0] -ne 1 -or $data[1] -ne 0) {
throw 'Неожиданный заголовок файла. Замена отменена.'
}
$encoding = [Text.UnicodeEncoding]::new($false, $false, $true)
$output = [IO.MemoryStream]::new()
$removed = [Collections.Generic.List[string]]::new()
$output.Write($data, 0, 2)
$pos = 2
$total = 0
while ($pos -lt $data.Length) {
if ($pos + 4 -gt $data.Length) {
throw "Неполная запись на смещении $pos."
}
$size = [int][BitConverter]::ToUInt16($data, $pos + 2)
$start = $pos + 4
$next = $start + $size + 8
if ($size -lt 2 -or ($size % 2) -ne 0 -or $next -gt $data.Length) {
throw "Некорректная длина записи на смещении $pos."
}
if ($data[$start + $size - 2] -ne 0 -or
$data[$start + $size - 1] -ne 0) {
throw "Не найден конец строки на смещении $pos."
}
$appPath = $encoding.GetString($data, $start, $size - 2)
if ($appPath.IndexOf([char]0) -ge 0) {
throw "Неожиданная структура строки на смещении $pos."
}
# Проверяем оба вида путей: D:\... и D:/...
if ($appPath.Replace('\', '/').StartsWith(
'D:/', [StringComparison]::OrdinalIgnoreCase
)) {
$removed.Add($appPath)
}
else {
# Всю оставляемую запись переносим побайтно без изменений.
$output.Write($data, $pos, $next - $pos)
}
$pos = $next
$total++
}
if ($removed.Count -eq 0) {
Write-Host 'В этом файле записей с D: нет. Файл не изменён.'
return
}
Write-Host "`nИз истории NVIDIA будут удалены:"
$removed | ForEach-Object { Write-Host $_ }
Write-Host "`nУдалить: $($removed.Count). Оставить: $($total - $removed.Count)."
if ((Read-Host 'Введи DELETE для удаления БЕЗ резервной копии') -cne 'DELETE') {
Write-Host 'Отмена. Файл не изменён.'
return
}
# Проверяем исходный файл ещё раз перед заменой.
$share = [IO.FileShare]::Read -bor [IO.FileShare]::Delete
$guard = [IO.File]::Open(
$file, [IO.FileMode]::Open, [IO.FileAccess]::Read, $share
)
$reader = [IO.BinaryReader]::new($guard)
[byte[]]$current = $reader.ReadBytes($data.Length + 1)
if ([Convert]::ToBase64String($current) -cne
[Convert]::ToBase64String($data)) {
throw 'Файл изменился за время подтверждения. Замена отменена; повтори запуск.'
}
# Временный файл содержит только новый результат, не резервную копию.
$temporary = "$file.$([Guid]::NewGuid().ToString('N')).new"
[IO.File]::WriteAllBytes($temporary, $output.ToArray())
[IO.File]::Replace(
$temporary,
$file,
[System.Management.Automation.Language.NullString]::Value
)
$temporary = $null
Write-Host "`nГотово. Удалено записей с D: $($removed.Count)."
Write-Host "Оставлено остальных записей: $($total - $removed.Count)."
Write-Host 'Резервная копия не создавалась.'
}
catch {
Write-Warning ("Ошибка: " + $_.Exception.Message)
}
finally {
if ($reader) { $reader.Dispose() }
if ($guard) { $guard.Dispose() }
if ($output) { $output.Dispose() }
if ($temporary -and [IO.File]::Exists($temporary)) {
try {
[IO.File]::Delete($temporary)
}
catch {
Write-Warning "Не удалось убрать временный файл: $temporary"
}
}
}
}