作为代理用户从存储过程执行SSIS包而不使用xp_cmdshell

时间:2014-12-17 21:42:08

标签: sql-server stored-procedures ssis impersonation sql-server-2014

我正在尝试通过存储过程运行SSIS包,但在尝试导入CSV时出现Access is denied错误。

我把包放在一个工作中并运行它,只要我使用代理帐户就可以工作。我正在尝试使用xp_cmdshell将该代理帐户复制到存储过程调用而不是。我还在Visual Studio中运行了这个包,它运行顺利。

我的SSIS包很简单:它从网络导入CSV文件,将数据转换为varchar,并将数据存储到表中。

即使我的系统管理员也无法成功运行存储过程。

我的存储过程如下所示:

ALTER PROCEDURE [dbo].[spImportFile] 
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @execution_id bigint
    EXEC SSISDB.CATALOG.create_execution
        @folder_name = 'folder_name',
        @project_name = 'project_name',
        @package_name = 'package_name.dtsx',
        @use32bitruntime = 1,
        @execution_id = @execution_id output

    EXEC SSISDB.CATALOG.start_execution @execution_id
END

我的问题是,如何在不使用xp_cmdshell的情况下以编程方式在此存储过程中使用代理用户?


更新

由于billinkc,我现在正试图冒充我的代理用户,但现在我在执行SSIS包时遇到了这个错误:

  

无法恢复当前的安全上下文。请切换到调用'Execute As'的原始数据库并再次尝试。

这是我改变的代码:

ALTER PROCEDURE [dbo].[spImportFile] 
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    EXECUTE AS LOGIN = 'domain\credentials'

    DECLARE @execution_id bigint
    EXEC SSISDB.CATALOG.create_execution
        @folder_name = 'folder_name',
        @project_name = 'project_name',
        @package_name = 'package_name.dtsx',
        @use32bitruntime = 1,
        @execution_id = @execution_id output

    EXEC SSISDB.CATALOG.start_execution @execution_id -- <<<< ERROR HERE!

    REVERT

END

通过查看我通常无法访问的系统表,我成功测试了EXECUTE AS LOGINREVERT而没有start_execution

2 个答案:

答案 0 :(得分:6)

我已经意识到,由于我要模仿用户并鼓励我使用某个作业,因此使用代理帐户在服务器上运行此SSIS包会更容易。

以下是包含运行作业的解决方案:

ALTER PROCEDURE [dbo].[spImportFile] 
    @intStatus int output
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    SELECT user_name() -- test before execute

    EXECUTE AS LOGIN = 'domain\credentials'

    SELECT user_name() -- test after execute

    -- Start job
    DECLARE @job_name VARCHAR(100) = 'JobName'
    EXEC msdb.dbo.sp_start_job @job_name = @job_name

    -- Wait for job to finish
    DECLARE @job_history_id AS INT = NULL
    DECLARE @intLimit AS INT = 10
    DECLARE @intAttempt AS INT = 1

    WHILE @intAttempt < @intLimit
    BEGIN
        SELECT TOP 1 @job_history_id = activity.job_history_id
        FROM msdb.dbo.sysjobs jobs
        INNER JOIN msdb.dbo.sysjobactivity activity ON activity.job_id = jobs.job_id
        WHERE jobs.name = @job_name
        ORDER BY activity.start_execution_date DESC

        IF @job_history_id IS NULL
        BEGIN
            WAITFOR DELAY '00:00:01'
            CONTINUE
        END
        ELSE
        BEGIN
            BREAK
        END

        SET @intAttempt = @intAttempt + 1
    END

    -- Check exit code
    SELECT @intStatus = history.run_status
    FROM msdb.dbo.sysjobhistory history
    WHERE history.instance_id = @job_history_id

    REVERT

    SELECT user_name() -- test after revert

END

此职位代码基于此问题,&#34; Executing SQL Server Agent Job from a stored procedure and returning job result&#34;


<强>首饰
我了解到您需要GRANT IMPERSONATE ON LOGIN::[domain\ProxyUser] to [domain\credentials] ALTER DATABASE database_name SET TRUSTWORTHY ON

sysadmin是需要实施dbo的另一个设置,此MSDN source有助于解释其用法。

<强>说明
此解决方案基于以下事实:我是数据库的sysadmin,我向我的Windows安全组授予了{{1}}个代理帐户模拟权限。我也在使用Windows身份验证。

我已更新问题,不限制最初处理此问题的任何人使用工作。如果有一个解决方案不需要工作,我将非常乐意看一看,甚至改变这个问题的公认解决方案。

答案 1 :(得分:1)

我从未在一组凭据上尝试过,但您可以查看EXECUTE AS

ALTER PROCEDURE [dbo].[spImportFile] 
WITH EXECUTE AS 'domain\credentials'
AS
BEGIN
    ...
END