Agen SQL - PowerShell langkah "kesalahan sintaks"

10

Saya memiliki pengaturan kode berikut dalam langkah Pekerjaan Agen SQL yang tidak berjalan. Pesan yang diterima adalah:

Tidak dapat memulai pelaksanaan langkah 1 (alasan: baris (46): Kesalahan sintaksis). Langkah itu gagal.

Durasi pekerjaan adalah: 00:00:00

Baris 46 dari skrip ini adalah here-string:


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

Script ini berjalan sempurna di luar SQL Server Agent.

Tabel ServerNames:


CREATE TABLE ServerTable (
ServerName varchar(50)
)

Tabel Disk Space akan menjadi sesuatu yang mirip dengan:


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

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

}

EDIT

Siapkan langkah-langkah tambahan untuk mencoba menggunakan tipe CmdExec sebagai PowerShell -Command "& { }". Dengan eksekusi ini, skrip berjalan dan log kesalahan diisi untuk menangkap blok yang sesuai, tetapi tidak ada data ruang disk yang ditulis ke tabel.

Riwayat agen untuk proses ini menunjukkan pesan peringatan:

Pesan yang Dieksekusi sebagai pengguna: NT Service \ SQLAgent $ myInstance. PERINGATAN: Beberapa nama perintah yang diimpor termasuk kata kerja yang tidak disetujui yang mungkin membuatnya kurang dapat ditemukan. Gunakan parameter Verbose untuk lebih detail atau ketik Get-Verb untuk melihat daftar kata kerja yang disetujui. Kode Keluar Proses 0. Langkah ini berhasil.

Jika saya menggunakan tipe langkah yang sama tetapi memanggil file: PowerShell -File MyScript.ps1 Saya mendapatkan pesan yang sama dengan tipe langkah PowerShell di atas untuk kesalahan sintaks.

RolandoMySQLDBA
sumber

Jawaban:

11

Ini sangat tidak intuitif dan saya tidak pernah dapat menemukan sesuatu yang konkret pada penjelasan [misalnya tidak ada BOL atau kertas putih yang tepat ditemukan].

Kesalahan sintaksis dalam pekerjaan SQL Agent adalah kesalahan sintaksis T-SQL berdasarkan Token Pengguna . Sehingga pada dasarnya berarti bahwa Operator Sub-Ekspresi PowerShell diperlakukan sebagai Token to SQL Server Agent. Jadi di PowerShell ini $( )tampaknya diperlakukan sebagai urutan karakter khusus untuk SQL Server Agent. Jadi SQL Agen akan mencari sesuatu seperti T-SQL ini contoh dari artikel BOL direferensikan: PRINT N'Current database name is $(A-DBN)' ; .

Jadi dalam skrip saya ketika mencapai ,@DriveLetter = '$($c.DriveLetter)', "$ c.DriveLetter" bukan salah satu token yang diizinkan.

Solusi untuk ini adalah tidak menggunakan pernyataan sub-ekspresi di PowerShell. Saya akan membuat penyesuaian dalam skrip saya jadi ini:


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

harus diubah menjadi seperti ini:


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

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

Buat penyesuaian di atas untuk skrip saya dan sekarang berjalan dengan sempurna.


sumber
1

Kutipan tunggal (') adalah karakter khusus untuk string Powershell dan delimits. Perbedaan antara tanda kutip ganda dan tunggal adalah dalam hal bagaimana ia menafsirkan string . Karena ini adalah karakter khusus, Anda ingin menghindarinya menggunakan aksen kubur (`) . Sintaks ini bekerja untuk Anda:

 @ServerName = `'$($c.ServerName)`'
,@DriveLetter = `'$($c.DriveLetter)`'
Mike Fal
sumber
Itu adalah di sini-string yang tidak memperlakukannya sebagai karakter khusus, menganggapnya apa adanya. Menambahkan aksen kubur meskipun tidak berpengaruh, masih menerima pesan sintaks yang sama oleh SQL Agent untuk nomor baris yang sama.