Скрипт резервного копирования файлов ubuntu. Пример скрипта для создания резервной копии MySQL. Сохранение данных на удаленном компьютере

Обновлено: 21.07.2017 Опубликовано: 15.08.2016

Данный скрипт написан на Unix Shell под управлением операционной системы CentOS . Он будет работать на большинстве систем семейств Linux и BSD.

Пример скрипта

Скрипт будет создавать для каждой базы свой дамп. Это необходимо для быстрого восстановления данных.

  1. #!/bin/bash
  2. PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
  3. destination="/backup/mysql"
  4. userDB="backup"
  5. passwordDB="backup"
  6. fdate=`date +%Y-%m-%d`
  7. find $destination -type d \(-name "*-1[^5]" -o -name "*-?" \) -ctime +30 -exec rm -R {} \; 2>&1
  8. find $destination -type d -name "*-*" -ctime +180 -exec rm -R {} \; 2>&1
  9. mkdir $destination/$fdate 2>&1
  10. for dbname in `echo show databases | mysql -u$userDB -p$passwordDB | grep -v Database`; do
  11. case $dbname in
  12. information_schema)
  13. continue ;;
  14. mysql)
  15. continue ;;
  16. performance_schema)
  17. continue ;;
  18. test)
  19. continue ;;
  20. *) mysqldump --databases --skip-comments -u$userDB -p$passwordDB $dbname | gzip > $destination/$fdate/$dbname.sql.gz ;;
  21. done;

Описание скрипта

1 Указываем на путь к интерпретатору.
2 Задаем системные переменные, чтобы не пришлось в скрипте прописывать полные пути до исполняемых файлов.
4 - 7 Задаем переменные.
4 Каталог, в котором будем сохранять резервные копии.
5 Учетная запись для подключения к базе данных.
6 Пароль для подключения к базе данных.
7 Дата, когда запускается скрипт.
9 Находим все резервные копии, которые старше 30 дней и удаляем их. Оставаляем для архива файлы на 15 число.
10 Удаляем все резервные копии старше 180 дней.
11 Создаем каталог, в который будем сохранять резервные копии. В качестве имени каталога используем дату запуска скрипта в формате ГГГГ-MM-ДД.
13 - 25 Подключаемся к базе данных и вытаскиваем список всех баз данных. Для каждой делаем резервную копию.
15 - 22 Пропускаем служебные базы information_schema, mysql, performance_schema, test.
23 Делаем резервную копию для баз.

Подготовка системы

Подключаемся к базе данных и создаем учетную запись с правом на создание резервных копий:

> GRANT SELECT, SHOW VIEW, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER, LOCK TABLES ON *.* TO backup@localhost IDENTIFIED BY "backup";

* в данном примере мы создаем учетную запись backup с паролем backup .

Создаем каталог, в котором будут храниться резервные копии:

mkdir -p /backup/mysql

Сохранение данных на удаленном компьютере

Резервные копии необходимо создавать на удаленном компьютере или внешнем диске, чтобы они были доступны при выходе из строя сервера. В данном примере используется общая папка на удаленном сервере, в которой будут размещаться файлы с backup.

Чтобы упростить процесс монтирования сетевой папки, откроем на редактирование следующий файл:

и добавим в него следующую строчку:

//192.168.0.1/backup /mnt cifs user,rw,noauto,credentials=/root/.smbclient 0 0

* в данном примере выполняется монтирование общей папки backup на сервере с IP-адресом 192.168.0.1 в каталог /mnt . В качестве сетевой файловой системы используется cifs (протокол SMB: сервер samba или общая папка Windows). Параметры для подключения — user : позволяет выполнить монтирование любому пользователю, rw : с правом на чтение и запись, noauto : не монтировать автоматически при старте системы, credentials : файл, в котором написаны логин и пароль для подключения к общей папке.

Теперь создадим файл с логином и паролем:

# vi /root/.smbclient

и приведем его к следующему виду:

username=backup
password=backup

