Показать ошибку для задания SQL 2005, которое выполняет сценарий Powershell через приглашение CMD, если сценарий PS сбой - PullRequest
2 голосов
/ 29 сентября 2010

У меня есть экземпляр SQL 2005, который выполняет задание, использующее сценарий Powershell для переименования текущего файла резервной копии журнала TX, добавив к нему «-PrevDay» (впоследствии удалив резервную копию, уже названную «XXX-PrevDay.bak»). если он существует), а затем запустите полное резервное копирование БД и резервное копирование журнала TX, если БД не находится в простом режиме.

Задание агента SQL Server запускает сценарий Powershell через CMD на каждом этапе задания, а сценарий powershell запускает резервную копию sql с помощью командлета Invoke-SQLCmd. Это прекрасно работает, если резервное копирование не выполнено, потому что задание SQL по-прежнему отображается как «Успешное». Это связано с тем, что задание SQL, которое запускает сценарий Powershell через приглашение CMD, заботится только о том, запускается ли сценарий Powershell ... а не о том, действительно ли команды IN в сценарии выполняются или не выполняются.

Возможно ли, используя перехват ошибок в powershell (или любом другом методе), заставить скрипт powershell "не выполнить" действие приглашения cmd при запуске сценария ... так, чтобы задание SQL сообщало об ошибке?

Имеет ли это смысл? LOL

Я бы предположил, что если бы мне удалось использовать SQL 2008, который допускает тип шага задания SQL «Скрипт Powershell» (вместо того, чтобы быть типом шага, который должен быть «Операционная система»… который запускает сценарий PS) это не будет проблемой ... однако ... это не вариант.

В данный момент шаг задания запускает сценарий powershell через CMD с использованием параметров для DBName, Path и Servername и выглядит следующим образом:

powershell.exe "C:\SQLBackupScriptsTest\SQLServerBackup.ps1" -DBName 'Angel_Food' -Path 'E:\SQLBackup1' -Server 'DEVSQLSRV'

Фактический скрипт Powershell выглядит следующим образом:

Param($DBName,$Path,$Server)

## Add sql snapins...must have for Invoke-Sqlcmd with powershell 2.0 ##

add-pssnapin sqlserverprovidersnapin100
add-pssnapin sqlservercmdletsnapin100
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null

## Set parameter for finding DB recovery model ##
$Recovery = (Invoke-Sqlcmd -Query "SELECT recovery_model_desc FROM sys.databases WHERE name = '$DBName'" -Server $Server)

## Do full backup of DB ##
(Invoke-Sqlcmd -Query "BACKUP DATABASE $DBName TO  DISK = N'$Path\$DBName\$DBName.bak' WITH NOFORMAT, INIT,  NAME = N'$DBNameTEST', SKIP, NOREWIND, NOUNLOAD,  STATS = 10, CHECKSUM" -Server $Server -ConnectionTimeout 0 -QueryTimeout 65535)

############################################################################################################
## Check recovery mode, if FULL, check for Log-PrevDay.bak. If exists then delete.  If not exist, move on ##
## Then check for Current TX log backup.  If exists, rename to Log-PreDay.bak. If not exist, move on      ##
## Then perform TX Log backup                                                                             ##
## If recovery mode NOT FULL, do nothing                                                                  ##
############################################################################################################
    IF
    ($Recovery.recovery_model_desc -eq 'FULL')
    #THEN#
    {
            ## Look to see if PrevDay TX log exists.  If so, delete, if not, move on ##
            IF 
            (Test-Path $Path\$DBName\$DBName-Log-PrevDay.bak) 
            #THEN#
            {remove-item $Path\$DBName\$DBName-Log-PrevDay.bak -force}
            ELSE
            {}
                ## Look to see if current TX log exists, if so, rename to Prev Day TX Log, if not, move on ##
                IF
                (Test-Path $Path\$DBName\$DBName-Log.bak)
                #THEN#
                {rename-item $Path\$DBName\$DBName-Log.bak -newname $DBName-Log-PrevDay.bak -force}
                ELSE
                {}

    Invoke-Sqlcmd -Query "BACKUP LOG $DBName TO  DISK = N'$Path\$DBName\$DBName-Log.bak' WITH NOFORMAT, INIT,  NAME = N'$DBName LogTEST (Init)', SKIP, NOREWIND, NOUNLOAD,  STATS = 10, CHECKSUM" -Server $Server -ConnectionTimeout 0 -QueryTimeout 65535}
    ELSE
    {}

1 Ответ

1 голос
/ 01 октября 2010

