Проект

Общее

Профиль

Бэкап Hyper-V через PowerShell » Бэкап Hyper-V через PowerShell.txt

Redmine Admin, 25.03.2026 10:44

 
Скрипт PowerShell (Backup-HyperV.ps1)
Этот скрипт делает следующее:
Создает папку для бэкапа с текущей датой.
Экспортирует все виртуальные машины в эту папку.
Удаляет папки с бэкапами, старше 180 дней.
Ведет лог действий.
Создайте файл C:\Scripts\Backup-HyperV.ps1 и вставьте в него этот код:

powershell
# ================= НАСТРОЙКИ =================
$BackupRootPath = "D:\HyperVBackups" # Путь, где будут храниться бэкапы
$LogFilePath = "C:\Scripts\BackupLog.txt" # Путь к файлу лога
$RetentionDays = 180 # Сколько дней хранить бэкапы
# =============================================

# Функция для записи в лог
function Write-Log {
param ([string]$Message)
$TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogEntry = "[$TimeStamp] $Message"
Add-Content -Path $LogFilePath -Value $LogEntry
Write-Host $LogEntry
}

# Проверка прав администратора
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Log "ОШИБКА: Скрипт должен быть запущен от имени администратора!"
exit 1
}

# Проверка существования модуля Hyper-V
if (-not (Get-Module -ListAvailable -Name Hyper-V)) {
Write-Log "ОШИБКА: Модуль Hyper-V не найден. Убедитесь, что роль установлена."
exit 1
}

# Проверка пути бэкапа
if (-not (Test-Path -Path $BackupRootPath)) {
try {
New-Item -ItemType Directory -Path $BackupRootPath -Force | Out-Null
Write-Log "Папка бэкапов создана: $BackupRootPath"
} catch {
Write-Log "ОШИБКА: Не удалось создать папку бэкапов. $_"
exit 1
}
}

$DateStamp = Get-Date -Format "yyyy-MM-dd"
Write-Log "=== Начало задачи бэкапа ==="
Write-Log "Дата бэкапа: $DateStamp"

# Получение списка всех ВМ
$VMs = Get-VM

if ($VMs.Count -eq 0) {
Write-Log "Виртуальные машины не найдены."
} else {
foreach ($VM in $VMs) {
$VMName = $VM.Name
# Формируем имя папки: ИмяВМ_Дата
# Экспорт создаст внутри еще одну папку с именем ВМ, это стандартное поведение Export-VM
$ExportPath = "$BackupRootPath\$($VMName)_$DateStamp"
try {
Write-Log "Начало экспорта ВМ: $VMName"
# Export-VM автоматически создает чекпоинт на время бэкапа для консистентности данных
Export-VM -Name $VMName -Path $ExportPath -ErrorAction Stop
Write-Log "Успешно: ВМ $VMName экспортирована в $ExportPath"
}
catch {
Write-Log "ОШИБКА экспорта ВМ $VMName : $_"
}
}
}

Write-Log "=== Начало очистки старых бэкапов (старше $RetentionDays дней) ==="

# Получаем все папки в корне бэкапа
$BackupFolders = Get-ChildItem -Path $BackupRootPath -Directory

$DeletedCount = 0
foreach ($Folder in $BackupFolders) {
# Проверяем возраст папки по времени создания
if ($Folder.CreationTime -lt (Get-Date).AddDays(-$RetentionDays)) {
try {
Write-Log "Удаление старой папки: $($Folder.Name) (Дата: $($Folder.CreationTime))"
Remove-Item -Path $Folder.FullName -Recurse -Force
$DeletedCount++
}
catch {
Write-Log "ОШИБКА удаления папки $($Folder.Name): $_"
}
}
}

Write-Log "Удалено папок: $DeletedCount"
Write-Log "=== Задача бэкапа завершена ==="
Write-Log "-------------------------------------------"




2. Настройка Планировщика заданий (Task Scheduler)
Чтобы скрипт запускался автоматически в воскресенье в 03:00:
Откройте Планировщик заданий (taskschd.msc).
В меню справа выберите Создать задачу... (не "Создать простую задачу", чтобы были все опции).
Вкладка "Общие":
Имя: Hyper-V Weekly Backup.
Выберите Выполнять для всех пользователей.
Поставьте галочку Выполнять с наивысшими правами (Критично для доступа к Hyper-V!).
Выберите ОС: Windows 10/Server 2016 и выше (под вашу систему).
Вкладка "Триггеры":
Нажмите Создать.
Начало задачи: По расписанию.
Еженедельно.
Дни недели: Воскресенье.
Время: 03:00:00.
Нажмите ОК.
Вкладка "Действия":
Нажмите Создать.
Действие: Запуск программы.
Программа или сценарий: powershell.exe

Добавить аргументы:

text
-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\Backup-HyperV.ps1"

