Agente SQL: passaggio "errore di sintassi" di PowerShell


10

Ho la seguente impostazione del codice nel passaggio del processo SQL Agent che non è in esecuzione. Il messaggio ricevuto è semplicemente:

Impossibile avviare l'esecuzione del passaggio 1 (motivo: riga (46): errore di sintassi). Il passo è fallito.

La durata del lavoro è: 00:00:00

La riga 46 di questo script è una here-string:


    ,@DriveLetter = '$($c.DriveLetter)'

Questo script funziona perfettamente al di fuori di SQL Server Agent.

Tabella ServerNames:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

La tabella Spazio su disco sarebbe simile a:


CREATE TABLE DiskSpace (
ID int IDENTITY(1,1),
ServerName varchar(50),
DriveLetter varchar(2),
DiskSpaceCapacityGB decimal(12,5),
DiskSpaceFreeGB decimal(12,5)
)

Script di PowerShell:


This command is to allow SQL Agent job to show failure in event PowerShell script errors
Default behavior in SQL Agent for PowerShell steps it 'Continue'
$erroractionpreference = "Stop"

$sqlInstance = 'server1' $sqlDatabase = 'database1'

$qServerList = @" Select ServerName From ServerTable "@

$srvList = Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $sqlDatabase -Query $qServerList | Where-Object {$_ -ne '' -or $_ -ne $null} | Select-Object -ExpandProperty ServerName

