"USN Change Journal DELETE/CREATE" PowerShell Betiği

Programlama ve Script dilleri konusunda bilgi paylaşım alanıdır.
Cevapla
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15575
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2703 kez
Teşekkür edildi: 5605 kez

"USN Change Journal DELETE/CREATE" PowerShell Betiği

Mesaj gönderen TRWE_2012 »

Merhabalar

Aslında böyle bir betik filan tasarlamak aklımda yoktu ama son zamanlar'da

Kod: Tümünü seç

chkdsk C:
sorgusunda, böyle ifadeler sıklaşmaya başlayınca, anladım ki, NTFS USN Günlüklerinin bozulduğunu....

Kod: Tümünü seç

Stage 3: Examining security descriptors ...
Cleaning up 43 unused index entries from index $SII of file 9.
Cleaning up 43 unused index entries from index $SDH of file 9.
Cleaning up 43 unused security descriptors.
Security descriptor verification completed.
 Phase duration (Security descriptor verification): 14.08 milliseconds.
  69564 data files processed.
 Phase duration (Data attribute verification): 0.94 milliseconds.
CHKDSK is verifying Usn Journal...
  35749512 USN bytes processed.
Usn Journal verification completed.
 Phase duration (USN journal verification): 212.12 milliseconds.
Yukarıdaki kodlamada

Kod: Tümünü seç

Cleaning up 43 unused index entries from index $SII of file 9.
Cleaning up 43 unused index entries from index $SDH of file 9.
Cleaning up 43 unused security descriptors.
Bunlardan kurtulmak için WinPE11_10_8_Sergei_Strelec_x86_x64_2026.04.14.ENG.ISO ile

Kod: Tümünü seç

chkdsk C: /F /R /V
komutunu uyguyordum ama her seferinde geri geliyordu , anladım ki bu ne bir disk bozulması nede dosya sistemi hatasıydı, tamamen USN günlüklerden kaynaklanıyordu.İşte bende bundan kurtulmak için aşağdaki betiği tasarladım...

WinPE11_10_8_Sergei_Strelec_x86_x64_2026.04.14.ENG.ISO İNDİRME BAĞLANTISI :

https://sergeistrelec.name/winpe_10_8/2 ... D1%8F.html

usn_journal_reset6.ps1

Kod: Tümünü seç

# ==========================================================================
# Script Name : usn_journal_reset version 6.0.ps1
# Purpose     : General-purpose tool. Deletes and recreates the NTFS USN
#               Change Journal for one or more user-selected drives on any
#               Windows system, using fsutil, with a mandatory wait-and-
#               verify buffer between deletion and recreation. Detects all
#               NTFS volumes on the system dynamically (not tied to any
#               fixed drive letters) and reports whether each volume sits
#               on an SSD or HDD to help the user make an informed choice.
#               Accepts journal size input in MB and converts it to bytes
#               automatically. Verifies administrator privileges before
#               attempting any operation.
# Note        : fsutil usn deletejournal /d starts an ASYNCHRONOUS deletion
#               and returns immediately; the actual deletion continues in
#               the background. This script triggers deletion first, waits
#               a fixed 30 second buffer, then actively verifies deletion
#               completed (extending the wait if needed) before collecting
#               user input and creating the new journal. This avoids
#               Error 1178 (journal delete in progress).
# ==========================================================================

# fsutil / Win32 error codes relevant to USN journal operations
$ERROR_SUCCESS                = 0
$ERROR_JOURNAL_DELETE_IN_PROGRESS = 1178
$ERROR_JOURNAL_NOT_ACTIVE     = 1179

Clear-Host
Write-Host "=========================================="
Write-Host " USN Journal Reset Tool (MB input)"
Write-Host "=========================================="
Write-Host ""

# Verify the script is running with administrator privileges
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

if (-not $isAdmin) {
    Write-Host "ERROR: This script must be run with administrator privileges." -ForegroundColor Red
    Write-Host "USN journal operations (query, delete, create) require membership in the Administrators group." -ForegroundColor Red
    Read-Host "`nPress ENTER to exit."
    exit 1
}

Write-Host "Administrator privileges confirmed." -ForegroundColor Green
Write-Host ""

# Retrieve all volumes that have a drive letter and are NTFS formatted
$volumes = Get-Volume -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter -and $_.FileSystem -eq "NTFS" } | Sort-Object DriveLetter

if (-not $volumes -or $volumes.Count -eq 0) {
    Write-Host "No NTFS volumes with an assigned drive letter were found." -ForegroundColor Red
    Read-Host "`nPress ENTER to exit."
    exit 1
}