(Убедитесь, что путь к файлу совпадает с тем, где вы сохранили скрипт).
Нажмите ОК.
Вкладка "Условия":
Рекомендуется снять галочку Запускать задачу только при питании от электросети (если это сервер с ИБП, чтобы бэкап не пропустился при кратком перебое).
Снять галочку Запускать только при входе пользователя в сеть (если есть).
Нажмите ОК и введите пароль администратора.
3. Важные замечания и рекомендации
Дисковое пространство:
Бэкап через Export-VM создает полные копии дисков (VHDX).
Формула места: Размер_ВМ * Количество_ВМ * (180 дней / 7 дней).
Пример: Если у вас 5 ВМ по 100 ГБ, то за 180 дней (26 недель) вам понадобится: 5 * 100ГБ * 26 = 13 ТБ.
Убедитесь, что на диске D: достаточно места. Если место ограничено, рассмотрите сокращение срока хранения или использование дедупликации.
Производительность:
Export-VM создает временный чекпоинт (снимок) на работающей ВМ для обеспечения целостности данных. Это может немного замедлить ВМ во время бэкапа.
Время бэкапа зависит от скорости диска и объема данных. Если бэкап не успевает сделать к утру понедельника, это нормально, но следующие задания не должны накладываться (в данном случае они не наложатся, так как раз в неделю).
Тестирование:
Не ждите воскресенья. Запустите скрипт вручную в PowerShell (от имени администратора) один раз, чтобы проверить, что он работает, ВМ экспортируются и лог пишется.
Проверьте, что папки удаляются (можно временно изменить $RetentionDays = 0 для теста, а потом вернуть 180).
Восстановление:
Для восстановления используйте команду:
Import-VM -Path "D:\HyperVBackups\VMName_2023-10-29\VMName\Virtual Machines\GUID.xml"
Или через диспетчер Hyper-V -> Импорт виртуальной машины.
Уведомления:
В данном скрипте уведомления только в лог-файл. Если нужно получать письмо об ошибке на Email, потребуется дополнительная настройка SMTP в скрипте (командлет Send-MailMessage).



скрипт PowerShell, который автоматически создаст и настроит задачу в Планировщике заданий для еженедельного бэкапа виртуальных машин Hyper-V.
Инструкция по использованию
Сохраните скрипт бэкапа:
Убедитесь, что основной скрипт бэкапа (из предыдущего ответа) сохранен по пути:
C:\Scripts\Backup-HyperV.ps1
(Если путь другой, измените переменную $ScriptPath в скрипте ниже).
Создайте скрипт настройки:
Создайте файл C:\Scripts\Setup-BackupTask.ps1 и вставьте в него код ниже.
Запустите от имени Администратора:
Откройте PowerShell от имени администратора и выполните:

powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
C:\Scripts\Setup-BackupTask.ps1

Скрипт создания задачи (Setup-BackupTask.ps1)
powershell
# ==============================================================================
# Скрипт создания задачи Планировщика для бэкапа Hyper-V
# Запускать СТРОГО от имени Администратора
# ==============================================================================

# --- НАСТРОЙКИ ---
$TaskName = "Hyper-V Weekly Backup"
$TaskPath = "\"
$ScriptPath = "C:\Scripts\Backup-HyperV.ps1" # Путь к скрипту бэкапа
$LogPath = "C:\Scripts\TaskCreation.log"
$RunAsUser = "SYSTEM" # Запуск от системы (надежнее для серверов)
# -----------------

function Write-Log {
param ([string]$Message)
$TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$LogEntry = "[$TimeStamp] $Message"
Add-Content -Path $LogPath -Value $LogEntry
Write-Host $LogEntry -ForegroundColor Cyan
}

Write-Log "=== Начало настройки задачи планировщика ==="

# 1. Проверка прав администратора
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Log "ОШИБКА: Скрипт должен быть запущен от имени администратора!"
exit 1
}

# 2. Проверка существования скрипта бэкапа
if (-not (Test-Path -Path $ScriptPath)) {
Write-Log "ОШИБКА: Скрипт бэкапа не найден по пути: $ScriptPath"
Write-Log "Пожалуйста, создайте скрипт бэкапа перед запуском этой настройки."
exit 1
}

# 3. Проверка модуля Планировщика
try {
$ScheduleService = New-Object -ComObject "Schedule.Service"
$ScheduleService.Connect()
Write-Log "Подключение к службе Планировщика заданий успешно."
} catch {
Write-Log "ОШИБКА: Не удалось подключиться к службе Планировщика. $_"
exit 1
}

# 4. Удаление старой задачи (если существует), чтобы пересоздать её чистой
$RootFolder = $ScheduleService.GetFolder($TaskPath)
try {
$OldTask = $RootFolder.GetTask($TaskName)
if ($OldTask) {
Write-Log "Обнаружена существующая задача '$TaskName'. Удаление..."
$RootFolder.DeleteTask($TaskName, 0)
Start-Sleep -Seconds 1
}
} catch {
# Задачи нет, это нормально
}