foreach ($s in $srvList) { if (Test-Connection -ComputerName $s -Count 1 -ErrorAction 'SilentlyContinue') { try { $cServer = Get-WmiObject Win32_Volume -ComputerName $s -ErrorAction 'Stop' | where {$.DriveType -eq 3 -and $.DriveLetter } | Select-Object @{Label="ServerName";Expression={$s}}, @{Label="DriveLetter";Expression={$.DriveLetter}}, @{Label="DiskSpaceCapacityGB";Expression={"{0:N0}" -f($.Capacity/1GB)}}, @{Label="DiskFreeSpaceGB";Expression={"{0:N2}" -f($_.FreeSpace/1GB)}}

        foreach ($c in $cServer) 
        {
            $qAddServerDiskSpace = @"

EXEC [dbo].[StoredProcInsert] @ServerName = '$($c.ServerName)' ,@DriveLetter = '$($c.DriveLetter)' ,@DiskSpaceCapacityGB = $($c.DiskSpaceCapacityGB) ,@DiskFreeSpaceGB = $($c.DiskFreeSpaceGB) "@

            try
            {
                Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $sqlDatabase -Query $qAddServerDiskSpace -ErrorAction 'Stop'
            }
            catch
            {
                $ErrorMsg = $_.Exception.Message
                $fullMsg = "Error writing executing dbo.StoredProcInsert for $s - $ErrorMsg"
                Return $fullMsg
            }           
        }
    }
    catch
    {
        $ErrorMsg = $_.Exception.Message
        $qAddPSErrorLog = @"

EXEC [dbo].[StoredProcInsert_Error] @ServerName = '$($cServer.ServerName)' , @ErrorText = '$($ErrorMsg)' "@ try { Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $sqlDatabase -Query $qAddPSErrorLog -ErrorAction 'Stop' } catch { $ErrorMsg = $_.Exception.Message $fullMsg = "Error writing executing dbo.StoredProcInsert_Error for $s - $ErrorMsg" Return $fullMsg } } } else { $qAddPSErrorLog = @" EXEC [dbo].[StoredProcInsert_Error] @ServerName = '$($cServer.ServerName)' , @ErrorText = 'Unable to ping server' "@

    try 
    {
        Invoke-Sqlcmd -ServerInstance $sqlInstance -Database $sqlDatabase -Query $qAddPSErrorLog  -ErrorAction 'Stop'
    }
    catch 
    {
        $ErrorMsg = $_.Exception.Message
        $fullMsg = "Error writing executing dbo.StoredProcInsert_Error for $s - $ErrorMsg"
        Return $fullMsg
    }
}

}

MODIFICARE

Configurare i passaggi aggiuntivi per provare a utilizzare CmdExec come PowerShell -Command "& { }". Con questa esecuzione lo script viene eseguito e il registro errori viene popolato per i blocchi catch appropriati, ma non vengono scritti dati di spazio su disco nella tabella.

La cronologia dell'agente per questa esecuzione mostra un messaggio di avviso:

Messaggio eseguito come utente: Servizio NT \ SQLAgent $ myInstance. ATTENZIONE: alcuni nomi di comandi importati includono verbi non approvati che potrebbero renderli meno rilevabili. Utilizzare il parametro Verbose per maggiori dettagli o digitare Get-Verb per visualizzare l'elenco dei verbi approvati. Codice di uscita processo 0. Il passaggio è riuscito.

Se utilizzo lo stesso passaggio di tipo ma chiamo il file: PowerShell -File MyScript.ps1 ricevo lo stesso messaggio del passaggio precedente di PowerShell per errore di sintassi.

Risposte:


11

Questo non è molto intuitivo e non sono mai stato in grado di trovare qualcosa di concreto sulla spiegazione [ad esempio, non è stato trovato nessun BOL o white paper esatto].

L'errore di sintassi nel processo Agente SQL è un errore di sintassi T-SQL basato sui token utente . Ciò significa sostanzialmente che un operatore di sottoespressione di PowerShell viene trattato come token per SQL Server Agent. Quindi in PowerShell questo $( )sembra essere trattato come una sequenza di caratteri riservata per SQL Server Agent. Quindi SQL agente sarebbe in cerca di qualcosa di simile a questo esempio T-SQL dall'articolo BOL riferimento: PRINT N'Current database name is $(A-DBN)' ; .

Quindi nel mio script quando è arrivato ,@DriveLetter = '$($c.DriveLetter)', "$ c.DriveLetter" non è uno dei token consentiti.

La soluzione a questo è semplicemente di non usare le dichiarazioni di sottoespressione in PowerShell. Vorrei apportare le modifiche alla mia sceneggiatura in questo modo:


$qAddServerDiskSpace = @"
EXEC [dbo].[StoredProcInsert]
    @ServerName = '$($c.ServerName)'
    ,@DriveLetter = '$($c.DriveLetter)'
    ,@DiskSpaceCapacityGB = $($c.DiskSpaceCapacityGB)
    ,@DiskFreeSpaceGB = $($c.DiskFreeSpaceGB)
"@

dovrebbe essere modificato in qualcosa del genere:


$severName = $c.ServerName
$driveLetter = $c.DriveLetter
$capacityGB = $c.DiskSpaceCapacityGB
$freeGB = $c.DiskFreeSpaceGB

$qAddServerDiskSpace = @"
EXEC [dbo].[StoredProcInsert]
   @ServerName = '$serverName'
   ,@DriveLetter = '$driveLetter'
   ,@DiskSpaceCapacityGB = $CapacityGB
   ,@DiskFreeSpaceGB = $freeGB
"@

Ho apportato le modifiche di cui sopra alla mia sceneggiatura e ora funziona perfettamente.


1

La virgoletta singola (') è un carattere speciale per Powershell e delimita le stringhe. La differenza tra virgolette doppie e singole dipende da come interpreta la stringa . Dato che è un personaggio speciale, vorrai fuggire usando accento grave (`) . Questa sintassi dovrebbe funzionare per te:

 @ServerName = `'$($c.ServerName)`'
,@DriveLetter = `'$($c.DriveLetter)`'

È all'interno di una stringa qui che non lo tratta come un carattere speciale, lo prende così com'è. L'aggiunta dell'accento grave, tuttavia, non ha alcun effetto, riceve comunque lo stesso messaggio di sintassi dall'agente SQL per lo stesso numero di riga.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.