Загрузка данных


& {
    $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)
        $end = $data.Length - 1

        if ($data.Length -lt 2 -or $data[$end] -ne 1) {
            throw 'Неожиданный формат файла. Замена отменена.'
        }

        $encoding = [Text.UnicodeEncoding]::new($false, $false, $true)
        $output = [IO.MemoryStream]::new()
        $removed = [Collections.Generic.List[string]]::new()

        $output.WriteByte($data[0])
        $pos = 1

        while ($pos -lt $end) {
            if ($pos + 5 -gt $end) {
                throw "Неполная запись на смещении $pos."
            }

            $size = [int]$data[$pos + 3] +
                    ([int]$data[$pos + 4] -shl 8)

            $start = $pos + 5
            $next = $start + $size + 7

            if ($size -lt 2 -or ($size % 2) -ne 0 -or $next -gt $end) {
                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:\
            if ($appPath.StartsWith('D:\', [StringComparison]::OrdinalIgnoreCase)) {
                $removed.Add($appPath)
            }
            else {
                # Все остальные записи сохраняем без изменений.
                $output.Write($data, $pos, $next - $pos)
            }

            $pos = $next
        }

        $output.WriteByte(1)

        if ($removed.Count -eq 0) {
            Write-Host 'Записей D:\ не найдено. Файл не изменён.'
            return
        }

        Write-Host "`nБудут удалены записи из истории NVIDIA:"
        $removed | Sort-Object -Unique | ForEach-Object { Write-Host $_ }
        Write-Host "`nВсего записей: $($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())

        # Настоящий null для строкового параметра: резервная копия отключена.
        [IO.File]::Replace(
            $temporary,
            $file,
            [System.Management.Automation.Language.NullString]::Value
        )

        $temporary = $null
        Write-Host "`nГотово. Удалено записей D:\: $($removed.Count)"
        Write-Host 'Резервная копия не создавалась.'
    }
    catch {
        Write-Warning ("Ошибка: " + $_.Exception.Message)

        if ($temporary -and [IO.File]::Exists($temporary)) {
            Write-Host "После ошибки остался временный файл: $temporary"
        }
    }
    finally {
        if ($reader) { $reader.Dispose() }
        if ($guard)  { $guard.Dispose() }
        if ($output) { $output.Dispose() }
    }
}