Write-Host "Available NTFS volumes:"
Write-Host ""

$volumeMap = @{}
$index = 1

foreach ($vol in $volumes) {
    $sizeGB = [math]::Round($vol.Size / 1GB, 2)
    $label  = if ($vol.FileSystemLabel) { $vol.FileSystemLabel } else { "(no label)" }

    # Determine the media type (SSD / HDD / Unknown) of the physical disk
    # underlying this volume, by walking Volume -> Partition -> Disk -> PhysicalDisk.
    # IMPORTANT: Get-Partition's DiskNumber and Get-PhysicalDisk's DeviceId
    # do not always share the same numbering scheme (this can differ on
    # systems with mixed NVMe/SATA controllers). Comparing them directly
    # can silently produce a wrong match. The reliable approach is to pipe
    # Get-Disk directly into Get-PhysicalDisk, which uses the correct
    # internal CIM association instead of a manual numeric comparison.
    $mediaType = "Unknown"
    try {
        $partition = Get-Partition -DriveLetter $vol.DriveLetter -ErrorAction Stop
        $physicalDisk = Get-Disk -Number $partition.DiskNumber -ErrorAction Stop | Get-PhysicalDisk -ErrorAction Stop
        if ($physicalDisk -and $physicalDisk.MediaType) {
            $mediaType = $physicalDisk.MediaType
        }
    } catch {
        # Storage cmdlets may be unavailable or the mapping may fail on some
        # systems (e.g. certain virtual disks); fall back to "Unknown"
        # rather than stopping the script.
    }

    Write-Host ("[{0}] Drive {1}:  Size={2} GB  Type={3}  Label={4}" -f $index, $vol.DriveLetter, $sizeGB, $mediaType, $label)
    $volumeMap[$index] = $vol.DriveLetter
    $index++
}

Write-Host ""
Write-Host "Enter the numbers of the drives to process, separated by commas (e.g. 1,3)."
$selectionRaw = Read-Host "Or type ALL to select every listed drive"

$selectedLetters = @()

if ($selectionRaw.Trim().ToUpper() -eq "ALL") {
    $selectedLetters = $volumeMap.Values
} else {
    $parts = $selectionRaw -split "," | ForEach-Object { $_.Trim() }
    foreach ($part in $parts) {
        $num = 0
        if ([int]::TryParse($part, [ref]$num) -and $volumeMap.ContainsKey($num)) {
            $selectedLetters += $volumeMap[$num]
        } else {
            Write-Host "Ignoring invalid entry: $part" -ForegroundColor Yellow
        }
    }
}

if ($selectedLetters.Count -eq 0) {
    Write-Host "No valid drives were selected. No action was taken." -ForegroundColor Red
    Read-Host "`nPress ENTER to exit."
    exit 1
}

Write-Host ""
Write-Host "The journal on the following drives will now be DELETED:" -ForegroundColor Yellow
$selectedLetters | ForEach-Object { Write-Host " - ${_}:" -ForegroundColor Yellow }
Write-Host ""
$preConfirm = Read-Host "Type YES (in capital letters) to trigger deletion now"

if ($preConfirm -cne "YES") {
    Write-Host "Operation cancelled by user. No changes were made." -ForegroundColor Yellow
    Read-Host "`nPress ENTER to exit."
    exit 0
}

# Step 1: trigger deletion on every selected drive right away.
foreach ($letter in $selectedLetters) {
    $target = "${letter}:"
    Write-Host ""
    Write-Host "Triggering journal deletion for $target ..." -ForegroundColor Cyan
    fsutil usn deletejournal /d $target
    if ($LASTEXITCODE -ne $ERROR_SUCCESS) {
        Write-Host "Delete command returned exit code $LASTEXITCODE for $target (this can be normal if no journal existed yet)" -ForegroundColor Yellow
    }
}

# Step 2: mandatory 30 second buffer with a countdown, since deletion
# runs asynchronously in the background and needs time to complete.
Write-Host ""
Write-Host "Waiting 30 seconds for background deletion to complete on all selected drives..." -ForegroundColor Cyan
for ($remaining = 30; $remaining -gt 0; $remaining--) {
    Write-Host -NoNewline "`rTime remaining: $remaining seconds  "
    Start-Sleep -Seconds 1
}
Write-Host "`rInitial 30 second wait complete.                  "
Write-Host ""

