Архивация файлов базы данных — Hey, Scripting Guy! Blog

Этот пост также как и предыдущие использует встроенный класс WMI _InstanceModificationEvent. Используемый здесь запрос может оказаться очень полезным в некоторых случаях, также как и сам подход к решению проблемы. Описываемый метод может использоваться при решении определенных задач, когда другие варианты решения могут оказаться излишне трудоемкими. Этот скрипт можно несколько упростить, воспользовавшись преимуществами Windows PowerShell 2.0, так как он был написан для Windows PowerShell 1.0, однако он по прежнему может использоваться.

Вопрос: У меня есть проблема. Я хочу написать скрипт для архивации каталога, содержащего файлы базы данных, используемой одним из наших приложений. Проблема в том, что когда база данных в активном состоянии — файлы, естественно, заблокированы. Я нашел службу, которая работает с базой данных. Но когда я пытаюсь остановить эту службу при помощи WMI, копирования файлов все равно не происходит, потому как остановка служба базы данных может занять продолжительное время.

Я решил использовать командлет Start-Sleep и иногда это помогает. Однако проблема в том, что иногда служба прекращает свою работу быстро, а иногда на это уходит некоторое количество времени. Я полагаю, что это зависит от того, насколько было загружено приложение перед тем как я дал команду на остановку службы. Я мог бы добавить в скрипт несколько попыток копирования базы данных, и после каждой неудачной добавлять ко времени ожидания 10 процентов, однако это все приведет к излишним затратам времени в тех случаях, когда служба останавливается практически сразу. Можете ли вы что-то посоветовать в данном случае?

Ответ: Как вы сами видите, попытка определить время, необходимое для завершения работы службы может быть проблематичной даже при идеальных условиях. Это зависит от того, чем занят сервер в этот конкретный момент, загрузки его процессора, памяти или жестких дисков. Кроме того, при завершении работы чего-либо происходит множество разных вещей. Раньше я обычно добавлял команду паузы в текст скрипта и надеялся на лучшее. Но однажды мне пришла в голову идея использовать события WMI для решения этой проблемы.

Скрипт StopServiceMonitor.ps1 представляет собой пример использования событий WMI для определения необходимого промежутка времени перед тем как запустить следующую команду. Скрипт дает команду остановки службы, а затем создает монитор событий WMI для определения когда именно служба остановится. После того, как служба действительно остановилась, вы можете приступить к копированию файлов базы данных или к чему бы то ни было еще.

Текст скрипта:

Clear-Host
$computer = «localhost»
$dte = get-date
$ServiceName = «‘AdobeActiveFileMonitor6.0′»
$Query = «select * from __instanceModificationEvent within 5 where
targetInstance isa ‘win32_Service’ AND targetInstance.name = $ServiceName»

Write-Host «Waiting for $ServiceName to be terminated …
You will be notified within 5 seconds of service termination
start time was $dte»

