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


$ErrorActionPreference = "SilentlyContinue"

$ScanRoot = "C:\"
$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$Report = "C:\Disk_C_Audit_$TimeStamp.txt"

$IsAdmin = (
    New-Object Security.Principal.WindowsPrincipal(
        [Security.Principal.WindowsIdentity]::GetCurrent()
    )
).IsInRole(
    [Security.Principal.WindowsBuiltInRole]::Administrator
)

if (-not $IsAdmin) {
    Write-Host ""
    Write-Host "ОШИБКА: PowerShell необходимо запустить от имени администратора." -ForegroundColor Red
    Write-Host ""
    return
}

function Convert-Size {
    param(
        [long]$Bytes
    )

    if ($Bytes -ge 1TB) {
        return "{0:N2} TB" -f ($Bytes / 1TB)
    }
    elseif ($Bytes -ge 1GB) {
        return "{0:N2} GB" -f ($Bytes / 1GB)
    }
    elseif ($Bytes -ge 1MB) {
        return "{0:N2} MB" -f ($Bytes / 1MB)
    }
    elseif ($Bytes -ge 1KB) {
        return "{0:N2} KB" -f ($Bytes / 1KB)
    }
    else {
        return "$Bytes B"
    }
}

function Add-Size {
    param(
        [hashtable]$Table,
        [string]$Key,
        [long]$Length
    )

    if ([string]::IsNullOrEmpty($Key)) {
        return
    }

    if ($Table.ContainsKey($Key)) {
        $Table[$Key] += $Length
    }
    else {
        $Table[$Key] = $Length
    }
}

function Add-ReportText {
    param(
        [string]$Text
    )

    $Text | Out-File `
        -FilePath $Report `
        -Encoding UTF8 `
        -Append `
        -Width 300
}