* username : имя пользователя, password : пароль. Само собой, в вашем случае указываются свои данные.

Теперь введите следующую команду.

Бэкап важной информации - каждый системный администратор сталкивается с такой задачей. Задача казалось бы тривиальная и у многих читателей интереса не вызовет. Но, например, мне бы такая статья в определенный момент помогла бы весьма сильно, поэтому считаю, что этой статье быть.

Задача: Бэкап данных в локальную директорию и на отдельный сервер, с использованием минимума стороннего ПО, логированием и оповещением администратора в jabber при сбоях. Все основные функции большинства ПО для автоматического бэкапа, но без установки оного, а следовательно без его багов (что, собственно, и привело к подобной идее).

А теперь к делу.

Для начала создадим и откроем скрипт
nano backup-script
Теперь в скрипте добавим строку
#!/bin/bash
Объявим некоторые переменные.
TN - TASKNAME - имя задания.Используется для вывода в лог и определения названия файла.
Так как заданий несколько (ежемесячное, еженедельное, ежедневное) и писать на каждый случай скрипт было лень, я создал универсальный, в котором надо просто раскомментить нужные строки. Наименование заданий писать надо без пробелов, желательно в латинице, если не хотите проблем с кодировкой и неправильными параметрами команд.
TN=docs-monthly
#TN=docs-weekly
#TN=docs-daily
OF - Output File - имя выходного файла. Получается из переменной TN, то есть имени задания.
OF=$TN.tar.gz
Объявляем переменную с путем к файлу лога, и далее все сообщения об ошибках и остальном будем выводить в лог.
LOGFILE=/var/log/backup.log
Сделаем запись в лог о начале бэкапа (дата, время, имя задания)
echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE
Есть проблема в том что если указывать в параметрах команд (напр. tar) имена каталогов с пробелами, скрипт срабатывает с ошибкой. Решение найдено на просторах интернета - операционная система linux использует пробел в качестве стандартного разделителя параметров команды. Переопределим стандартный разделитель (хранится в переменной $IFS) отличным от пробела, например \n – знаком переноса строки.
Запоминаем старое значение стандартного разделителя
OLD_IFS=$IFS
Заменяем стандартный разделитель своим
IFS=$"\n"
SRCD - SouRCe Directory - каталог с данными для бэкапа
Теперь можно перечислять несколько каталогов, разделителем будет перенос строк как мы сами указали строкой выше
SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N"
TGTD - TarGeT Directory - каталог в который будут складываться бэкапы
TGTD="/var/backups/"
Естественно мы понимаем что хранить важные бэкапы только на источнике как минимум легкомысленно. Поэтому оставим копию и на удаленном ресурсе, который будем отдельно монтировать с помощью mount и fstab. Сразу поясню почему я использовал mount и fstab, а не один mount - я монтирую этот каталог и в других своих скриптах, а как сказал один из знакомых программистов - хороший программист не будет писать один и тот же код дважды (как-то так, дословно не помню, но надеюсь смысл донес).
TGTD2="/mnt/archive/"
Сам процесс архивирования в варианте "Создать новый архив"
tar -czf $TGTD$OF $SRCD &>>$LOGFILE
и в варианте "Обновить файлы в старом архиве"
tar -u -f $TGTD$OF $SRCD &>>$LOGFILE
Во втором случае лучше вместо $OF использовать конктретное имя файла потому что у меня например ежедневно апдэйтится еженедельный архив, а их $TN (имена задания) не совпадают, соответственно и $OF.

В переменной "?" ханится статус выполнения последней команды. Сохраним его, чтобы воспользоваться позже.
STATUS=$?
Возвращаем стандартный разделитель к исходному значению
IFS=$OLD_IFS
Теперь добавим условие - если процесс упаковки в архив tar закончился с ошибкой, отправляем сообщение админу, удаляем неудачный файл бекапа. Иначе продолжаем дальше - монтируем сетевую шару и кидаем в нее копию архива. После каждой операции проверяем результат выполнения, пишем логи, и либо продолжаем, либо извещаем админа и прерываем процедуру.
if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi exit

