Загрузка данных
$ErrorActionPreference = "Stop"
$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$ArchiveRoot = "V:\C_Drive_Archive\Installers_$TimeStamp"
$Log = Join-Path $ArchiveRoot "Move_Installers.log"
$Manifest = Join-Path $ArchiveRoot "Manifest.csv"
function Write-Log {
param([string]$Text)
$Line = "{0} {1}" -f (
Get-Date -Format "yyyy-MM-dd HH:mm:ss"
), $Text
Write-Host $Line
$Line |
Out-File `
-FilePath $Log `
-Encoding UTF8 `
-Append
}
function Get-CDriveInfo {
$Drive = Get-WmiObject `
Win32_LogicalDisk `
-Filter "DeviceID='C:'"
[pscustomobject]@{
SizeGB = [math]::Round($Drive.Size / 1GB, 2)
UsedGB = [math]::Round(
($Drive.Size - $Drive.FreeSpace) / 1GB,
2
)
FreeGB = [math]::Round($Drive.FreeSpace / 1GB, 2)
FreePct = [math]::Round(
($Drive.FreeSpace / $Drive.Size) * 100,
1
)
}
}
$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
return
}
$VDrive = Get-PSDrive -Name V -ErrorAction SilentlyContinue
if (-not $VDrive) {
Write-Host ""
Write-Host "Диск V: не найден. Операция отменена." `
-ForegroundColor Red
return
}
if ($VDrive.Free -lt 5GB) {
Write-Host ""
Write-Host "На диске V: недостаточно свободного места." `
-ForegroundColor Red
return
}
New-Item `
-Path $ArchiveRoot `
-ItemType Directory `
-Force |
Out-Null
$Before = Get-CDriveInfo
Write-Log "============================================================"
Write-Log "АРХИВАЦИЯ УСТАНОВОЧНЫХ ФАЙЛОВ С ДИСКА C:"
Write-Log "============================================================"
Write-Log "Каталог архива: $ArchiveRoot"
Write-Log "До операции свободно на C: $($Before.FreeGB) GB"
Write-Log ""
$Candidates = New-Object System.Collections.ArrayList
$DataFiles = @(
"C:\Data\LibreOffice_25.8.1_Win_x86-64.msi",
"C:\Data\LibreOffice_25.2.6_Win_x86-64.msi"
)
foreach ($Path in $DataFiles) {
if (Test-Path -LiteralPath $Path) {
[void]$Candidates.Add(
[pscustomobject]@{
Source = $Path
Category = "Data"
}
)
}
}
if (Test-Path -LiteralPath "C:\distr") {
Get-ChildItem `
-LiteralPath "C:\distr" `
-File `
-Force `
-ErrorAction SilentlyContinue |
Where-Object {
$_.Name -like "pgadmin4-*.exe"
} |
ForEach-Object {
[void]$Candidates.Add(
[pscustomobject]@{
Source = $_.FullName
Category = "distr"
}
)
}
}
if ($Candidates.Count -eq 0) {
Write-Log "Подходящие установочные файлы не найдены."
return
}
Write-Log "Найденные файлы:"
$CandidateReport = foreach ($Candidate in $Candidates) {
$Item = Get-Item -LiteralPath $Candidate.Source
[pscustomobject]@{
Path = $Item.FullName
Size = "{0:N2} MB" -f ($Item.Length / 1MB)
}
}
$CandidateReport |
Format-Table -AutoSize |
Out-String -Width 300 |
ForEach-Object {
Write-Log $_
}
$TotalCandidateBytes = (
$Candidates |
ForEach-Object {
(Get-Item -LiteralPath $_.Source).Length
} |
Measure-Object -Sum
).Sum
Write-Log (
"Общий размер кандидатов: {0:N2} GB" -f (
$TotalCandidateBytes / 1GB
)
)
Write-Log ""
$Results = New-Object System.Collections.ArrayList
foreach ($Candidate in $Candidates) {
$Source = $Candidate.Source
$SourceItem = Get-Item -LiteralPath $Source
$DestinationFolder = Join-Path `
$ArchiveRoot `
$Candidate.Category
New-Item `
-Path $DestinationFolder `
-ItemType Directory `
-Force |
Out-Null
$Destination = Join-Path `
$DestinationFolder `
$SourceItem.Name
Write-Log "------------------------------------------------------------"
Write-Log "Источник: $Source"
Write-Log "Назначение: $Destination"
Write-Log (
"Размер: {0:N2} MB" -f (
$SourceItem.Length / 1MB
)
)
$Result = [ordered]@{
Source = $Source
Destination = $Destination
SizeBytes = $SourceItem.Length
SourceSHA256 = $null
DestinationSHA256 = $null
Copied = $false
Verified = $false
SourceDeleted = $false
Error = $null
}
try {
$SourceHash = (
Get-FileHash `
-LiteralPath $Source `
-Algorithm SHA256
).Hash
$Result.SourceSHA256 = $SourceHash
Copy-Item `
-LiteralPath $Source `
-Destination $Destination `
-Force `
-ErrorAction Stop
$Result.Copied = $true
$DestinationItem = Get-Item `
-LiteralPath $Destination
$DestinationHash = (
Get-FileHash `
-LiteralPath $Destination `
-Algorithm SHA256
).Hash
$Result.DestinationSHA256 = $DestinationHash
$SizeMatches = (
$SourceItem.Length -eq
$DestinationItem.Length
)
$HashMatches = (
$SourceHash -eq
$DestinationHash
)
if (-not $SizeMatches) {
throw "Размер исходного файла и копии не совпадает."
}
if (-not $HashMatches) {
throw "Контрольные суммы SHA256 не совпадают."
}
$Result.Verified = $true
Write-Log "Копия успешно проверена по размеру и SHA256."
Remove-Item `
-LiteralPath $Source `
-Force `
-ErrorAction Stop
$Result.SourceDeleted = $true
Write-Log "Исходный файл удалён с диска C:."
}
catch {
$Result.Error = $_.Exception.Message
Write-Log "ОШИБКА: $($_.Exception.Message)"
Write-Log "Исходный файл оставлен без изменений."
}
[void]$Results.Add(
[pscustomobject]$Result
)
}
$Results |
Export-Csv `
-Path $Manifest `
-NoTypeInformation `
-Encoding UTF8
$After = Get-CDriveInfo
$Freed = [math]::Round(
$After.FreeGB - $Before.FreeGB,
2
)
Write-Log ""
Write-Log "============================================================"
Write-Log "ОПЕРАЦИЯ ЗАВЕРШЕНА"
Write-Log "============================================================"
Write-Log "До операции свободно: $($Before.FreeGB) GB"
Write-Log "После операции свободно: $($After.FreeGB) GB"
Write-Log "Освобождено: $Freed GB"
Write-Log "Свободно сейчас: $($After.FreePct)%"
Write-Log ""
Write-Log "Архив: $ArchiveRoot"
Write-Log "Манифест: $Manifest"
Write-Log "Лог: $Log"
Write-Host ""
Write-Host "Результат по файлам:" -ForegroundColor Cyan
$Results |
Select-Object `
Source,
@{N="SizeMB";E={
[math]::Round($_.SizeBytes / 1MB, 2)
}},
Copied,
Verified,
SourceDeleted,
Error |
Format-Table -AutoSize
Write-Host ""
Write-Host "Состояние диска C:" -ForegroundColor Cyan
Get-CDriveInfo |
Format-List