$WMI=Get-WmiObject -Class Win32_Service -computername $computer `
-filter «name=$Servicename»

if($WMI.acceptstop)
{
$Eventwatcher = New-Object management.managementEventWatcher $Query
$rtn=$WMI.stopservice()
«Stopping $ServiceName returned $($rtn.ReturnValue)»
$Event = $Eventwatcher.waitForNextEvent()
$Event.targetInstance |
Format-List -property [a-z]*
}
ELSE
{
«$ServiceName unable to accept stop command»
exit
}

Первое, что мы делаем — это очищаем экран консоли при помощи командлета Clear-Host.

Clear-Host

Теперь нам нужно инициализировать пару переменных. Переменная $Computer будет содержать имя компьютера, остановку службы которого мы собираемся отслеживать. В переменной $dte мы сохраним текущие дату и время, а в переменной $ServiceName будет находиться имя останавливаемой службы.

$computer = «localhost»
$dte = get-date
$ServiceName = «‘AdobeActiveFileMonitor6.0′»

Теперь нам нужно создать запрос WMI. В этом скрипте мы будем запрашивать класс __instanceModificationEvent. Этот класс позволит нам отслеживать события изменения чего-либо. Недавно мы использовали класс __instanceDeletionEvent для отслеживания события прекращения работы процесса и __instanceCreationEvent для отслеживания события создания процесса. Разница заключается в том, что в этом случае наблюдаемый процесс не создается и не удаляется — происходит лишь изменение его статуса («Работает»/»Остановлена»). Это небольшое отличие, однако, оказывает серьезное влияние на то, как будет работать ваш скрипт.

Еще одно изменение по сравнению с предыдущими скриптами — это то, что здесь мы будем использовать составной запрос. В этом скрипте мы, конечно, будем отслеживать изменения в состоянии служб, однако нас интересует изменение статуса только одного определенного экземпляра службы. Того, чье имя задано в переменной $ServiceName. TargetInstance — это объект, создаваемый в момент регистрации события и он содержит копию объекта, статус которого этим событием и был изменен. Это дает нам возможность использовать любое свойство отслеживаемого объекта.

Текст запроса WMI:

$Query = «select * from __instanceModificationEvent within 5 where
targetInstance isa ‘win32_Service’ AND targetInstance.name = $ServiceName»

После того, как мы присвоили текст запроса переменной $Query, мы выведем сообщение с целью проинформировать пользователя о том, чем скрипт собирается заниматься. Для этого мы используем командлет Write-Host.

Write-Host «Waiting for $ServiceName to be terminated …
You will be notified within 5 seconds of service termination
start time was $dte»

Далее мы выполняем обычный запрос WMI. А делаем мы это для того, чтобы определить, поддерживает ли интересующая нас служба команду остановки. Можно считать это одним из способов избежать ошибки. Мы используем командлет Get-WMIObject. В качестве запрашиваемого класса мы указываем Win32_Service. Кроме того мы задаем имя компьютера, содержащееся в переменной $computer. Также мы используем параметр -filter для того, чтобы ограничить результаты только службой, имя которой задано в переменной $ServiceName.

$WMI=Get-WmiObject -Class Win32_Service -computername $computer `
-filter «name=$Servicename»

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

if($WMI.acceptstop)

Если проверка условия проходит успешно, мы создаем экземпляр класса .NET Framework ManagementEventWatcher. Этот класс находится в пространстве имен System.Management. В качестве аргумента мы передаем текст запроса, содержащийся в переменной $query. Полученный объект мы сохраним в переменной $EventWatcher.

{
$Eventwatcher = New-Object management.managementEventWatcher $Query

После создания объекта ManagementEventWatcher мы приступим к остановке службы. Для этого мы вызовем метод stopService объекта службы, сохраненного в переменной $WMI. Возвращенный методом результат выполнения мы сохраним в переменной $rtn.

$rtn=$WMI.stopservice()

Далее мы отобразим на экране полученный в предыдущем выражении код возрата. Для того, чтобы вывести значение свойства ReturnValue, а не всего содержимого переменной $rtn, нам придется воспользоваться подвыражением.

«Stopping $ServiceName returned $($rtn.ReturnValue)»

Теперь, используя объект ManagementEventWatcher, сохраненный в переменной $EventWatcher, мы будем ожидать интересующего нас события. Для этого мы воспользуемся методом waitForNextEvent. Результат выполнения метода мы сохраним в переменной $Event.

Стоит упомянуть, что этот скрипт создан для работы со службами, запуск и остановка которых требует некоторого времени. Если вы решите применить этот скрипт для отслеживания службы с быстрым запуском или завершением, вы можете пропустить это событие.

$Event = $Eventwatcher.waitForNextEvent()

В этой части скрипта, вы можете задать любое нужное вам действие. Вы можете запустить резервное копирование сервера или просто скопировать файлы, которые были заблокированы службой. В этом скрипте мы просто выведем все свойства измененного объекта службы. Для этого мы получим значение свойства targetInstance объекта ManagementObject, полученного в результате выполнения метода waitForNextEvent, и передадим его командлету Format-List. Мы отобразим только те свойства, имя которых начинается с букв от a до z, что позволит нам отфильтровать системные свойства, имя которых начинается с двух символов подчеркивания.

$Event.targetInstance |
Format-List -property [a-z]*
}

После запуска скрипта, вы увидите вывод, похожий на приведенный на рисунке:

01

Если служба не поддерживает команду остановки, скрипт выводит сообщение и завершает работу.

ELSE
{
«$ServiceName unable to accept stop command»
exit
}

Авторы: Ed Wilson and Craig Liebendorfer, Scripting Guys
Оригинал: http://blogs.technet.com/b/heyscriptingguy/archive/2009/01/21/how-can-i-back-up-a-database-s-data-folder-while-the-database-is-running.aspx


Страницы в социальных сетях:

Twitter: https://twitter.com/vsseth
Facebook: https://fb.com/inpowershell
VKontakte: https://vk.com/inpowershell


Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s