Агент SQL - шаг PowerShell «синтаксическая ошибка»

10

У меня есть следующий код настройки в шаге задания агента SQL, который не выполняется. Полученное сообщение просто:

Невозможно начать выполнение шага 1 (причина: строка (46): синтаксическая ошибка). Шаг не удался.

Продолжительность работы составляет: 00:00:00

Строка 46 этого сценария here-string:


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

Этот сценарий отлично работает вне агента SQL Server.

Таблица ServerNames:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

Таблица дискового пространства будет выглядеть примерно так:


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

Скрипт 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
    }
}

}

РЕДАКТИРОВАТЬ

Установите дополнительные шаги, чтобы попытаться использовать тип CmdExec как PowerShell -Command "& { }". При таком выполнении сценарий запускается, и журнал ошибок заполняется для соответствующих блоков перехвата, но данные дискового пространства не записываются в таблицу.

История агента для этого запуска показывает предупреждающее сообщение:

Сообщение выполнено от имени пользователя: NT Service \ SQLAgent $ myInstance. ВНИМАНИЕ: Некоторые импортированные имена команд содержат неутвержденные глаголы, которые могут сделать их менее доступными для обнаружения. Используйте параметр Verbose для более подробной информации или введите Get-Verb, чтобы увидеть список утвержденных глаголов. Код выхода процесса 0. Шаг успешно выполнен.

Если я использую тот же тип шага, но вызываю файл: PowerShell -File MyScript.ps1 я получаю то же сообщение, что и тип шага PowerShell выше для синтаксической ошибки.

RolandoMySQLDBA
источник

Ответы:

11

Это не очень интуитивно понятно, и я так и не смог найти что-то конкретное в объяснении (например, не было найдено точного BOL или белой книги).

Синтаксическая ошибка в задании агента SQL - это синтаксическая ошибка T-SQL на основе пользовательских токенов . Таким образом, это в основном означает, что оператор подвыражения PowerShell обрабатывается как агент Token to SQL Server. Таким образом, в PowerShell это $( )выглядит как зарезервированная последовательность символов для агента SQL Server. Таким образом , агент SQL будет искать что - то вроде этого примера T-SQL из статьи BOL ссылка: PRINT N'Current database name is $(A-DBN)' ; .

Поэтому в моем сценарии, когда он достиг ,@DriveLetter = '$($c.DriveLetter)', «$ c.DriveLetter» не является одним из разрешенных токенов.

Обходной путь к этому просто состоит в том, чтобы не использовать операторы подвыражения в PowerShell. Я бы внес коррективы в мой скрипт так:


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

пришлось бы изменить что-то вроде этого:


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

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

Внесены вышеуказанные корректировки в мой скрипт, и теперь он работает отлично.


источник
1

Одиночная кавычка (') является специальным символом для Powershell и разделяет строки. Разница между двойными и одинарными кавычками заключается в том, как она интерпретирует строку . Поскольку это специальный символ, вы можете избежать его, используя grave-accent (`) . Этот синтаксис должен работать для вас:

 @ServerName = `'$($c.ServerName)`'
,@DriveLetter = `'$($c.DriveLetter)`'
Майк Фал
источник
Он находится внутри строки здесь, которая не обрабатывает его как специальный символ, принимает его как есть. Добавление серьезного акцента, хотя и не оказывает никакого влияния, все еще получает то же самое синтаксическое сообщение агентом SQL для того же номера строки.