# 5. Создание новой задачи
Write-Log "Создание новой задачи '$TaskName'..."
$TaskDefinition = $ScheduleService.NewTask(0)

# --- Настройка принципов (Principals) ---
$TaskDefinition.Principal.UserId = $RunAsUser
$TaskDefinition.Principal.RunLevel = 1 # Highest (Наивысшие права)
$TaskDefinition.Principal.LogonType = 3 # S4U (Запуск без входа пользователя)
Write-Log "Настроено: Запуск от $RunAsUser с наивысшими правами."

# --- Настройка триггера (Triggers) ---
$Trigger = $TaskDefinition.Triggers.Create(1) # 1 = Weekly (Еженедельно)
$Trigger.StartBoundary = (Get-Date).Date.AddHours(3).ToString("yyyy-MM-ddTHH:mm:ss") # Сегодня в 3:00 (для инициализации)
$Trigger.DaysOfWeek = 64 # 64 = Sunday (Воскресенье)
$Trigger.WeeksInterval = 1
$Trigger.Enabled = $true
Write-Log "Настроено: Запуск каждое Воскресенье в 03:00."

# --- Настройка действия (Actions) ---
$Action = $TaskDefinition.Actions.Create(0) # 0 = Executable
$Action.Path = "powershell.exe"
# Аргументы: Bypass (обход политик), Hidden (скрытое окно), File (путь к скрипту)
$Action.Arguments = "-ExecutionPolicy Bypass -WindowStyle Hidden -File `"$ScriptPath`""
$Action.WorkingDirectory = "C:\Scripts"
Write-Log "Настроено: Запуск PowerShell скрипта $ScriptPath"

# --- Настройка условий (Settings) ---
$TaskDefinition.Settings.AllowHardTerminate = $true
$TaskDefinition.Settings.StartWhenAvailable = $true
$TaskDefinition.Settings.StopIfGoingOnBatteries = $false # Не останавливать при питании от батарей (важно для ИБП)
$TaskDefinition.Settings.IdleSettings.StopOnIdleEnd = $false
$TaskDefinition.Settings.ExecutionTimeLimit = "PT12H" # Лимит выполнения 12 часов
Write-Log "Настроено: Отключена остановка при работе от батарей, лимит времени 12ч."

# --- Регистрация задачи ---
try {
# 6 = Create or Update
$RootFolder.RegisterTaskDefinition($TaskName, $TaskDefinition, 6, $RunAsUser, $null, 3)
Write-Log "УСПЕШНО: Задача '$TaskName' создана и зарегистрирована."
} catch {
Write-Log "ОШИБКА при регистрации задачи: $_"
exit 1
}

# 6. Проверка и запуск теста (опционально)
Write-Log "Проверка статуса задачи..."
try {
$CreatedTask = $RootFolder.GetTask($TaskName)
Write-Log "Статус задачи: $($CreatedTask.State)"
# Предложение запустить тестовый бэкап сразу
Write-Host "`nХотите запустить тестовое выполнение задачи прямо сейчас? (Y/N)" -ForegroundColor Yellow
$response = Read-Host
if ($response -eq 'Y' -or $response -eq 'y') {
Write-Log "Запуск задачи на выполнение..."
$CreatedTask.Run("")
Write-Log "Задача запущена. Проверьте логи бэкапа через несколько минут."
} else {
Write-Log "Тестовый запуск пропущен. Задача начнёт работать в ближайшее воскресенье в 03:00."
}
} catch {
Write-Log "Не удалось получить доступ к созданной задаче: $_"
}

Write-Log "=== Настройка завершена ==="



Что делает этот скрипт:
Проверяет права: Убеждается, что вы запустили консоль от имени Администратора.
Очищает старое: Если задача с таким именем уже существует, она удаляется и создается заново (чтобы избежать конфликтов настроек).
Настраивает безопасность:
Запуск от имени SYSTEM (наиболее надежно для серверных задач).
Уровень прав: Наивысшие.
Тип входа: S4U (задача работает, даже если никто не залогинен в сервер).
Настраивает расписание: Каждое воскресенье в 03:00 ночи.
Настраивает питание: Запрещает остановку задачи, если сервер работает от ИБП (важно для длительных бэкапов).
Тест: После создания скрипт спросит, хотите ли вы запустить бэкап прямо сейчас для проверки.
Как проверить результат:
Откройте Планировщик заданий (taskschd.msc).
Найдите в списке задачу Hyper-V Weekly Backup.
Нажмите правой кнопкой -> Свойства.
Убедитесь, что на вкладке "Общие" стоит галочка "Выполнять с наивысшими правами".
Посмотрите вкладку "Журнал" (включите её, если отключена), чтобы видеть историю запусков.
    (1-1/1)