2

J'ai une instance SQL 2005 qui exécute un travail qui utilise un script Powershell pour renommer le fichier de sauvegarde actuel du journal TX TX en ajoutant "-PrevDay" "pour cela, (en supprimant ensuite la sauvegarde déjà nommée" XXX-PrevDay.bak "si elle existe), puis exécutez une sauvegarde complète de la base de données et une sauvegarde du journal TX, si le DB n'est pas en mode simple. Le travail SQL Server Agent démarre le script Powershell via CMD à chaque étape du travail et le script powershell lance la sauvegarde sql à l'aide de la cmdlet "Invoke-SQLCmd". Cela fonctionne très bien, à moins que la sauvegarde échoue, car le travail SQL s'affiche toujours comme "Réussi". C'est parce que le travail SQL qui lance le script Powershell via l'invite CMD, se soucie seulement si le script Powershell s'exécute ... pas si les commandes du script réussissent ou échouent.Afficher l'échec pour SQL 2005 Travail qui exécute le script Powershell via l'invite CMD, échec du script PS

Est-il possible, en utilisant le piégeage d'erreurs dans powershell (ou n'importe quelle méthode), que le script powershell "échoue" l'action de commande cmd d'exécuter le script ... de sorte que le travail SQL signale un échec?

Est-ce que cela a même du sens? LOL

Je suppose que si j'étais capable d'utiliser SQL 2008, qui permet un type d'étape de travail SQL de "Powershell Script" (au lieu du type d'étape devant être le système d'exploitation ... qui lance le PS script) ce ne serait pas un problème ... cependant ... ce n'est pas une option.

En ce moment, l'étape de travail exécute le script Powershell, par CMD à l'aide de paramètres pour DBName, Path et Servername et ressemble à ceci:

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

Le script Powershell réelle ressemble à ceci:

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 
    {} 
+0

peut-être obtenir le code de sortie PS ... et l'envoi retour à CMD? Quelque chose dans ce sens? – Emo

Répondre

1

Ok, après avoir regardé quelques blogs et un peu de procès/erreur/chance ... je l'ai eu à faire ce que je veux. J'ai décidé que je devais renvoyer le code de sortie Powershell au CMDEXEC. Cependant, d'après ce que j'ai trouvé, Powershell utilise toujours par défaut un code de sortie de 0 (succès) ... à moins que vous ne franchissiez quelques obstacles en utilisant 2 scripts PS ... ce que je ne voulais vraiment pas faire. J'ai donc décidé de piéger n'importe quelle erreur et si une erreur était piégée, faites-la sortir du script PS avec un code de 1, quoi qu'il arrive. Honnêtement ... tout ce que je voulais vraiment, c'était un code de sortie fiable de 0 (succès) ou 1 (échec). Alors ... longue histoire courte ... voici comment j'ai changé mon code.

J'ai changé le CmdExec de chaque étape à ceci:

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

Puis j'ai changé mon script 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 
    {} 

Fondamentalement, j'ajouté trap {$_.Exception.Message; exit 1; continue} juste en face de chaque déclaration Invoke-Sqlcmd et finit chaque Invoke-Sqlcmd déclaration avec -ea stop.

Le trap $_.Exception.Message intercepte toute erreur ... recueille le message d'erreur, puis exit 1 quitte immédiatement le script PS avec un code de sortie de 1.

Le travail SQL lit chaque étape avec un 0 ou un 1 et interprète automatiquement 0 comme succès et 1 comme échec et marque le travail SQL comme un succès ou un échec correctement. De plus, depuis que j'ai capturé le message d'erreur réel ... il apparaît dans l'historique des travaux SQL.

Ceci étant exactement ce dont j'ai besoin. :)

Si vous êtes curieux ... voici les blogs qui m'a aidé le plus: