SQL Agent - PowerShell-Schritt "Syntaxfehler"

10

Ich habe den folgenden Code-Setup im SQL Agent-Jobschritt, der nicht ausgeführt wird. Die empfangene Nachricht lautet einfach:

Die Ausführung von Schritt 1 kann nicht gestartet werden (Grund: Zeile (46): Syntaxfehler). Der Schritt ist fehlgeschlagen.

Die Dauer des Auftrags beträgt: 00:00:00

Zeile 46 dieses Skripts lautet here-string:


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

Dieses Skript läuft perfekt außerhalb von SQL Server Agent.

ServerNames-Tabelle:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

Die Speicherplatztabelle wäre ungefähr so:


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

PowerShell-Skript:


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
    }
}

}

BEARBEITEN

Richten Sie zusätzliche Schritte ein, um zu versuchen, den CmdExec-Typ als zu verwenden PowerShell -Command "& { }". Bei dieser Ausführung wird das Skript ausgeführt und das Fehlerprotokoll wird für die entsprechenden Catch-Blöcke ausgefüllt, es werden jedoch keine Speicherplatzdaten in die Tabelle geschrieben.

Der Agentenverlauf für diesen Lauf zeigt eine Warnmeldung an:

Als Benutzer ausgeführte Nachricht: NT Service \ SQLAgent $ myInstance. WARNUNG: Einige importierte Befehlsnamen enthalten nicht genehmigte Verben, wodurch sie möglicherweise weniger auffindbar sind. Verwenden Sie den Parameter Verbose für weitere Details oder geben Sie Get-Verb ein, um die Liste der genehmigten Verben anzuzeigen. Prozess-Exit-Code 0. Der Schritt war erfolgreich.

Wenn ich denselben Typschritt verwende, aber die Datei aufrufe: PowerShell -File MyScript.ps1 Ich erhalte dieselbe Meldung wie der oben angegebene PowerShell-Schritttyp für Syntaxfehler.

RolandoMySQLDBA
quelle

Antworten:

11

Dies ist nicht sehr intuitiv und ich konnte nie etwas Konkretes zu der Erklärung finden [z. B. wurde kein genaues BOL oder Whitepaper gefunden].

Der Syntaxfehler im SQL Agent-Job ist ein T-SQL-Syntaxfehler, der auf Benutzertoken basiert . Dies bedeutet im Grunde, dass ein PowerShell-Unterausdrucksoperator als Token für den SQL Server-Agenten behandelt wird. In PowerShell $( )scheint dies als reservierte Zeichenfolge für den SQL Server-Agenten behandelt zu werden. SQL Agent würde also nach so etwas wie diesem T-SQL-Beispiel aus dem BOL-Artikel suchen, auf den verwiesen wird : PRINT N'Current database name is $(A-DBN)' ; .

Wenn es in meinem Skript erreicht ist ,@DriveLetter = '$($c.DriveLetter)', ist der "$ c.DriveLetter" nicht einer der zulässigen Token.

Die Problemumgehung besteht einfach darin, keine Unterausdrucksanweisungen in PowerShell zu verwenden. Ich würde die Anpassungen in meinem Skript so vornehmen:


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

müsste auf so etwas geändert werden:


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

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

Ich habe die obigen Anpassungen an meinem Skript vorgenommen und es läuft jetzt perfekt.


quelle
1

Das einfache Anführungszeichen (') ist ein Sonderzeichen für Powershell und begrenzt Zeichenfolgen. Der Unterschied zwischen doppelten und einfachen Anführungszeichen besteht darin, wie die Zeichenfolge dann interpretiert wird . Da es sich um ein Sonderzeichen handelt, sollten Sie es mit dem Grabakzent (`) umgehen . Diese Syntax sollte für Sie funktionieren:

 @ServerName = `'$($c.ServerName)`'
,@DriveLetter = `'$($c.DriveLetter)`'
Mike Fal
quelle
Es befindet sich in einer Here-Zeichenfolge, die es nicht als Sonderzeichen behandelt, sondern so wie es ist. Das Hinzufügen des schwerwiegenden Akzents hat jedoch keine Auswirkungen. Sie erhalten dennoch dieselbe Syntaxnachricht von SQL Agent für dieselbe Zeilennummer.