SSIS script task to collect lineage IDs


I have an SSIS script task that collects extended error information.

The contents of the script are as follows:

/// <summary>
/// ScriptMain is the entry point class of the script.  Do not change the name, attributes,
/// or parent of this class.
/// </summary>

public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase

    Dictionary<string, string> lineageIds = null;

    public void Main()
        // Grab the executables so we have to something to iterate over, and initialize our lineageIDs list
        // Why the executables?  Well, SSIS won't let us store a reference to the Package itself...
        Dts.Variables["User::execsObj"].Value = ((Package)Dts.Variables["User::execsObj"].Parent).Executables;
        Dts.Variables["User::lineageIds"].Value = new Dictionary<string, string>();
        lineageIds = (Dictionary<string, string>)Dts.Variables["User::lineageIds"].Value;
        Executables execs = (Executables)Dts.Variables["User::execsObj"].Value;


        Dts.TaskResult = (int)ScriptResults.Success;

    private void ReadExecutables(Executables executables)
        foreach (Executable pkgExecutable in executables)
            if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.TaskHost)))
                TaskHost pkgExecTaskHost = (TaskHost)pkgExecutable;
                if (pkgExecTaskHost.CreationName.StartsWith("SSIS.Pipeline"))
            else if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.ForEachLoop)))
                // Recurse into FELCs

    private void ProcessDataFlowTask(TaskHost currentDataFlowTask)
        MainPipe currentDataFlow = (MainPipe)currentDataFlowTask.InnerObject;
        foreach (IDTSComponentMetaData100 currentComponent in currentDataFlow.ComponentMetaDataCollection)
            // Get the inputs in the component.
            foreach (IDTSInput100 currentInput in currentComponent.InputCollection)
                foreach (IDTSInputColumn100 currentInputColumn in currentInput.InputColumnCollection)
                    lineageIds.Add(currentDataFlowTask.ID.ToString() + currentInputColumn.ID, currentInputColumn.Name);

            // Get the outputs in the component.
            foreach (IDTSOutput100 currentOutput in currentComponent.OutputCollection)
                foreach (IDTSOutputColumn100 currentoutputColumn in currentOutput.OutputColumnCollection)
                    lineageIds.Add(currentDataFlowTask.ID.ToString() + currentoutputColumn.ID, currentoutputColumn.Name);

    enum ScriptResults
        Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
        Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure

This used to work correctly on SQL Server 2014. However since upgrading to SQL server 2017 the task gives the following error message on the line:

MainPipe currentDataFlow = (MainPipe)currentDataFlowTask.InnerObject;

An exception of type 'System.InvalidCastException' occurred in ST_47767930511349f4b94ba74c27240570 but was not handled in user code

Additional information: Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.SqlServer.Dts.Pipeline.Wrapper.MainPipe'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{6D3931AC-822D-414C-8F10-7447A54BA55C}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Has anybody else seen this since upgrading to SQL Server 2017?

asked on Stack Overflow Mar 21, 2019 by Giles Roberts • edited Mar 21, 2019 by Hadi

1 Answer


Turned out the Com object returned by currentDataFlowTask.InnerObject was coming from a newer version of Microsoft.SqlServer.DTSPipelineWrap.

To fix the issue I removed the reference to Microsoft.SqlServer.DTSPipelineWrap and replaced with version 14 of the same assembly.

Then I altered the following line:

MainPipe currentDataFlow = (MainPipe)currentDataFlowTask.InnerObject;


IDTSPipeline130 currentDataFlow = (IDTSPipeline130)currentDataFlowTask.InnerObject;
answered on Stack Overflow Mar 21, 2019 by Giles Roberts

User contributions licensed under CC BY-SA 3.0