function Add-ReportObject {
    param(
        $Object
    )

    $Object |
        Out-String -Width 300 |
        Out-File `
            -FilePath $Report `
            -Encoding UTF8 `
            -Append
}

$TopLevelSizes = @{}
$SecondLevelSizes = @{}
$WatchPathSizes = @{}
$ExtensionSizes = @{}

$LargeFiles = New-Object System.Collections.ArrayList

$WatchPaths = [ordered]@{
    "C:\Windows\Temp"                              = "Windows TEMP"
    "C:\Windows\SoftwareDistribution\Download"    = "Кэш обновлений Windows"
    "C:\Windows\Logs\CBS"                         = "Логи CBS"
    "C:\Windows\Logs\DISM"                        = "Логи DISM"
    "C:\Windows\Minidump"                         = "Минидампы Windows"
    "C:\Windows\Installer"                        = "Windows Installer — вручную не удалять"
    "C:\Windows\WinSxS"                           = "WinSxS — вручную не удалять"
    "C:\inetpub\logs\LogFiles"                    = "Логи IIS"
    "C:\ProgramData\Microsoft\Windows\WER"         = "Отчёты об ошибках WER"
    "C:\ProgramData\Package Cache"                 = "Package Cache — вручную не удалять"
    "C:\`$Recycle.Bin"                             = "Корзина"
}

foreach ($Label in $WatchPaths.Values) {
    $WatchPathSizes[$Label] = 0L
}

$WatchPathSizes["TEMP всех пользователей"] = 0L

$Drive = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'"
$OS = Get-WmiObject Win32_OperatingSystem

"" | Out-File -FilePath $Report -Encoding UTF8

Add-ReportText "============================================================"
Add-ReportText "ОТЧЁТ ПО ИСПОЛЬЗОВАНИЮ ДИСКА C:"
Add-ReportText "============================================================"
Add-ReportText ""
Add-ReportText ("Компьютер:      {0}" -f $env:COMPUTERNAME)
Add-ReportText ("Операционная ОС: {0}" -f $OS.Caption)
Add-ReportText ("Версия ОС:       {0}" -f $OS.Version)
Add-ReportText ("Дата проверки:   {0}" -f (Get-Date))
Add-ReportText ""
Add-ReportText ("Размер диска C:  {0}" -f (Convert-Size $Drive.Size))
Add-ReportText ("Занято:          {0}" -f (Convert-Size ($Drive.Size - $Drive.FreeSpace)))
Add-ReportText ("Свободно:        {0}" -f (Convert-Size $Drive.FreeSpace))
Add-ReportText ("Свободно, %:     {0:N1}%" -f (($Drive.FreeSpace / $Drive.Size) * 100))
Add-ReportText ""

Write-Host ""
Write-Host "============================================================"
Write-Host "СКАНИРОВАНИЕ ДИСКА C:"
Write-Host "============================================================"
Write-Host ""
Write-Host "Проверка может занять 5–20 минут."
Write-Host "Никакие файлы не удаляются."
Write-Host ""

$Stack = New-Object System.Collections.Stack
$Stack.Push((Get-Item -LiteralPath $ScanRoot -Force))

$FileCount = 0L
$DirectoryCount = 0L
$ReadErrors = 0L
$TotalFoundSize = 0L

while ($Stack.Count -gt 0) {

    $CurrentDirectory = $Stack.Pop()
    $DirectoryCount++

    if (($DirectoryCount % 1000) -eq 0) {
        Write-Host (
            "Папок: {0:N0}; файлов: {1:N0}; найдено: {2}" -f `
                $DirectoryCount,
                $FileCount,
                (Convert-Size $TotalFoundSize)
        )
    }

    try {
        $Files = $CurrentDirectory.GetFiles()
    }
    catch {
        $ReadErrors++
        $Files = @()
    }

    foreach ($File in $Files) {

        try {
            $Length = [long]$File.Length
            $FullName = $File.FullName
        }
        catch {
            $ReadErrors++
            continue
        }

        $FileCount++
        $TotalFoundSize += $Length

        $RelativePath = $FullName.Substring($ScanRoot.Length)
        $Parts = $RelativePath.Split("\")

        if ($Parts.Count -eq 1) {
            $TopLevelName = "[Файлы в корне C:\]"
        }
        else {
            $TopLevelName = $Parts[0]
        }

        Add-Size `
            -Table $TopLevelSizes `
            -Key $TopLevelName `
            -Length $Length

        if ($Parts.Count -ge 2) {

            if ($TopLevelName -ne "[Файлы в корне C:\]") {
                $SecondLevelName = $Parts[0] + "\" + $Parts[1]

                Add-Size `
                    -Table $SecondLevelSizes `
                    -Key $SecondLevelName `
                    -Length $Length
            }
        }

        foreach ($WatchPath in $WatchPaths.Keys) {

            if (
                $FullName.StartsWith(
                    $WatchPath + "\",
                    [System.StringComparison]::OrdinalIgnoreCase
                ) -or
                $FullName.Equals(
                    $WatchPath,
                    [System.StringComparison]::OrdinalIgnoreCase
                )
            ) {
                $WatchPathSizes[$WatchPaths[$WatchPath]] += $Length
            }
        }

        if (
            $FullName -match "\\Users\\[^\\]+\\AppData\\Local\\Temp\\"
        ) {
            $WatchPathSizes["TEMP всех пользователей"] += $Length
        }

        $Extension = $File.Extension

        if ([string]::IsNullOrEmpty($Extension)) {
            $Extension = "[без расширения]"
        }
        else {
            $Extension = $Extension.ToLower()
        }

        Add-Size `
            -Table $ExtensionSizes `
            -Key $Extension `
            -Length $Length

        if ($Length -ge 50MB) {

            [void]$LargeFiles.Add(
                [pscustomobject]@{
                    Path          = $FullName
                    SizeBytes     = $Length
                    Size          = Convert-Size $Length
                    LastWriteTime = $File.LastWriteTime
                }
            )
        }
    }

    try {
        $SubDirectories = $CurrentDirectory.GetDirectories()
    }
    catch {
        $ReadErrors++
        $SubDirectories = @()
    }

    foreach ($SubDirectory in $SubDirectories) {

        try {
            $IsReparsePoint = (
                $SubDirectory.Attributes -band
                [System.IO.FileAttributes]::ReparsePoint
            )

            if (-not $IsReparsePoint) {
                $Stack.Push($SubDirectory)
            }
        }
        catch {
            $ReadErrors++
        }
    }
}

Write-Host ""
Write-Host "Сканирование завершено." -ForegroundColor Green
Write-Host ""

Add-ReportText "============================================================"
Add-ReportText "1. РАЗМЕР КАТАЛОГОВ В КОРНЕ C:"
Add-ReportText "============================================================"
Add-ReportText ""

$TopLevelReport = $TopLevelSizes.GetEnumerator() |
    Sort-Object Value -Descending |
    ForEach-Object {
        [pscustomobject]@{
            Folder    = $_.Key
            Size      = Convert-Size $_.Value
            SizeBytes = $_.Value
        }
    }

Add-ReportObject (
    $TopLevelReport |
        Select-Object Folder, Size
)

Add-ReportText "============================================================"
Add-ReportText "2. КРУПНЕЙШИЕ КАТАЛОГИ ВТОРОГО УРОВНЯ"
Add-ReportText "============================================================"
Add-ReportText ""

$SecondLevelReport = $SecondLevelSizes.GetEnumerator() |
    Sort-Object Value -Descending |
    Select-Object -First 50 |
    ForEach-Object {
        [pscustomobject]@{
            Folder = "C:\" + $_.Key
            Size   = Convert-Size $_.Value
        }
    }

Add-ReportObject $SecondLevelReport

Add-ReportText "============================================================"
Add-ReportText "3. КРУПНЫЕ ФАЙЛЫ — ОТ 50 MB"
Add-ReportText "============================================================"
Add-ReportText ""

$LargeFilesReport = $LargeFiles |
    Sort-Object SizeBytes -Descending |
    Select-Object -First 80 `
        Path,
        Size,
        LastWriteTime