В процессе мы копируем архив из локального хванилища в удаленное. Естественно, проверяем, что каждая операция успешно завершена, и пишем все в логи.
Для отсылки сообщения администратору я использую XMPP сообщение, так как в организации поднят Jabber-сервер, и я больше люблю получить быстрое сообщение о сбое, чем лезть в почту, вбивая пароли, тыкая на ссылки, и ожидая пока браузер мне все отобразит. В любом случае никто не мешает вам использовать sendmail вместо sendxmpp.
Файл /usr/local/etc/XMPP_settings следующего содержания:

#логин_отправителя@домен;IP_jabber_сервера:порт_jabber_сервера пароль_отправителя login@domen;127.0.0.1:5222 password
В файле fstab строка описывающая подключение шары Windows
//192.168.0.250/arhiv /mnt/archive cifs noauto,rw,iocharset=utf8,cp866,file_mod=0666,dir_mod=0777,noexec,_netdev,credentials=/root/.passwd_to_archive_directory 0 0
Теперь осталось только добавить задание в cron. Это можно сделать с помощью файла /etc/crontab, но я, в силу привычки к GUI, оставшейся в наследство от виндовс, пользую вэб-интерфейсы для таких случаев. Команда должна выполняться с правами рута, то бишь, к примеру, sudo bash backup_script. Добавляя команду в cron можно определить что она будет сразу выполняться от имени root`а

В ходе обсуждений затронули проблему разрастания логов. Пошел по простейшему (на мой взгляд) пути: будем хранить только последние N строк лога, например 300. В скрипт добавятся две строки, в которых мы сохраним последние 300 строк лога во временный файл, потом затрем им лог
tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE
Приведу полный текст скрипта:
#!/bin/bash TN=docs-monthly #TN=docs-weekly #TN=docs-daily OF=$TN.tar.gz LOGFILE=/var/log/backup.log echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE OLD_IFS=$IFS IFS=$"\n" SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N" TGTD="/var/backups/" TGTD2="/mnt/archive/" tar -czf $TGTD$OF $SRCD &>>$LOGFILE #tar -u -f $TGTD$OF $SRCD &>>$LOGFILE STATUS=$? IFS=$OLD_IFS if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE exit

Всем спасибо за внимание!

Резервное копирование должно быть таким, чтобы Вы в любой момент могли сменить хостера и переехать на новый сервер. Поэтому весь процесс создания архивов должен быть автоматизирован. А файлы бэкапов должны лежать в надежном месте с возможностью круглосуточного доступа из любой точки планеты.

Публикую очередное решение по резервному копированию вебсервера. Этот bash скрипт создает единый архив базы данных и всех файлов сайта. Для удобства на диске локально хранится 30 последних резервных копий. А для надежности архивы резервных копий выкладываются на облачное хранилище Яндекс.Диск .
Подобных решений полно в сети. Но данный скрипт наиболее полно отражает мое видение резервного копирования web-серверов.

Основные принципы резервного копирования

Архивы делаем встроенными средствами операционной системы, чтобы облегчить процесс создания архива и ускорить восстановление сайта на новом сервере при необходимости.
Используем форматы архивом, которые позволяют сохранить все атрибуты файлов и папок. Чтобы получить точную копию сайта на новом месте.
Отдельно архивируем со сжатием базу данных и директорию веб-сервера со всеми файлами. А потом объединяем в единый архив уже без сжатия. Имя архива для удобства формируем на основании имени домена и даты его создания.
Организуем локальное хранилище из 30-ти последний архивных копий. Чтобы была возможность «откатить» сайт в предыдущее состояние на случай непредвиденных ситуаций. К примеру при заражения вирусами. Или неудачном обновлении CMS.
Организуем независимое хранилище резервных копий в облачном хранилище Яндекс.Диск и выкладываем туда наши архивы.

BASH скрипт резервного копирования файлов сайта и базы данных MySQL

#!/bin/bash # #ver 1.0 #2013-09-09 # #Переменные Базы данных DBHOST="localhost" #Адрес MySQL сервера DBUSER="bd_user" #Имя пользователя базы данных DBPASS="dBpAsS" #Пароль пользователя базы данных DBNAME="db_name" #Имя базы данных DBARC=$DBNAME.sql.gz #Имя архива базы данных # #Переменные WEBDAV WEBDAVURL="https://webdav.yandex.ru/backup/" #Адрес Яндекс.Диск. Папка должна существовать! WEBDAVUSER="[email protected]" #Имя пользователя от Яндекс.Диска (Яндекс.Почты) WEBDAVPASS="MyPasWordAtYandexMail" #Пароль от Яндекс.Диска # #Переменные сайта SCRIPTDIR="/home/serveruser/backup/" #Абсолютный путь откуда запускается скрипт и где храняться архивы SCRDIR="/home/serveruser/web/mydomain.com/public_html/" #Абсолютный путь к сайту от корня диска SCREXCLUDE="webstat" #Что не попадет в архив SCRARC="public_html.tar.gz" #Имя архива файлов сайта # #Переменные Резерных копий ARCNAME="mydomain.com"=$(date "+%F(%H:%M)")".tar" #Имя архивной копии сайта ARCMAX="30" #Количество файлов в локальном хранилище # #Переходим в корневую директорию вебсервера cd $SCRDIR # #Создаем файловый архив со сжатием, учитываем исключения tar cfz $SCRIPTDIR$SCRARC --exclude=$SCREXCLUDE * # #Возвращаемся в папку со скриптом, где лежат все архивы cd $SCRIPTDIR # #Архивируем базу данных со сжатием mysqldump -h$DBHOST -u$DBUSER -p$DBPASS $DBNAME | gzip > $DBARC # #Объединяем файловый архив и дамп базы данных, теперь уже без сжатия tar cf $SCRIPTDIR$ARCNAME $SCRARC $DBARC # #Отправляем результат в Яндекс.Диск curl --user $WEBDAVUSER:$WEBDAVPASS -T $ARCNAME $WEBDAVURL # #Убираем промежуточные архивы rm *.gz # #Удаляем старые копии сайта, оставляем несколько свежих копий ls -t *.tar | tail -n+$ARCMAX | xargs rm -f

Теперь разберем скрипт по полочкам. С переменными указанными в начале скрипта все понятно. Я постарался максимально отделить мух от котлет и все необходимое прокомментировал.
Перейдем к исполняемой части скрипта.

Как создать архив файлов сайта

C созданием архива проблем, как правило, нет. Главное не запутаться с абсолютными и относительными путями. Чтобы быть уверенными, что вы архивируете и где сохраняете.
Чтобы избежать полных абсолютных путей в архиве предварительно перейдем в корневую директорию сайта.

Я так не люблю, раскрываешь архив, а там папка home , заходишь в нее, а там еще одна, ты в нее, за ней следующая и так далее, короче матрешка. Замучаешься до содержимого добираться.
Поэтому перед созданием архива выполним команду:

Cd $SCRDIR

Тогда в архиве будет сразу содержимое корневой директории сайта безо всяких папок и подпапок. Примерно так:


Если у Вас есть файлы, которым не обязательно быть в резервной копии сайта, у меня это папка webstat , тогда необходимо настроить параметр —exclude.

Подробнее о всех параметрах tar можно почитать в официальном мануале .

Как создать резервную копию базы данных MySQL

Для получения дампа базы данных нам понадобятся параметры доступа к ней. Все они описаны в переменных скрипта и не должны вызвать затруднений. Для уменьшения размера файла сжимаем вывод утилиты mysqldump . Я использую gzip , который в *NIX-ах присутствует по-умолчанию.
Если у Вас используется старая версия MySQL сервера, до 4.1, то на базах большого объема может пригодиться параметр —quick . Использование которого указывает команде mysqldump сразу писать дамп базы на диск, а не кэшировать его в памяти. В более свежих версиях этот параметр включен по-умолчанию.

Единый файл резервных копий сайта

Чтобы решение было изящным, объединим два архива файлов сайта и дампа базы данных в один архив. Только теперь уже без сжатия, так как каждый из них мы их предварительно пропустили через gzip .
Для удобства имя файла составим из имени используемого домена и времени создания.

Как сохранить резервную копию сайта в Яндекс.Диск

В качестве облачного хранилища совсем не обязательно должен выступать Яндекс.Диск . Вы можете использовать, к примеру, Microsoft SkyDrive или любой другой сервис, использующий для доступа протокол WebDAV.

Как убрать старые копии файлов, сохранив несколько последних

В конце скрипта уберем ненужные файлы, это архивы файлов и базы данных и ограничим количество архивный копий сайта.
Осуществим поиск устаревших резервных копий и при наличии таковых их удалим. За это отвечает нижеследующий код:

Ls -t *.tar | tail -n+$MAXARC | xargs rm -f

Как это работает? По команде ls ищутся архивы (файлы с расширением tar ), вывод формируется по времени создания файла. Далее команда tail фильтрует список вырезая из него 30 первых. А остаток передается команде rm на удаление. Параметр f у нее служит для «молчания» в случае, если нечего удалять. Такое бывает, когда Вы только начали собирать резервные копии и их число не превышает значение переменной $MAXARC .
По совести говоря, после выполнения данной команды в «живых» останется только 29 резервных копий.

Запуск скрипта резервного копирования

Сохраняем скрипт, к примеру backup.sh . И присваиваем ему права на исполнение:

#chmod +x backup.sh

Удобнее всего использовать CRON для запуска скрипта по расписанию. Я создаю резервные копии раз в сутки в часы наименьшей нагрузки, то есть во второй половине ночи под утро.
Не забываем про владельцев папок и файлов, когда будем запускать скрипт на исполнение. Ведь файлы пользователя VASYA будут недоступны, если запустить скрипт от имени пользователя PETYA.

Результаты работы скрипта резервного копирования


Каждый день в 6 утра на сервере создается резервная копия сайта (файлы плюс база данных) и отправляется в облачное хранилище Яндекс.Диск .
При написании статьи в качестве тестовой площадки выступал реальный сервер, на котором работает этот блог. На сервере используется CentOS 6.4 со всеми обновлениями на начало сентября 2013.
Замечания и пожелания по работе скрипта приветствуются. В планах реализовать ограничение по количеству резервных копий не только на сервере, но и в облаке Яндекс.Диск . Пока же накопившееся со временем архивы приходится вычищать вручную.

Способов резервного копирования превеликое множество, но лично для меня они имеют свои минусы из-за которых я не использую их. Проще написать несколько простых скриптов, например, с помощью так называемого bat-ника или PowerShell. В этой статье я расскажу, как можно настроить резервное копирование с помощью скриптов, я их комбинирую и создаю связки.

Схема резервного копирования

В большинстве случаев backup сводится к сохранение неких файл. Это могут образы виртуальных машин, файлы пользователей, бекап базы SQL, выгрузка информационной базы 1С:Предприятие и т.д. Правильнее все эти резервные копии файлов хранить в другом месте, это может быть , сетевая папка, внешний диск, ленточный накопитель, ftp и т.д. Из-за удобства я использую ftp сервер.

Давайте разберем схему как же это все происходит:

  1. Копируем или перемещаем их в папку для отправки в архив
  2. Проверяем папку на наличие в ней новых backup"ов
  3. Отправляем файлы в архив на FTP сервер
  4. Удаляем старые backup файлы

В первом пункте мы создали файлы, которые нам необходимо скопировать на наш FTP сервер. Теперь нам нужно скопировать их в папку, которую в свою очередь отправим на FTP. Для этого можно воспользоваться простой командой:

Copy "ПУТЬ_К_ИСХОДНОЙ_ПАПКЕ\* C:\Backup\

Выполнив эту команды все наши файлы будут скопированы C:\Backup\. Выполнять данную команду имеет смысл, если Вы собираете из разных мест Ваши backup"ы. Теперь нам понадобится скрипт, который будет проверять папку на появление новых файлов и отправлять их на FTP сервер. Создаем пустой файл backup.ps1 и в него записываем следующий скрипт.

$a = (Get-Host).UI.RawUI $a.WindowTitle = "Sync Folder To Ftp" $ftp = "ftp://АДРЕС_FTP_СЕРВЕРА/" $localDirectory = "C:\Backup" $user = "ИМЯ_ПОЛЬЗОВАТЕЛЯ" $pass = "ПАРОЛЬ" $webclient = New-Object System.Net.WebClient $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass) $Files = Get-ChildItem $localDirectory | Where {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} foreach ($File in $Files) { $LocalFile = $File.FullName Write-Host "Getting $File from $localDirectory" -Foreground "Red" $webclient.UploadFile($ftp + $File, $LocalFile) Write-Host "Puting $File to $ftp" -Foreground "Yellow" } Write-Host "Finished Sync to $ftp" -Foreground "Green"

Давайте разберем как же работает данный скрипт. Сначало задаются переменные, в которых указывается сервер, имя пользователя, пароль, исходная папка. Затем в строке $Files = Get-ChildItem $localDirectory | Where {$_.LastWriteTime -gt (Get-Date).AddDays(-1)} делается выборка всех файлов, у которых дата изменения больше (-qt) чем текущая дата минус 1 день. Здесь можете подкорректировать под Ваше расписание. Я резервное копирование делаю каждый день. Затем в цикле мы проходим по каждому файлу, удовлетворяющему условия и отправляем его на FTP сервер.

Дабы не занимать место на диске, я удаляю бекапы старше 30 дней. В принципе, после отправки на FTP их можно тут же удалять, я оставляю их только для того что, если они вдруг понадобятся не пришлось бы тратить время на скачивание их с FTP, да и лишняя копия backup"ов не помешает, мало ли что может случится с FTP. Так что если место Вам позволяет, рекомендую хранить их и на исходном сервере.

Для очистки папки я использую скрипт removeOldBackups.ps1

$fullTargetPath = "C:\Backup" $deleteFiles = Get-Childitem $fullTargetPath -Recurse | Where {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Foreach { Remove-Item $_.FullName -Force -Recurse}

Крайне простой скрипт, поясню только одну строку Where {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | в этой строке сравнивается дата изменения файла с текущей датой минус 30 дней, под это сравнения попадут файлы у которых LastWriteTime меньше текущей даты минус 30 дней. При необходимости можете подправить под Ваши нужды.

И так, краткая выжимка из теоритических знаний, которая нам потребуется:

Выполнять резервное копирование можно на сетевой ресурс или на отдельный том. Копирование на сетевой ресурс имеет пару существенных недостатков: во-первых, при возникновении проблем с сетью (во время выполнения архивирования) ваша резервная копия, очевидно, не будет создана, а, во-вторых, сетевая папка может содержать только одну единственную резервную копию (выполняя резервную копию в ту же сетевую папку, что и раньше, вы уничтожаете предыдущую резервную копию).

Копирование на отдельный том выполняется следующим образом: На целевом томе создается папка WindowsImageBackup\<ComputerName >\. В этой папке в свою очередь будут созданы виртуальные диски (по одному на каждый из бэкапируемых томов), на который и будет производится резервное копирование. По окончании копирования состояние виртуальных дисков, хранящих резервные копии, будет сохранено при помощи службы теневого копирования. При следующем архивировании будут произведены те же самые действия в результате получится, что каждый конкретный архив будет доступен при обращении к конкретной теневой копии. Причем с точки зрения программы архивирования каждый такой архив будет являться полным архивом, а с точки зрения используемого пространства – инкрементальным (теневая копия хранит информацию только об измененных блоках данных).

Информация о выполненном процессе архивирования хранится в нескольких местах ОС, которые, может так случиться, могут содержать рассогласованную информацию. Понятно, что реальное количество резервных копий, которое хранится локально на компьютере, не может быть больше, чем количество теневых копий тома, на который выполнялось резервное копирование. Посмотреть информацию о количестве теневых копий можно, например, в командной строке при помощи команды diskshadow (и ее подкоманд list shadows all ). Однако, теневые копии не содержат достаточное количество информации, необходимой для создания перечня резервных копий, поэтому эта информация берется из других мест. Так, например, ОС ведет учет архивных копий в глобальном каталоге архивов, а так же в журнале событий Windows Server Backup Log. Информация из этих источников отображается оснастке “Система архивации данных Windows Server”. В результате может сложиться такая ситуация, что оснастка будет демонстрировать нам противоречивую информацию, которая не имеет ничего общего с реальностью.

Посмотрите на скриншот. Он был сделан в системе, для которой на локальном диске хранилось всего два архива (существовало только две теневые копии) и не было создано ни одного сетевого архива. Однако, оснастка сообщает нам в разделе “Все архивы” о том, что у нас якобы имеется 6 архивов, а в окне сообщений мы видим отчет о создании только 3х архивов. Для того, чтобы заставить ОС отображать непротиворечивую информацию, соответствующую действительности, нам придется проинициализировать все компоненты системы архивации, которые хранят информацию о резервных копиях или сами резервные копии. Для этого нам нужно будет очистить windows backup log , удалить глобальный каталог архивов (при помощи команды wbadmin delete catalog ) и удалить все теневые копии (при помощи команды diskshadow delete shadows all ). По большому счету информация, хранящаяся в windows backup log, носит чисто информационный характер и никак не влияет на процесс восстановления информации из архива, если таковой потребуется выполнить, чего не скажешь об информации, хранящейся в глобальном каталоге. Если глобальный каталог поврежден, то восстановить информацию при помощи штатных средств архивирования ОС windows у нас не получится. Однако, поврежденный или удаленный глобальный каталог архивов можно восстановить из резервной копии, которая создается при каждом архивировании в папке WindowsImageBackup\<ComputerName >\. Для восстановления поврежденного глобального каталога архивов необходимо его сначала удалить (при помощи команды wbadmin delete catalog) , а затем восстановить из резервной копии (при помощи команды wbadmin restore catalog) .

Ну, а теперь, собственно, опубликую скрипт для резервного копирования:

Write-Verbose "Начали..." #Сохраняем значение переменной окружения $VerbosePreference $tmpVerbpref=$VerbosePreference $VerbosePreference="Continue" #Путь к сетевой папке, в которую будем копировать архив $NetworkBackupPath="\\SRV66\Backup$\SRV02\BMR" #Имя раздела, на котором будем создавать архив $VolumeTarget="D:" # Количество копий бэкапа, которые необходимо сохранить на локальном носителе $BackupQuantity=3 # Количество копий бэкапа, которые необходимо сохранить на сетевом носителе $NetBackupQuantity=5 #Путь к файлу-списку бэкапов $csvFile="D:\Backup\ProfileBackup.csv" #Путь к папке, в котой будем создавать архив 7zip $Path2Arc="D:\Backup" # подключаем оснастку Server Backup Add-PSSnapin Windows.Serverbackup -ErrorAction SilentlyContinue # создаём задание бэкапа $policy = New-WBPolicy <# # создаём и добавляем в задание бэкапа о бэкапируемых файлах $source = New-WBFileSpec -FileSpec "C:\Users" Add-WBFileSpec -Policy $policy -FileSpec $source #> # #Get list of critical volumes $VolSources = Get-WBVolume -CriticalVolumes #Add volumes to be backed up Add-WBVolume -Policy $policy -Volume $VolSources #Define VSS Backup Otions Set-WBVssBackupOptions -policy $policy -VssCopyBackup #Enable SystemState backup Add-WBSystemState -policy $policy #Enable Bare Metal Recovery Add-WBBareMetalRecovery -Policy $policy # # указываем локальный том, на который будет копироваться архив $target = New-WBBackupTarget -VolumePath $VolumeTarget Add-WBBackupTarget -Policy $policy -Target $target Write-Verbose "Начинаем процесс создания backup"а" # выполняем бэкап Start-WBBackup -Policy $policy # проверяем код возврата с результатом выполнения бэкапа if ((Get-WBSummary).LastBackupResultHR -eq 0) { # переименовываем архив в более понятное имя $newname = "_Backup_$(Get-Date -f yyyyMMddHHmm)" Write-Verbose "Переименовываем папку с только что созданным архивом в $newname ..." Ren $VolumeTarget\WindowsImageBackup -NewName $newname # Запаковываем архив при помощи 7zip $arc="C:\Program Files\7-Zip\7z.exe" $arc_params="a -t7z -m0=LZMA2 -mmt -mx9" $arc_source="$VolumeTarget\$newname" $arc_dest="$Path2Arc\$newname.7z" Write-Verbose "Запаковываем папку $newname при помощи 7zip в $newname.7z" Start-Process $arc -ArgumentList "$arc_params $arc_dest $arc_source" -Wait # копируем архив в сетевую папку #copy $VolumeTarget\$newname $NetworkBackupPath -Recurse Write-Verbose "Копируем файл $arc_dest в сетевую папку..." copy "$arc_dest" $NetworkBackupPath if ($?) { #если копирование прошло без ошибок, удаляем файл-архива и папку, которая была запакована в этот архив del "$arc_dest" -Force -Verbose del $VolumeTarget\$newname -Recurse -Force #-Verbose } # удаляем старые архивы из сетевой папки, за исключением последних $BackupQuantity архивов $NetBackups=dir $NetworkBackupPath | ?{$_.Name -match "_.+(\d)+\.7z$"} $NetBackupsCount=$NetBackups.count if (($NetBackupsCount - $NetBackupQuantity) -gt 0) { $NetBackups | sort lastwritetime | select -First ($NetBackupsCount - $NetBackupQuantity) | del -Force -Verbose #-Recurse -WhatIf } # читаем наш собственный каталог бэкапов $csv=@() if (Test-Path $csvFile) {$csv = @(Import-Csv $csvFile)} # считываем данные о последнем бэкапе $current = Get-WBBackupSet | select -Last 1 | select VersionID, SnapshotId # и добавляем его в массив объектов действующих бэкапов $csv += $current # чтобы не было путаницы, снова сортируем объекты и пишем обратно в CSV файл $csv | sort @{Expression={($_.VersionId)}}| select -Last $BackupQuantity | Export-Csv $csvFile -NoTypeInformation # и считаем сколько там записей $count = $csv.count # если записей больше BackupQuantity, то считаем сколько лишних архивов нужно удалить. # если меньше BackupQuantity записей, то ничего удалять не надо и просто добавляем новую запись if ($count -gt $BackupQuantity) { $old = $count - $BackupQuantity # генерируем случайное имя для скрипта, который будет использоваться в diskshadow $file = ::GetRandomFileName() # выбираем все лишние архивы и пропускаем их по конвейеру на удаление $csv | sort @{Expression={($_.VersionId)}}| select -First $old | %{ #Read-Host "Press Enter to continue..." | Out-Null #Write-Verbose $file ##Read-Host "Press Enter to continue..." | Out-Null # записываем команду во временный файл "delete shadows ID {$($_.SnapshotID)}"|Out-File -FilePath $Env:TEMP\$file -Encoding OEM #gc $Env:TEMP\$file #Read-Host "Press Enter to continue..." | Out-Null # и запускаем diskshadow в режиме скрипта diskshadow /s $Env:TEMP\$file | Out-Default } del $Env:TEMP\$file } } else { # ругаемся, что бэкап не был завершён успешно Write-Verbose "Ошибка выполнения бэкапа" } Write-Verbose "Скрипт закончил работу" #Восстанавливаем значение переменной окружения $VerbosePreference $VerbosePreference=$tmpVerbpref