You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需SQL Server代理作业,从C#以代理身份执行SSIS包

直接从C#以指定代理身份执行SSIS包的实用方案

刚好我之前处理过类似的场景,不想每次创建代理作业又要复用现有代理用户执行SSIS包?这里有几个经过验证的实操方案,帮你解决问题:

方案1:通过dtexec命令行+Windows凭据模拟

如果你的代理用户是Windows账户,这种方式最直接——在C#里模拟该账户身份,然后调用dtexec命令行工具执行包,相当于让包以代理用户的权限跑起来。

代码示例

using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;

// 封装Windows用户模拟的辅助类
public class ImpersonationHelper
{
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
        int dwLogonType, int dwLogonProvider, out IntPtr phToken);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public static WindowsImpersonationContext ImpersonateUser(string username, string domain, string password)
    {
        IntPtr token = IntPtr.Zero;
        try
        {
            // 9对应LOGON32_LOGON_NEW_CREDENTIALS,适合远程资源访问
            if (LogonUser(username, domain, password, 9, 0, out token))
            {
                WindowsIdentity identity = new WindowsIdentity(token);
                return identity.Impersonate();
            }
            else
            {
                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        finally
        {
            if (token != IntPtr.Zero)
                CloseHandle(token);
        }
    }
}

// 执行SSIS包的核心方法
public void RunSsisPackageAsProxy(string proxyUser, string proxyDomain, string proxyPwd, string packageFilePath)
{
    WindowsImpersonationContext impersonationCtx = null;
    try
    {
        // 切换到代理用户身份
        impersonationCtx = ImpersonationHelper.ImpersonateUser(proxyUser, proxyDomain, proxyPwd);

        // 注意:dtexec路径要根据你的SQL Server版本调整,比如150对应2019,140对应2017
        string dtexecPath = @"C:\Program Files\Microsoft SQL Server\150\DTS\Binn\dtexec.exe";
        // 可以添加变量、配置文件等参数,比如 /SET \Package.Variables[MyVar].Value;"123"
        string cmdArgs = $"/F \"{packageFilePath}\"";

        var startInfo = new ProcessStartInfo(dtexecPath, cmdArgs)
        {
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        };

        using (var process = Process.Start(startInfo))
        {
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();
            process.WaitForExit();

            if (process.ExitCode != 0)
            {
                throw new Exception($"包执行失败:{error}");
            }
            Console.WriteLine($"执行成功,输出:{output}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"出错了:{ex.Message}");
        throw;
    }
    finally
    {
        // 切回原用户身份
        impersonationCtx?.Undo();
    }
}

踩过的坑&注意事项

  • 一定要根据SQL Server版本调整dtexec的路径,不同版本的数字后缀不一样(比如2016是130)
  • 代理用户得有访问SSIS包所在路径的权限,还有执行包的权限
  • 密码别明文存!建议用DPAPI加密或者存到密钥管理服务里,比如Azure Key Vault

方案2:用SSIS Catalog存储过程(SQL Server 2012+适用)

如果你的包部署在SSIS Catalog(也就是SSISDB)里,直接调用系统存储过程就能指定代理用户执行,完全不用创建作业。

代码示例

using System.Data.SqlClient;

public void ExecuteSsisInCatalogAsProxy(string dbConnString, string folderName, string projectName, string packageName, string proxyUserName)
{
    using (var conn = new SqlConnection(dbConnString))
    {
        conn.Open();

        // 先拿到代理用户的ID(如果用代理ID的话)
        int proxyId = GetProxyAccountId(conn, proxyUserName);

        // 创建执行实例
        var createExecCmd = new SqlCommand("catalog.create_execution", conn)
        {
            CommandType = System.Data.CommandType.StoredProcedure
        };
        createExecCmd.Parameters.AddWithValue("@folder_name", folderName);
        createExecCmd.Parameters.AddWithValue("@project_name", projectName);
        createExecCmd.Parameters.AddWithValue("@package_name", packageName);
        createExecCmd.Parameters.AddWithValue("@reference_id", DBNull.Value); // 没有环境引用就传Null
        createExecCmd.Parameters.AddWithValue("@use32bitruntime", 0); // 按需调整,比如32位驱动就设为1
        var execIdParam = createExecCmd.Parameters.Add("@execution_id", System.Data.SqlDbType.BigInt);
        execIdParam.Direction = System.Data.ParameterDirection.Output;

        createExecCmd.ExecuteNonQuery();
        long executionId = (long)execIdParam.Value;

        // 设置执行上下文为代理用户
        var setProxyCmd = new SqlCommand("catalog.set_execution_property", conn)
        {
            CommandType = System.Data.CommandType.StoredProcedure
        };
        setProxyCmd.Parameters.AddWithValue("@execution_id", executionId);
        // 可以用LOGIN_NAME直接指定用户名,或者用AGENT_PROXY_ID指定代理ID
        setProxyCmd.Parameters.AddWithValue("@property_name", "LOGIN_NAME");
        setProxyCmd.Parameters.AddWithValue("@property_value", proxyUserName);

        setProxyCmd.ExecuteNonQuery();

        // 启动执行
        var startExecCmd = new SqlCommand("catalog.start_execution", conn)
        {
            CommandType = System.Data.CommandType.StoredProcedure
        };
        startExecCmd.Parameters.AddWithValue("@execution_id", executionId);
        startExecCmd.ExecuteNonQuery();

        Console.WriteLine($"包已启动,执行ID:{executionId}");
    }
}

// 从msdb获取代理账户ID
private int GetProxyAccountId(SqlConnection conn, string proxyName)
{
    var cmd = new SqlCommand("SELECT id FROM msdb.dbo.sysproxies WHERE name = @proxyName", conn);
    cmd.Parameters.AddWithValue("@proxyName", proxyName);
    var result = cmd.ExecuteScalar();
    if (result == null)
    {
        throw new Exception($"找不到代理账户:{proxyName}");
    }
    return (int)result;
}

注意事项

  • 连接SQL Server的账户得有SSIS Catalog的操作权限,比如加入ssis_admin角色
  • 如果用AGENT_PROXY_ID,要确保代理用户已经被授予执行SSIS包的权限(在SQL Server代理里配置)
  • 想查执行状态的话,可以调用catalog.get_execution_status存储过程

方案3:用SMO直接操作

通过SQL Server Management Objects(SMO)库,直接调用SSIS的管理API,这种方式更贴近SQL Server的原生管理逻辑。

代码示例

using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Smo.Agent;
using Microsoft.SqlServer.Management.IntegrationServices;

public void RunSsisWithSmoAsProxy(string serverName, string proxyUserName, string packageFullName)
{
    // 连接到目标SQL Server
    var server = new Server(serverName);
    var isService = new IntegrationServices(server);

    // 获取代理账户
    var proxy = server.JobServer.ProxyAccounts[proxyUserName];
    if (proxy == null)
    {
        throw new Exception($"代理账户 {proxyUserName} 不存在");
    }

    // 定位到SSIS Catalog里的包
    var catalog = isService.Catalogs["SSISDB"];
    var folder = catalog.Folders["你的文件夹名"];
    var project = folder.Projects["你的项目名"];
    var package = project.Packages["你的包名.dtsx"];

    // 以代理用户身份执行包
    var execution = package.Execute(false, null, proxy.Name);

    // 可选:等待执行完成
    while (!execution.Completed)
    {
        System.Threading.Thread.Sleep(1000);
        execution.Refresh();
    }

    if (execution.Status == OperationStatus.Succeeded)
    {
        Console.WriteLine("包执行成功!");
    }
    else
    {
        throw new Exception($"执行失败,状态:{execution.Status}");
    }
}

注意事项

  • 需要安装两个NuGet包:Microsoft.SqlServer.SqlManagementObjects和Microsoft.SqlServer.Management.IntegrationServices
  • 程序运行的账户得有访问SQL Server代理和SSIS Catalog的权限,不然会报错

内容的提问来源于stack exchange,提问作者Tyron78

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:44:14