执行 xp_cmdshell 以生成 CSV -- 不喜欢查询中的 'WHERE' 子句

Executing xp_cmdshell to Generate a CSV -- Doesn't Like 'WHERE' Clause in Query

我有以下代码:

USE MyFakeDB
GO

DECLARE @month VARCHAR(16) 
SET @month = 'October2021'
;

DECLARE @cmd VARCHAR(8000)
    , @sql NVARCHAR(max)
    , @return INT
    , @filepath VARCHAR(512)
    , @servername VARCHAR(255) = @@ServerName
    , @username VARCHAR(255) = 'me'
    , @password VARCHAR(255) = 'password1234'
    , @dbname VARCHAR(255) = 'MyFakeDB'
    , @tablename VARCHAR(255) = 'Monthly_Insert'
    , @folderpath VARCHAR(255) = 'E:\SomeData\Monthly'  
    , @filename VARCHAR(255) = '' +@month+ '_Inserts.csv'
    , @datadate NVARCHAR(255) = 'WHERE DataMonth = ''' +@month+ ''''
;

SET @cmd = 'Invoke-Sqlcmd -Query ''SELECT Medium, RunDate, RunTime, UTCDate, UTCTime FROM '+@dbname+'.dbo.'+@tablename+' '+@datadate+ ';'' -Database '+@dbname+' -Server "'+@servername+'" -Username '+@username+' -Password '+@password+
        ' | ConvertTo-Csv -NoTypeInformation | Set-Content -Path '+@folderpath+'\'+@filename+' -Encoding UTF8'
SET @cmd = 'powershell.exe -noprofile -command "'+@cmd+'"'
EXEC @return = xp_cmdshell @cmd, no_output
    IF @return <> 0
    BEGIN
        PRINT 'ERROR: '+@cmd
    END
;
GO

当我尝试 运行 时,我得到一个

ERROR: powershell.exe -noprofile -command blah blah blah

错误。如果我删除 @datadate 变量(实际上只是 WHERE 子句),它工作得很好。

我也试过在 WHERE 子句没有变量的情况下做到这一点,只是写了文字字符串但它仍然不起作用,这让我相信它不喜欢有一个 WHERE 子句。

知道为什么吗?

谢谢,

通过 -command 参数传递 powershell 脚本是出了名的棘手。

而是使用 -command -,它指示 Powershell 从标准输入读取脚本,您可以在 cmd.exe 中使用 < 重定向运算符提供该脚本。

EG

SET @cmd = 'powershell.exe -noprofile -command - < '+@cmd

并且这还允许您发送多行 powershell 脚本,更易于阅读,例如

SET @cmd = 'Invoke-Sqlcmd -Query ''SELECT Medium, RunDate, RunTime, UTCDate, UTCTime FROM '+@dbname+'.dbo.'+@tablename+' '+@datadate+ ';'' -Database '+@dbname+' -Server "'+@servername+'" -Username '+@username+' -Password '+@password+ '
          | ConvertTo-Csv -NoTypeInformation 
          | Set-Content -Path '+@folderpath+'\'+@filename+' -Encoding UTF8'

调试时总是在 运行 之前打印你的 cmd,不要抑制输出。

SET @cmd = 'powershell.exe -noprofile -command - < '+@cmd

print @cmd

EXEC @return = xp_cmdshell @cmd
IF @return <> 0
BEGIN
    PRINT 'ERROR: '+@cmd
END
;