# Step 3: actively verify the "delete in progress" transitional state has
# ended for each drive; extend the wait in 2 second increments (up to 60
# additional seconds) if needed.
#
# IMPORTANT: fsutil does not reliably surface specific Win32 error numbers
# (such as 1178 "delete in progress" or 1179 "not active") as the process
# exit code ($LASTEXITCODE) - it typically returns a generic 0 or 1, and
# the actual error number only appears in the printed text. We therefore
# inspect the text output directly instead of relying on $LASTEXITCODE.
#
# We only need to wait until the drive is OUT of the transitional
# "being deleted" state. Once out of that state, createjournal succeeds
# whether the drive currently has no journal or already has one (for
# example a default one that Windows or a background service may have
# recreated automatically) - createjournal updates an existing journal in
# place rather than requiring it to be absent.
function Wait-ForDeleteInProgressToClear {
    param(
        [string]$Target,
        [int]$ExtraTimeoutSeconds = 60
    )

    $deletingPattern = "1178|being deleted|siliniyor"

    $output = (& fsutil usn queryjournal $Target 2>&1 | Out-String)
    if ($output -notmatch $deletingPattern) {
        return $true
    }

    $elapsed = 0
    while ($elapsed -lt $ExtraTimeoutSeconds) {
        Start-Sleep -Seconds 2
        $elapsed += 2
        $output = (& fsutil usn queryjournal $Target 2>&1 | Out-String)
        if ($output -notmatch $deletingPattern) {
            return $true
        }
    }
    return $false
}

$readyDrives = @()
foreach ($letter in $selectedLetters) {
    $target = "${letter}:"
    Write-Host "Verifying deletion status for $target ..." -NoNewline
    if (Wait-ForDeleteInProgressToClear -Target $target -ExtraTimeoutSeconds 60) {
        Write-Host " ready." -ForegroundColor Green
        $readyDrives += $letter
    } else {
        Write-Host " still in progress after extended wait." -ForegroundColor Red
        Write-Host "Skipping $target to avoid Error 1178. You can re-run the script for this drive later." -ForegroundColor Red
    }
}

if ($readyDrives.Count -eq 0) {
    Write-Host ""
    Write-Host "No drives are ready for journal creation. Exiting." -ForegroundColor Red
    Read-Host "`nPress ENTER to exit."
    exit 1
}

# Step 4: now that deletion is confirmed, collect the desired size for
# each drive that is ready.
$driveSizeMap = @{}

Write-Host ""
Write-Host "Enter the desired USN journal size in MB for each drive." -ForegroundColor Cyan
Write-Host "Minimum recommended value is 1 MB. Press ENTER to use the default of 64 MB." -ForegroundColor Cyan
Write-Host ""

foreach ($letter in $readyDrives) {
    $sizeMbRaw = Read-Host "Journal size in MB for drive ${letter}:"
    $sizeMb = 64
    if ($sizeMbRaw.Trim() -ne "") {
        $parsedMb = 0
        if ([int64]::TryParse($sizeMbRaw.Trim(), [ref]$parsedMb) -and $parsedMb -gt 0) {
            $sizeMb = $parsedMb
        } else {
            Write-Host "Invalid value entered for drive ${letter}:. Falling back to default 64 MB." -ForegroundColor Yellow
        }
    }
    $driveSizeMap[$letter] = $sizeMb
}

Write-Host ""
Write-Host "The following journals will now be created:" -ForegroundColor Yellow
foreach ($letter in $readyDrives) {
    $sizeMb = $driveSizeMap[$letter]
    $sizeBytes = [int64]$sizeMb * 1MB
    $deltaBytes = [int64]($sizeBytes * 0.2)
    Write-Host (" - Drive {0}:  Maximum Size = {1} MB ({2} bytes)  Allocation Delta = {3} bytes" -f $letter, $sizeMb, $sizeBytes, $deltaBytes)
}
Write-Host ""

$finalConfirm = Read-Host "Type YES (in capital letters) to confirm and create the journals"

if ($finalConfirm -cne "YES") {
    Write-Host "Operation cancelled by user. Journals were deleted but not recreated." -ForegroundColor Yellow
    Write-Host "Windows may automatically recreate a default-sized journal (typically 32 MB) on these drives if a background service requests one." -ForegroundColor Yellow
    Read-Host "`nPress ENTER to exit."
    exit 0
}