Хорошо, после просмотра нескольких блогов и небольшого количества проб / ошибок / удачи ... Я получил это, чтобы делать то, что я хочу.

Я решил, что мне нужно отправить код выхода Powershell обратно в CMDEXEC. Однако из того, что я обнаружил, Powershell по умолчанию всегда имеет код выхода 0 (успех) ... если только вы не перепрыгнете через несколько циклов, используя сценарии 2 PS ... что я действительно не хотел делать. Поэтому я решил просто перехватить любую ошибку, и если какая-либо ошибка была перехвачена, она должна выйти из сценария PS с кодом 1, несмотря ни на что. Честно говоря ... все, что я действительно хотел, это надежный код выхода 0 (успех) или 1 (сбой). Итак ... Короче говоря ... вот как я изменил свой код.

Я менял CMDEXEC каждого шага следующим образом:

powershell.exe -noprofile C:\SQLBackupScriptsTest\SQLServerBackup2.ps1 -DBName 'Angel_Food' -Path 'E:\SQLBackup' -Server 'DEVSQLSRV'
@Echo %errorlevel%

Затем я изменил свой сценарий PS на:

Param($DBName,$Path,$Server)

## Add sql snapins...must have for Invoke-Sqlcmd with powershell 2.0 ##

add-pssnapin sqlserverprovidersnapin100
add-pssnapin sqlservercmdletsnapin100
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null

## Set parameter for finding DB recovery model ##
$Recovery = (Invoke-Sqlcmd -Query "SELECT recovery_model_desc FROM sys.databases WHERE name = '$DBName'" -Server $Server)

## Do full backup of DB ##
trap {$_.Exception.Message; exit 1; continue}Invoke-Sqlcmd -Query "BACKUP DATABASE $DBName TO  DISK = N'$Path\$DBName\$DBName.bak' WITH NOFORMAT, INIT,  NAME = N'$DBNameTEST', SKIP, NOREWIND, NOUNLOAD,  STATS = 10, CHECKSUM" -Server $Server -ConnectionTimeout 0 -QueryTimeout 65535 -ea stop

############################################################################################################
## Check recovery mode, if FULL, check for Log-PrevDay.bak. If exists then delete.  If not exist, move on ##
## Then check for Current TX log backup.  If exists, rename to Log-PreDay.bak. If not exist, move on      ##
## Then perform TX Log backup                                                                             ##
## If recovery mode NOT FULL, do nothing                                                                  ##
############################################################################################################
    IF
    ($Recovery.recovery_model_desc -eq 'FULL')
    #THEN#
    {
            ## Look to see if PrevDay TX log exists.  If so, delete, if not, move on ##
            IF 
            (Test-Path $Path\$DBName\$DBName-Log-PrevDay.bak) 
            #THEN#
            {remove-item $Path\$DBName\$DBName-Log-PrevDay.bak -force}
            ELSE
            {}
                ## Look to see if current TX log exists, if so, rename to Prev Day TX Log, if not, move on ##
                IF
                (Test-Path $Path\$DBName\$DBName-Log.bak)
                #THEN#
                {rename-item $Path\$DBName\$DBName-Log.bak -newname $DBName-Log-PrevDay.bak -force}
                ELSE
                {}

            trap {$_.Exception.Message; exit 1; continue}Invoke-Sqlcmd -Query "BACKUP LOG $DBName TO  DISK = N'$Path\$DBName\$DBName-Log.bak' WITH NOFORMAT, INIT,  NAME = N'$DBName LogTEST (Init)', SKIP, NOREWIND, NOUNLOAD,  STATS = 10, CHECKSUM" -Server $Server -ConnectionTimeout 0 -QueryTimeout 65535 -ea stop}
    ELSE
    {}

Обычно я добавлял trap {$_.Exception.Message; exit 1; continue} прямо перед каждым оператором Invoke-Sqlcmd и заканчивал каждый оператор Invoke-Sqlcmd с помощью -ea stop.

trap $_.Exception.Message перехватывает любую ошибку ... собирает сообщение об ошибке, затем exit 1 немедленно выходит из сценария PS с кодом выхода 1.

Задание SQL считывает каждый шаг с 0 или 1 и автоматически интерпретирует 0 как успех, а 1 как сбой и правильно отмечает пометку SQL как успех или сбой. Кроме того, поскольку я зафиксировал фактическое сообщение об ошибке ... оно отображается в истории заданий SQL.

Это оказалось именно тем, что мне нужно. :)

Если вам интересно ... вот блоги, которые мне больше всего помогли:

...