Agente SQL: paso de PowerShell "error de sintaxis"


10

Tengo la siguiente configuración de código en el paso de trabajo del Agente SQL que no se está ejecutando. El mensaje recibido es simplemente:

No se puede iniciar la ejecución del paso 1 (razón: línea (46): error de sintaxis). El paso falló.

La duración del trabajo es: 00:00:00

La línea 46 de este script es un here-string:


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

Este script se ejecuta perfecto fuera del Agente SQL Server.

Tabla ServerNames:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

La tabla de espacio en disco sería algo similar a:


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

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

}

EDITAR

Configure pasos adicionales para intentar usar el tipo CmdExec como PowerShell -Command "& { }". Con esta ejecución, el script se ejecuta y el registro de errores se llena para los bloques catch apropiados, pero no se escriben datos de espacio en disco en la tabla.

El historial del agente para esta ejecución muestra un mensaje de advertencia:

Mensaje ejecutado como usuario: NT Service \ SQLAgent $ myInstance. ADVERTENCIA: Algunos nombres de comandos importados incluyen verbos no aprobados que pueden hacerlos menos reconocibles. Use el parámetro Verbose para obtener más detalles o escriba Get-Verb para ver la lista de verbos aprobados. Código de salida de proceso 0. El paso se realizó correctamente.

Si utilizo el mismo paso de tipo pero llamo al archivo: PowerShell -File MyScript.ps1 recibo el mismo mensaje que el paso de PowerShell del tipo anterior para el error de sintaxis.

Respuestas:


11

Esto no es muy intuitivo y nunca pude encontrar nada concreto en la explicación [por ejemplo, no se encontró BOL exacto o papel blanco].

El error de sintaxis en el trabajo del Agente SQL es un error de sintaxis T-SQL basado en tokens de usuario . Entonces, eso básicamente significa que un operador de subexpresión de PowerShell se trata como un token para el Agente SQL Server. Entonces, en PowerShell, esto $( )parece tratarse como una secuencia de caracteres reservada para el Agente SQL Server. Así Agente SQL estaría buscando algo así como este ejemplo de T-SQL del artículo de referencia BOL: PRINT N'Current database name is $(A-DBN)' ; .

Entonces, en mi script cuando llegó ,@DriveLetter = '$($c.DriveLetter)', el "$ c.DriveLetter" no es uno de los tokens permitidos.

La solución a esto es simplemente no usar declaraciones de subexpresión en PowerShell. Haría los ajustes en mi script para que esto:


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

tendría que ser modificado a algo como esto:


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

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

Hice los ajustes anteriores a mi script y ahora funciona perfectamente.


1

La comilla simple (') es un carácter especial para Powershell y delimita las cadenas. La diferencia entre comillas dobles y simples está en la cuestión de cómo interpreta la cadena . Como es un personaje especial, querrás escapar usando acento grave (`) . Esta sintaxis debería funcionar para usted:

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

Está dentro de una cadena aquí que no lo trata como un carácter especial, lo toma como está. Sin embargo, agregar el acento grave no tiene ningún efecto, aún recibirá el mismo mensaje de sintaxis del Agente SQL para el mismo número de línea.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.