Tác nhân SQL - Bước PowerShell Lỗi cú pháp lỗi


10

Tôi có thiết lập mã sau đây trong bước Công việc Tác nhân SQL không chạy. Tin nhắn nhận được chỉ đơn giản là:

Không thể bắt đầu thực hiện bước 1 (lý do: dòng (46): Lỗi cú pháp). Bước thất bại.

Thời gian của công việc là: 00:00:00

Dòng 46 của kịch bản này là here-string:


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

Kịch bản này chạy hoàn hảo bên ngoài SQL Server Agent.

Bảng ServerNames:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

Bảng không gian đĩa sẽ là một cái gì đó tương tự như:


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

Tập lệnh 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
    }
}

}

BIÊN TẬP

Thiết lập các bước bổ sung để thử sử dụng loại CmdExec như PowerShell -Command "& { }". Với việc thực thi này, tập lệnh chạy và nhật ký lỗi được điền cho các khối bắt thích hợp, nhưng không có dữ liệu không gian đĩa được ghi vào bảng.

Lịch sử đại lý cho lần chạy này hiển thị một thông báo cảnh báo:

Thông báo được thực thi với tư cách là người dùng: NT Service \ SQLAgent $ myInstance. CẢNH BÁO: Một số tên lệnh đã nhập bao gồm các động từ không được chấp thuận có thể khiến chúng ít được khám phá hơn. Sử dụng tham số Verbose để biết thêm chi tiết hoặc nhập Get-Verb để xem danh sách các động từ được phê duyệt. Quy trình thoát mã 0. Bước thành công.

Nếu tôi sử dụng bước cùng loại nhưng gọi tệp: PowerShell -File MyScript.ps1 Tôi nhận được thông báo tương tự như loại bước PowerShell ở trên vì lỗi cú pháp.

Câu trả lời:


11

Đây không phải là rất trực quan và tôi không bao giờ có thể tìm thấy bất cứ điều gì cụ thể trên lời giải thích [ví dụ: không tìm thấy BOL hoặc giấy trắng chính xác].

Lỗi cú pháp trong công việc Tác nhân SQL là lỗi cú pháp T-SQL dựa trên Mã thông báo người dùng . Vì vậy, về cơ bản có nghĩa là Toán tử biểu thức phụ PowerShell được coi là Mã thông báo cho Đại lý máy chủ SQL. Vì vậy, trong PowerShell, điều này $( )dường như được coi là chuỗi ký tự dành riêng cho SQL Server Agent. Vì vậy, Tác nhân SQL sẽ tìm kiếm một cái gì đó giống như ví dụ T-SQL này từ bài viết BOL được tham chiếu : PRINT N'Current database name is $(A-DBN)' ; .

Vì vậy, trong kịch bản của tôi khi đạt đến ,@DriveLetter = '$($c.DriveLetter)', "$ c.DriveLetter" không phải là một trong những mã thông báo được phép.

Cách giải quyết cho vấn đề này chỉ đơn giản là không sử dụng các câu lệnh biểu thức con trong PowerShell. Tôi sẽ thực hiện các điều chỉnh trong kịch bản của mình để điều này:


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

sẽ phải được sửa đổi thành một cái gì đó như thế này:


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

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

Thực hiện các điều chỉnh trên cho kịch bản của tôi và nó chạy hoàn hảo ngay bây giờ.


1

Dấu ngoặc đơn (') là một ký tự đặc biệt cho Powershell và phân định các chuỗi. Sự khác biệt giữa dấu ngoặc kép và dấu ngoặc đơn là ở chỗ nó diễn giải chuỗi như thế nào . Vì nó là một ký tự đặc biệt, bạn sẽ muốn thoát khỏi nó bằng cách sử dụng dấu trọng âm (`) . Cú pháp này sẽ làm việc cho bạn:

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

Nó nằm trong một chuỗi ở đây không coi nó là một ký tự đặc biệt, coi nó là như vậy. Thêm dấu trọng âm mặc dù không có ảnh hưởng, vẫn nhận được thông báo cú pháp tương tự của Tác nhân SQL cho cùng một số dòng.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.