foreach ($letter in $readyDrives) {
    $target = "${letter}:"
    $sizeMb = $driveSizeMap[$letter]
    $sizeBytes = [int64]$sizeMb * 1MB
    $deltaBytes = [int64]($sizeBytes * 0.2)

    Write-Host ""
    Write-Host "==========================================" -ForegroundColor Cyan
    Write-Host " Creating journal on drive $target (target size: $sizeMb MB)" -ForegroundColor Cyan
    Write-Host "==========================================" -ForegroundColor Cyan

    $createSucceeded = $false
    for ($attempt = 1; $attempt -le 3; $attempt++) {
        $createOutput = (& fsutil usn createjournal m=$sizeBytes a=$deltaBytes $target 2>&1 | Out-String)
        if ($createOutput.Trim() -ne "" -and $createOutput -notmatch "1178|1179|Error|Hata") {
            # fsutil prints nothing on success for createjournal; any
            # unexpected text is treated as a potential error message.
        }
        if ($createOutput -match "1178|1179|Error|Hata") {
            Write-Host $createOutput.Trim() -ForegroundColor Yellow
            Write-Host "Attempt $attempt reported an error. Retrying in 2 seconds..." -ForegroundColor Yellow
            Start-Sleep -Seconds 2
            continue
        }
        $createSucceeded = $true
        break
    }

    if ($createSucceeded) {
        Write-Host "Journal successfully created for $target" -ForegroundColor Green
    } else {
        Write-Host "Failed to create journal for $target after multiple attempts." -ForegroundColor Red
        continue
    }

    Write-Host "`nVerifying new journal size..."
    fsutil usn queryjournal $target
}

Write-Host ""
Write-Host "All ready drives have been processed." -ForegroundColor Green

Read-Host "`nPress ENTER to exit."
Betiğin Resimli Textsel Anlatımı :
Resim
Ekran Görüntüsü :
Resim
Tüm Akış Mantığı :

1.Yönetici yetkisi kontrolü : Script başlar başlamaz WindowsPrincipal ile Administrators grubunda olup olmadığınız kontrol edilir; değilseniz script anında sonlanır.

2.Sürücü taraması : Get-Volume ile sistemdeki tüm NTFS, sürücü harfi atanmış bölümler dinamik olarak listelenir (sabit C:/D:/E: varsayımı yoktur).

3.SSD/HDD tespiti : Her bölüm için Get-Partition → Get-Disk → Get-PhysicalDisk zinciriyle fiziksel diskin türü (SSD/HDD) bulunup listede gösterilir.

4.Kullanıcı sürücü seçimi : Numaralarla (1,3 gibi) veya ALL yazarak işlem yapılacak sürücüler seçilir.

5.İlk onay : Seçilen sürücülerdeki journal'ların silineceği açıkça belirtilir; yalnızca büyük harflerle "YES" yazılırsa devam edilir.

6.Silme tetiklenir : Seçilen her sürücüde fsutil usn deletejournal /d çalıştırılır (bu işlem arka planda asenkron devam eder).

7.30 saniyelik sabit bekleme : Silme işleminin arka planda tamamlanabilmesi için ekranda geri sayımlı bir bekleme uygulanır.

8.Aktif doğrulama : 30 saniye sonunda, her sürücü için fsutil usn queryjournal çıktısı metin olarak taranır ("siliniyor/being deleted/1178" ifadesi var mı); hâlâ "siliniyor" durumundaysa 2 saniye aralıklarla en fazla 60 saniye daha beklenir.

9.Hazır olmayan sürücüler elenir : Doğrulama süresi dolan bir sürücü varsa, işlem durdurulmaz; o sürücü atlanıp diğerleriyle devam edilir.

10.Boyut girişi : Yalnızca "hazır" onayı almış sürücüler için, MB cinsinden hedef journal boyutu kullanıcıdan istenir (boş bırakılırsa varsayılan 64 MB).

11.Otomatik bayt dönüşümü ve delta hesaplama : Girilen MB değeri 1MB ile çarpılarak bayta çevrilir; Allocation Delta, bu değerin %20'si olarak otomatik hesaplanır.

12.İkinci onay : Oluşturulacak journal'ların nihai boyutları özetlenip tekrar "YES" onayı istenir; onaylanmazsa journal'lar silinmiş ama yeniden oluşturulmamış halde bırakıldığı konusunda uyarı verilir.

13.Journal oluşturma : Onaylanan her sürücüde fsutil usn createjournal m=... a=... çalıştırılır; çıktı metninde hata ifadesi varsa 2 saniye arayla en fazla 3 kez tekrar denenir.

14.Sonuç doğrulaması : Her sürücü için işlem sonunda otomatik olarak fsutil usn queryjournal çalıştırılıp yeni Maximum Size, Allocation Delta ve Usn Journal ID ekrana yazdırılır.

15.Kapanış : Tüm sürücüler işlendikten sonra özet mesaj gösterilir ve Press ENTER to exit. ile script sonlandırılır.

SONUÇ :
Resim
Güle güle kullanın...
Cevapla

“Programlama ve Script dilleri” sayfasına dön