Скрипт 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. Нажмите правой кнопкой -> Свойства. Убедитесь, что на вкладке "Общие" стоит галочка "Выполнять с наивысшими правами". Посмотрите вкладку "Журнал" (включите её, если отключена), чтобы видеть историю запусков.