Add-ReportObject $LargeFilesReport

Add-ReportText "============================================================"
Add-ReportText "4. СИСТЕМНЫЕ КАТАЛОГИ И ВОЗМОЖНЫЕ КАНДИДАТЫ НА ОЧИСТКУ"
Add-ReportText "============================================================"
Add-ReportText ""

$WatchPathReport = $WatchPathSizes.GetEnumerator() |
    Sort-Object Value -Descending |
    ForEach-Object {
        [pscustomobject]@{
            Location = $_.Key
            Size     = Convert-Size $_.Value
        }
    }

Add-ReportObject $WatchPathReport

Add-ReportText "============================================================"
Add-ReportText "5. КРУПНЕЙШИЕ ТИПЫ ФАЙЛОВ"
Add-ReportText "============================================================"
Add-ReportText ""

$ExtensionReport = $ExtensionSizes.GetEnumerator() |
    Sort-Object Value -Descending |
    Select-Object -First 30 |
    ForEach-Object {
        [pscustomobject]@{
            Extension = $_.Key
            Size      = Convert-Size $_.Value
        }
    }

Add-ReportObject $ExtensionReport

Add-ReportText "============================================================"
Add-ReportText "6. PAGEFILE, MEMORY DUMP И СИСТЕМНЫЕ ФАЙЛЫ"
Add-ReportText "============================================================"
Add-ReportText ""

$SystemFiles = @(
    "C:\pagefile.sys",
    "C:\swapfile.sys",
    "C:\hiberfil.sys",
    "C:\Windows\MEMORY.DMP"
)

$SystemFileReport = foreach ($Path in $SystemFiles) {

    if (Test-Path -LiteralPath $Path) {

        $Item = Get-Item -LiteralPath $Path -Force

        [pscustomobject]@{
            Path          = $Item.FullName
            Size          = Convert-Size $Item.Length
            LastWriteTime = $Item.LastWriteTime
        }
    }
}

Add-ReportObject $SystemFileReport

Add-ReportText "Использование файлов подкачки:"
Add-ReportText ""

$PageFileUsage = Get-WmiObject Win32_PageFileUsage |
    Select-Object `
        Name,
        AllocatedBaseSize,
        CurrentUsage,
        PeakUsage

Add-ReportObject $PageFileUsage

Add-ReportText "Настройки файлов подкачки:"
Add-ReportText ""

$PageFileSettings = Get-WmiObject Win32_PageFileSetting |
    Select-Object `
        Name,
        InitialSize,
        MaximumSize

Add-ReportObject $PageFileSettings

Add-ReportText "============================================================"
Add-ReportText "7. ТЕНЕВЫЕ КОПИИ VSS"
Add-ReportText "============================================================"
Add-ReportText ""

$VssOutput = & vssadmin.exe list shadowstorage 2>&1
Add-ReportText ($VssOutput | Out-String -Width 300)

Add-ReportText "============================================================"
Add-ReportText "8. СОСТОЯНИЕ ХРАНИЛИЩА КОМПОНЕНТОВ WINDOWS"
Add-ReportText "============================================================"
Add-ReportText ""

$DismOutput = & dism.exe /Online /Cleanup-Image /AnalyzeComponentStore 2>&1
Add-ReportText ($DismOutput | Out-String -Width 300)

Add-ReportText "============================================================"
Add-ReportText "9. ИТОГ СКАНИРОВАНИЯ"
Add-ReportText "============================================================"
Add-ReportText ""
Add-ReportText ("Обработано каталогов: {0:N0}" -f $DirectoryCount)
Add-ReportText ("Обработано файлов:    {0:N0}" -f $FileCount)
Add-ReportText ("Размер файлов:        {0}" -f (Convert-Size $TotalFoundSize))
Add-ReportText ("Ошибок чтения:        {0:N0}" -f $ReadErrors)
Add-ReportText ""
Add-ReportText "ВАЖНО:"
Add-ReportText "Не удаляйте вручную содержимое Windows\Installer, WinSxS,"
Add-ReportText "System32, ProgramData и неизвестные файлы из Program Files."
Add-ReportText ""

Write-Host "============================================================"
Write-Host "ОТЧЁТ СОЗДАН"
Write-Host "============================================================"
Write-Host ""
Write-Host $Report -ForegroundColor Cyan
Write-Host ""
Write-Host "Размер отчёта:"
Write-Host ((Get-Item $Report).Length.ToString() + " байт")
Write-Host ""