2012-12-20 51 views
2

要求:将大量数据(OU内的所有用户)从活动目录中抽取到数据库表中。SSIS脚本任务将数据从AD中抽取到数据库中

方法:我的任务是使用SSIS来执行此操作,因为还有其他项目需要作为标准ETL事件的相同隔夜任务的一部分来完成,因此这只是流程流程中的另一个步骤。

代码:

/* 
Microsoft SQL Server Integration Services Script Task 
Write scripts using Microsoft Visual C# 2008. 
The ScriptMain is the entry point class of the script. 
*/ 

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.DirectoryServices; 
using Microsoft.SqlServer.Dts.Runtime; 
using System.Windows.Forms; 

namespace ST_dc256a9b209442c7bc089d333507abeb.csproj 
{ 
    [System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")] 
    public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase 
    { 

     #region VSTA generated code 
     enum ScriptResults 
     { 
      Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success, 
      Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure 
     }; 
     #endregion 

     /* 
     The execution engine calls this method when the task executes. 
     To access the object model, use the Dts property. Connections, variables, events, 
     and logging features are available as members of the Dts property as shown in the following examples. 

     To reference a variable, call Dts.Variables["MyCaseSensitiveVariableName"].Value; 
     To post a log entry, call Dts.Log("This is my log text", 999, null); 
     To fire an event, call Dts.Events.FireInformation(99, "test", "hit the help message", "", 0, true); 

     To use the connections collection use something like the following: 
     ConnectionManager cm = Dts.Connections.Add("OLEDB"); 
     cm.ConnectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;Provider=SQLNCLI10;Integrated Security=SSPI;Auto Translate=False;"; 

     Before returning from this method, set the value of Dts.TaskResult to indicate success or failure. 

     To open Help, press F1. 
    */ 

     public void Main() 
     { 
     //Set up the AD connection; 
     using (DirectorySearcher ds = new DirectorySearcher()) 
      { 
      //Edit the filter for your purposes; 
      ds.Filter = "(&(objectClass=user)(|(sAMAccountName=A*)(sAMAccountName=D0*)))"; 
      ds.SearchScope = SearchScope.Subtree; 
      ds.PageSize = 1000; 
      //This will page through the records 1000 at a time; 

      //Set up SQL Connection 
      string sSqlConn = Dts.Variables["SqlConn"].Value.ToString(); 
      SqlConnection sqlConnection1 = new SqlConnection(sSqlConn); 
      SqlCommand cmd = new SqlCommand(); 
      SqlDataReader reader; 
      cmd.CommandType = CommandType.Text; 
      cmd.Connection = sqlConnection1; 

      //Read all records in AD that meet the search criteria into a Collection 
      using (SearchResultCollection src = ds.FindAll()) 
       { 
       //For each record object in the Collection, insert a record into the SQL table 
       foreach (SearchResult results in src) 
        { 
        string sAMAccountName = results.Properties["sAMAccountName"][0].ToString(); 
        //string objectCategory = results.Properties["objectCategory"][0].ToString(); 
        string objectSid = results.Properties["objectSid"][0].ToString(); 
        string givenName = results.Properties["givenName"][0].ToString(); 
        string lastName = results.Properties["sn"][0].ToString(); 
        string employeeID = results.Properties["employeeID"][0].ToString(); 
        string email = results.Properties["mail"][0].ToString(); 

        //Replace any single quotes in the string with two single quotes for sql INSERT statement 
        objectSid = objectSid.Replace("'", "''"); 
        givenName = givenName.Replace("'", "''"); 
        lastName = lastName.Replace("'", "''"); 
        employeeID = employeeID.Replace("'", "''"); 
        email = email.Replace("'", "''"); 

        sqlConnection1.Open(); 
        cmd.CommandText = "INSERT INTO ADImport (userName, objectSid, firstName, lastName, employeeNo, email) VALUES ('" + sAMAccountName + "','" + objectSid + "','" + givenName + "','" + lastName + "','" + employeeID + "','" + email + "')"; 
        reader = cmd.ExecuteReader(); 

        string propertyName = "Description"; //or whichever multi-value field you are importing 
        ResultPropertyValueCollection valueCollection = results.Properties[propertyName]; 

        //Iterate thru the collection for the user and insert each value from the multi-value field into a table 
        foreach (String sMultiValueField in valueCollection) 
         { 
         string sValue = sMultiValueField.Replace("'","''"); //Replace any single quotes with double quotes 
         //sqlConnection1.Open(); 
         cmd.CommandText = "INSERT INTO ADImport_Description (userName, objectSid, objectDescription) VALUES ('" + sAMAccountName + "','" + objectSid + "','" + sValue + "')"; 
         reader = cmd.ExecuteReader(); 
         //sqlConnection1.Close(); 
         } 
        sqlConnection1.Close(); 
        } 
       } 
      } 
      Dts.TaskResult = (int)ScriptResults.Success; 
     } 
    } 
} 

我想到了很多,你会认识到这一点为基本相同的代码从这个帖子从数据女王:http://dataqueen.unlimitedviz.com/2012/09/get-around-active-directory-paging-on-ssis-import/我已经适应我的目的,因为我跑与我自己编写的代码混淆了很多问题。

这一切都在一个脚本任务本身。是的,我已经在相关参考文献中添加了,所以他们在那里。

问题:当我运行在SSIS的脚本任务(自身,以避免干扰包的其它部分的任何机会),我得到:

Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. 
Parameter name: index 
at System.Collections.ArrayList.get_Item(Int32 index) 
at System.DirectoryServices.ResultPropertyValueCollection.get_Item(Int32 index) 
at ST_dc256a9b209442c7bc089d333507abeb.csproj.ScriptMain.Main() 

请,任何人,任何想法? ?????

+3

我的猜测是失败的行是'string employeeID = results.Properties [“employeeID”] [0] .ToString();'因为您很可能会得到像Service帐户那样没有定义employeeID的东西。将你的代码复制到一个合适的.NET项目中(我喜欢控制台),并通过deubgger找到行号。 – billinkc

+0

谢谢,会给它一个去 - 我有非常有限的工具,所以可能需要回家调试... :) – Elatesummer

+0

@billinkc谢谢 - 解决了一些问题,如果count> 0语句...如果你添加你的评论作为答案我会将其标记为已解决? – Elatesummer

回答

1

所有功劳归于@billinkc(billinkc - 如果你添加一个答案,我会接受它而不是这一个,但我不喜欢留下没有回答的问题,所以现在添加你的答案,因为你没有添加答案上周)

“我的猜测是不及格线串雇员= results.Properties [”雇员“] [0]的ToString();你很可能得到类似的东西,不会有服务帐户定义了一个employeeID,将你的代码复制到一个合适的.NET项目中(我喜欢控制台),并通过deubgger逐步找到行号 - billinkc“

相关问题