<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule"><channel><title>Idea Excursion &#187; Microsoft</title> <atom:link href="http://www.ideaexcursion.com/category/microsoft/feed/" rel="self" type="application/rss+xml" /><link>http://www.ideaexcursion.com</link> <description>Technology Musings</description> <lastBuildDate>Wed, 18 Jan 2012 16:33:17 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <atom:link rel='hub' href='http://www.ideaexcursion.com/?pushpress=hub'/> <creativeCommons:license>http://creativecommons.org/licenses/by-sa/3.0/us/</creativeCommons:license> <item><title>Access system date in SSIS without a Script Task</title><link>http://www.ideaexcursion.com/2011/09/28/access-system-date-within-ssis-without-a-script-task/</link> <comments>http://www.ideaexcursion.com/2011/09/28/access-system-date-within-ssis-without-a-script-task/#comments</comments> <pubDate>Wed, 28 Sep 2011 18:53:26 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SSIS]]></category> <category><![CDATA[T-SQL]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1590</guid> <description><![CDATA[Set variables to contain the package start datetime with the time truncated, making it easier to compare dates directly.]]></description> <content:encoded><![CDATA[<p>In the world of <abbr title="Extract Transform Load">ETL</abbr>, it&#8217;s quite common to need to know the current date, especially without the time component. Because Script Tasks allows us to code up anything in .NET, it should be fairly obvious how to generate and expose the current date. for example:</p><div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">Dts<span style="color: #008000;">.</span><span style="color: #0000FF;">Variables</span><span style="color: #008000;">&#91;</span><span style="color: #666666;">&quot;TheCurrentDate&quot;</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">Value</span> <span style="color: #008000;">=</span> DateTime<span style="color: #008000;">.</span><span style="color: #0000FF;">Date</span><span style="color: #008000;">;</span></pre></div></div><p>That little snippet of code will store the current date into a variable named &#8220;TheCurrentDate&#8221;. This is straightforward and there&#8217;s absolutely nothing wrong with the approach, however, there&#8217;s a simpler way to fetch this information without the need of adding a whole control flow item for such a minute amount of work. It&#8217;s brilliantly simple, only requires the creation of a variable, and can be added in about 10 seconds:<br /> <span id="more-1590"></span></p><ol><li>Create new variable with Data Type = DateTime</li><ol><li>Set property EvaluateAsExpression = True</li><li>Set property Expression = <div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">DATEADD( <span style="color: #800000;">&quot;day&quot;</span>, DATEDIFF( <span style="color: #800000;">&quot;day&quot;</span>, (DT_DATE) <span style="color: #800000;">&quot;1900-01-01&quot;</span>, @[System::StartTime]  ) , (DT_DATE) <span style="color: #800000;">&quot;1900-01-01&quot;</span> )</pre></div></div></li></ol></ol><p>That&#8217;s it! The variable will contain the package start time with the time truncated, making it easier to compare dates directly. In fact, this method can be used to truncate the time portion of any DateTime Data Type. Simply replace @[System::StartTime] with another variable.</p><p>Want to know how it works? The inner DATEDIFF() function calculates the number of days since 1900. This value is supplied to the outer DATEADD() function, adding days forward from 1900, resulting in a DT_DBTIMESTAMP with the time rounded off. And we accomplished it with pure math—no messy string manipulation required! I borrowed the idea from the same expression in T-SQL: DATEADD(day, DATEDIFF(day, 0, getdate()), 0).</p><p>There&#8217;s one caveat to this: Because SSIS doesn&#8217;t have a native date-only variable type, the value technically contains the date at midnight. However, many tools—such as SQL Server—will implicitly convert to the requisite data type, making &#8220;2011-09-28 12:00:00 AM&#8221; equal to &#8220;2011-09-28&#8243;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2011/09/28/access-system-date-within-ssis-without-a-script-task/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Connecting to Oracle with SSIS 2008</title><link>http://www.ideaexcursion.com/2011/09/07/connecting-to-oracle-with-ssis-2008/</link> <comments>http://www.ideaexcursion.com/2011/09/07/connecting-to-oracle-with-ssis-2008/#comments</comments> <pubDate>Wed, 07 Sep 2011 21:44:22 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SSIS]]></category> <category><![CDATA[Oracle]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1571</guid> <description><![CDATA[Quickly configure a connection from SSIS to Oracle, optionally without TNSNAMES.ora, using the free Attunity Connector provided by Microsoft.]]></description> <content:encoded><![CDATA[<p>This isn&#8217;t my first adventure in connecting to Oracle from SQL Server. No, in fact, I wrote <a title="Connecting to Oracle from SQL Server" href="http://www.ideaexcursion.com/2009/01/05/connecting-to-oracle-from-sql-server/">a guide on that very topic</a> nearly 3 years ago. Unfortunately—as a technologist, but fortunately as a blogger—the times change as does the method for setting up the configuration. On the plus side, I&#8217;m much more confident in the setup and am convinced that it&#8217;s easier than ever to connect SSIS to Oracle. Without further adieu, let&#8217;s get started by downloading and installing a couple of necessary components:<br /> <span id="more-1571"></span></p><ul><li><a title="Microsoft Connectors Version 1.1 for Oracle and Teradata by Attunity" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6732934c-2eea-4a7f-85a8-8ba102e6b631">Attunity SSIS Oracle Connector v1.1</a></li><ul><li>After installation, you’ll need to enable the menu items in the Data Flow Source &amp; Destination</li><ul><li>Create Data Flow Task</li><li>Switch to Data Flow</li><li>Pull the Toolbox out</li><li>Right-click&rarr;Choose items…</li><li>Activate the SSIS Data Flow Items tab</li><li>Enable &#8220;Oracle Destination&#8221; and &#8220;Oracle Source&#8221;</li></ul></ul><li><a title="Oracle Database Instant Client" href="http://www.oracle.com/technetwork/database/features/instant-client/index-100365.html">Oracle Instant Client</a> Basic package</li><ul><li>Download and extract both 64-bit and 32-bit versions if you’re using a 64-bit OS</li><ul><li>Only need the 32-bit version if installing on 32-bit OS</li></ul><li>Installation location is up to you, but you’ll need to note it later. This tutorial assumes C:\oracle\ as the base location.</li><ul><li>For example, install the 64-bit package at &#8220;C:\oracle\instantclient_x64_11_2&#8243; and the 32-bit package at &#8220;C:\oracle\instantclient_x86_11_2&#8243;</li></ul></ul></ul><p>Once you have all the items installed, you’ll need to add a couple of registry keys with regedit so that the SSIS connector can find the Oracle Instant Client. Create the necessary keys and string values below where they don’t exist, updating files paths to point to where you extracted the items above (again, C:\oracle\ is assumed for this tutorial):</p><ul><li> [HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]</li><ul><li>New&rarr;String Value&rarr;Name = TNS_ADMIN&rarr;Value = C:\oracle\tnsnames.ora</li><li>New&rarr;String Value&rarr;Name = ORACLE_HOME&rarr;Value</li><ul><li>For 64-bit OS: C:\oracle\instantclient_x64_11_2</li><li>For 32-bit OS: C:\oracle\instantclient_x32_11_2</li></ul></ul><li>[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE] <strong>(64-bit OS only)</strong></li><ul><li>New&rarr;String Value&rarr;Name = TNS_ADMIN&rarr;Value = C:\oracle\tnsnames.ora</li><li>New&rarr;String Value&rarr;Name = ORACLE_HOME&rarr;Value = C:\oracle\instantclient_x86_11_2</li></ul></ul><div><p>If you prefer, simply save the following text as a file with extension .reg and run it.</p><p><strong>64-bit OS:</strong></p><div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">Windows Registry Editor Version 5.00
&nbsp;
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE]
&quot;TNS_ADMIN&quot;=&quot;C:\\oracle\\tnsnames.ora&quot;
&quot;ORACLE_HOME&quot;=&quot;C:\\oracle\\instantclient_x32_11_2&quot;
&nbsp;
[HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]
&quot;TNS_ADMIN&quot;=&quot;C:\\oracle\\tnsnames.ora&quot;
&quot;ORACLE_HOME&quot;=&quot;C:\\oracle\\instantclient_x64_11_2&quot;</pre></div></div><p><strong>32-bit OS:</strong></p><div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">Windows Registry Editor Version 5.00
&nbsp;
[HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE]
&quot;TNS_ADMIN&quot;=&quot;C:\\oracle\\tnsnames.ora&quot;
&quot;ORACLE_HOME&quot;=&quot;C:\\oracle\\instantclient_x32_11_2&quot;</pre></div></div></div><p>This setup allows you the choice of either using the names defined in TNSNAMES.ORA at the location specified in the registry above OR specifying the server inline in the format of &lt;server.name.trb:port/service&gt;. For example: &lt;servername.path.to.tld:1521/ORA10DEV&gt; (without the angle brackets). That&#8217;s really it! The process is much more streamlined than it was just a short while ago. Two installations and a couple regedit tweaks and you should be all set!</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2011/09/07/connecting-to-oracle-with-ssis-2008/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Set Permissions Across SQL Server Database Instances</title><link>http://www.ideaexcursion.com/2011/05/31/setting-user-permissions-across-database-instances/</link> <comments>http://www.ideaexcursion.com/2011/05/31/setting-user-permissions-across-database-instances/#comments</comments> <pubDate>Tue, 31 May 2011 20:35:17 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SQL Server]]></category> <category><![CDATA[T-SQL]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1567</guid> <description><![CDATA[Code to streamline adding and fixing roles for users, groups, and principals across multiple databases on a single SQL Server instance.]]></description> <content:encoded><![CDATA[<p>As a followup to my post on <a title="SQL Server Principals &amp; Roles Permission Audit" href="http://www.ideaexcursion.com/2011/04/11/sql-server-principals-roles-permission-audit/">SQL Server Principals &amp; Roles Permission Audit</a>, it&#8217;s completely expected that you may want to act on the results of that audit. Specifically, let&#8217;s say you want to organize users into groups and enforce group permissions across the instance. In a particular scenario at my company, we are constantly refreshing databases down from production, which has a nasty side-effect of destroying the finely-tuned permissions we&#8217;ve carefully set in place. What made the most sense to reduce the friction this would cause was to reset the permissions via a job. This allows us to schedule it nightly, fixing any broken permissions, but also makes it easy to fire on demand, should needs dictate. Of course, it would be easiest if this were all contained in a stored procedure, but how do we juggle all these users and groups when you&#8217;re hosting 50 databases?</p><p>What made sense for us was to be able to supply the name of a principal, a &#8220;like name&#8221; for the database, and the role that they should have. What the &#8220;like name&#8221; allows us to do is apply a permission to a series of databases based on name. For example: ideaexcursion1, ideaexcursion2, ideaexcursion3 can all be set by supplying the paramater ideaexcursion%. This increases the complexity by forcing us to use a cursor in the proc, but reduces the number of actions we need to manage.</p><div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">exec</span> dbo.<span style="color: #202020;">pr_SetGroupPermissions</span>
      @principal <span style="color: #808080;">=</span> <span style="color: #FF0000;">'domain\principalname'</span>
    , @db_likename <span style="color: #FF0000;">'ideaexcursion%'</span>
    , @addrole <span style="color: #FF0000;">'db_owner'</span></pre></div></div><p><span id="more-1567"></span><br /> This snippet will—as you&#8217;ll soon see—give domain\principalname the db_owner role in any databases that match LIKE ideaexcursion%. Here&#8217;s the magic behind the stored procedure:</p><div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">create</span> <span style="color: #0000FF;">proc</span> dbo.<span style="color: #202020;">pr_SetGroupPermissions</span> @principal sysname, @db_likename sysname, @addrole sysname, @printonly <span style="color: #0000FF;">bit</span> <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
<span style="color: #0000FF;">as</span>
<span style="color: #0000FF;">declare</span>
	  @<span style="color: #0000FF;">database</span> sysname
	, @cmd <span style="color: #0000FF;">nvarchar</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">max</span><span style="color: #808080;">&#41;</span>
&nbsp;
<span style="color: #0000FF;">declare</span> csr_dbname <span style="color: #0000FF;">cursor</span> <span style="color: #0000FF;">for</span>
<span style="color: #0000FF;">select</span> name <span style="color: #0000FF;">from</span> sys.<span style="color: #202020;">databases</span> <span style="color: #0000FF;">where</span> <span style="color: #0000FF;">state</span> <span style="color: #808080;">=</span> <span style="color: #000;">0</span> and name like @db_likename
&nbsp;
<span style="color: #0000FF;">open</span> csr_dbname
&nbsp;
<span style="color: #0000FF;">fetch</span> <span style="color: #0000FF;">next</span> <span style="color: #0000FF;">from</span> csr_dbname
<span style="color: #0000FF;">into</span> @<span style="color: #0000FF;">database</span>
&nbsp;
<span style="color: #0000FF;">while</span> <span style="color: #FF00FF;">@@fetch_status</span> <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
<span style="color: #0000FF;">begin</span>
&nbsp;
	<span style="color: #0000FF;">set</span> @cmd <span style="color: #808080;">=</span> <span style="color: #FF0000;">'
USE '</span><span style="color: #808080;">+</span><span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>@<span style="color: #0000FF;">database</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">+</span><span style="color: #FF0000;">'
&nbsp;
IF EXISTS (SELECT * FROM sys.server_principals WHERE name = N'</span><span style="color: #FF0000;">''</span><span style="color: #808080;">+</span>@principal<span style="color: #808080;">+</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">')
BEGIN
	IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = N'</span><span style="color: #FF0000;">''</span><span style="color: #808080;">+</span>@principal<span style="color: #808080;">+</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">')
		CREATE USER '</span><span style="color: #808080;">+</span><span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>@principal<span style="color: #808080;">&#41;</span><span style="color: #808080;">+</span><span style="color: #FF0000;">' FOR LOGIN '</span><span style="color: #808080;">+</span><span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>@principal<span style="color: #808080;">&#41;</span><span style="color: #808080;">+</span><span style="color: #FF0000;">'
	ELSE
		ALTER USER '</span><span style="color: #808080;">+</span><span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>@principal<span style="color: #808080;">&#41;</span><span style="color: #808080;">+</span><span style="color: #FF0000;">' WITH LOGIN = '</span><span style="color: #808080;">+</span><span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>@principal<span style="color: #808080;">&#41;</span><span style="color: #808080;">+</span><span style="color: #FF0000;">'
&nbsp;
	EXEC dbo.sp_addrolemember N'</span><span style="color: #FF0000;">''</span><span style="color: #808080;">+</span>@addrole<span style="color: #808080;">+</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">', N'</span><span style="color: #FF0000;">''</span><span style="color: #808080;">+</span>@principal<span style="color: #808080;">+</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">'
END
'</span>
&nbsp;
	<span style="color: #0000FF;">print</span> @cmd
	<span style="color: #0000FF;">if</span> @printonly <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
		<span style="color: #0000FF;">exec</span><span style="color: #808080;">&#40;</span>@cmd<span style="color: #808080;">&#41;</span>
&nbsp;
	<span style="color: #0000FF;">fetch</span> <span style="color: #0000FF;">next</span> <span style="color: #0000FF;">from</span> csr_dbname
	<span style="color: #0000FF;">into</span> @<span style="color: #0000FF;">database</span>
&nbsp;
<span style="color: #0000FF;">end</span>
&nbsp;
<span style="color: #0000FF;">close</span> csr_dbname
<span style="color: #0000FF;">deallocate</span> csr_dbname</pre></td></tr></table></div><p>And here&#8217;s a few notes on what the code does:</p><ul><li>Line 1: Parameter declaration. Notice that there is an optional @printonly param if you&#8217;d like to see the resulting code, but not execute it</li><li>Line 7-8: Set up the cursor. On line 8 is the trick that allows us to use a &#8220;like name&#8221; to simplify the rules. Also, note that we check for &#8220;state = 0&#8243; in the predicate, which corresponds to those with a state of ONLINE. If we didn&#8217;t check this, we would potentially attempt to execute commands against databases in RESTORING, RECOVERING, RECOVERY_PENDING, SUSPECT, EMERGENCY, or OFFLINE states</li><li>Line 18-30: The main code which will be evaluated and executed. There are several parts to it to accommodate a variety of situations:<ul><li>Line 19: Switch context to the correct database, since we&#8217;re executing within the confides of dynamic SQL. Also, the name is qualified with quotename(), which means that it should not be qualified when being passed in</li><li>Line 21: Validate that the user or group exists, otherwise we will get an error when trying to set it. Since we&#8217;re concerning ourselves with permission to a database, and not an instance, we don&#8217;t bother creating a user if it doesn&#8217;t exist. This is probably smart from a security perspective</li><li>Line 23-24: Check if the principal exists within the specific database. If not, create the user</li><li>Line 26: If the user already exists, fix any mismatched SIDswith ALTER USER. This is the preferred way to fix mismatched a mismatched SIDwhich was previously handled by sp_change_users_login, which has since been deprecated</li><li>Line 28: Assume database login is not valid and add the user or group to the specified role</li></ul></li><li>Line 32:  Always print the commands to be executed</li><li>Line 33-34: Execute the code, unless the @printonly parameter has been specified</li></ul><p>There you have it. A proc that grants specific roles to a principal across your entire database instance.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2011/05/31/setting-user-permissions-across-database-instances/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>SQL Server Principals &amp; Roles Permission Audit</title><link>http://www.ideaexcursion.com/2011/04/11/sql-server-principals-roles-permission-audit/</link> <comments>http://www.ideaexcursion.com/2011/04/11/sql-server-principals-roles-permission-audit/#comments</comments> <pubDate>Mon, 11 Apr 2011 20:50:06 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SQL Server]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1561</guid> <description><![CDATA[If you largely manage users by way of roles, SQL exposes this relationship in a single view, which can produce a report of what principal is part of what role.]]></description> <content:encoded><![CDATA[<p>Thanks to the expansion of catalog views in SQL Server 2005, managing users and permissions has become much easier. Specifically, if you largely manage users by way of roles, rather than per-object permissions, SQL exposes this relationship in a single view, which can produce a report of what principal is part of what role. Check out the query:</p><div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">select</span> <span style="color: #FF00FF;">db_name</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span> <span style="color: #808080;">&#91;</span>database_name<span style="color: #808080;">&#93;</span>
	, dbpm.<span style="color: #202020;">name</span>, dbpm.<span style="color: #202020;">type_desc</span>, dbpm.<span style="color: #202020;">create_date</span>, dbpm.<span style="color: #202020;">modify_date</span>
	, dbpr.<span style="color: #202020;">name</span>, dbpr.<span style="color: #202020;">type_desc</span>
<span style="color: #0000FF;">from</span> sys.<span style="color: #202020;">database_role_members</span> dbrm
<span style="color: #0000FF;">left</span> join sys.<span style="color: #202020;">database_principals</span> dbpm
	<span style="color: #0000FF;">on</span> dbrm.<span style="color: #202020;">member_principal_id</span> <span style="color: #808080;">=</span> dbpm.<span style="color: #202020;">principal_id</span>
<span style="color: #0000FF;">left</span> join sys.<span style="color: #202020;">database_principals</span> dbpr
	<span style="color: #0000FF;">on</span> dbrm.<span style="color: #202020;">role_principal_id</span> <span style="color: #808080;">=</span> dbpr.<span style="color: #202020;">principal_id</span>
<span style="color: #0000FF;">order</span> <span style="color: #0000FF;">by</span>
	dbpm.<span style="color: #202020;">name</span>, dbpr.<span style="color: #202020;">name</span></pre></div></div><p>This is handily fantastic and works well when you&#8217;re just managing access to a single database. What about if you want to audit logins for the entirety of the database instance? Unfortunately, we have to rely on database cursors to build a query and execute it. The concept is easy, but the details can be a little tricky to manage. Here&#8217;s what I came up with:<br /> <span id="more-1561"></span></p><div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">declare</span> @cmd <span style="color: #0000FF;">nvarchar</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">max</span><span style="color: #808080;">&#41;</span> <span style="color: #808080;">=</span> <span style="color: #FF0000;">''</span>, @dbname sysname
&nbsp;
<span style="color: #0000FF;">declare</span> csr_dbname <span style="color: #0000FF;">cursor</span> <span style="color: #0000FF;">for</span>
<span style="color: #0000FF;">select</span> <span style="color: #FF00FF;">quotename</span><span style="color: #808080;">&#40;</span>name<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">from</span> sys.<span style="color: #202020;">databases</span> <span style="color: #0000FF;">where</span> <span style="color: #0000FF;">state</span> <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
&nbsp;
<span style="color: #0000FF;">open</span> csr_dbname
&nbsp;
<span style="color: #0000FF;">fetch</span> <span style="color: #0000FF;">next</span> <span style="color: #0000FF;">from</span> csr_dbname
<span style="color: #0000FF;">into</span> @dbname
&nbsp;
<span style="color: #0000FF;">while</span> <span style="color: #FF00FF;">@@fetch_status</span> <span style="color: #808080;">=</span> <span style="color: #000;">0</span>
<span style="color: #0000FF;">begin</span>
	<span style="color: #0000FF;">set</span> @cmd <span style="color: #808080;">=</span> @cmd <span style="color: #808080;">+</span> <span style="color: #FF0000;">'
select '</span><span style="color: #FF0000;">''</span><span style="color: #808080;">+</span>@dbname<span style="color: #808080;">+</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">' [database_name]
, dbpm.name [principal_name], dbpm.type_desc [principal_type], dbpm.create_date [principal_create], dbpm.modify_date [principal_modify]
, dbpr.name [role_name], dbpr.type_desc [role_type]
from '</span><span style="color: #808080;">+</span>@dbname<span style="color: #808080;">+</span><span style="color: #FF0000;">'.sys.database_role_members dbrm
left join '</span><span style="color: #808080;">+</span>@dbname<span style="color: #808080;">+</span><span style="color: #FF0000;">'.sys.database_principals dbpm
	on dbrm.member_principal_id = dbpm.principal_id
left join '</span><span style="color: #808080;">+</span>@dbname<span style="color: #808080;">+</span><span style="color: #FF0000;">'.sys.database_principals dbpr
	on dbrm.role_principal_id = dbpr.principal_id
	union all
	'</span>
&nbsp;
	<span style="color: #0000FF;">fetch</span> <span style="color: #0000FF;">next</span> <span style="color: #0000FF;">from</span> csr_dbname
	<span style="color: #0000FF;">into</span> @dbname
&nbsp;
<span style="color: #0000FF;">end</span>
&nbsp;
<span style="color: #0000FF;">close</span> csr_dbname
<span style="color: #0000FF;">deallocate</span> csr_dbname
&nbsp;
<span style="color: #0000FF;">set</span> @cmd <span style="color: #808080;">=</span> <span style="color: #0000FF;">left</span><span style="color: #808080;">&#40;</span>@cmd, <span style="color: #FF00FF;">len</span><span style="color: #808080;">&#40;</span>@cmd<span style="color: #808080;">&#41;</span> <span style="color: #808080;">-</span> <span style="color: #000;">12</span><span style="color: #808080;">&#41;</span>
&nbsp;
<span style="color: #0000FF;">exec</span><span style="color: #808080;">&#40;</span>@cmd<span style="color: #808080;">&#41;</span></pre></div></div><p>There are a couple hacky things in this solution that could be factored out, but I&#8217;m keeping it simple. Here&#8217;s the walkthrough:</p><ul><li>Line 1: Declare and initialize necessary variables. Note that we&#8217;re combining declaration and initialization in a single step. If you&#8217;re not using SQL Server 2008, you&#8217;ll have to separate the initialization with a distinct &#8220;set @cmd = &#8221;&#8221; command</li><li>Line 3-4: Declare the query which defines the cursor. On line 4, we limit state = 0, because otherwise we might get databases in restoring or offline mode. Additionally, QUOTENAME() is used to ensure the input is sanitized for string concatenation. If you wanted to limit the scope of your databases, do it here.</li><li>Line 6-12: Standard cursor setup</li><li>Line 13-23: Build the query we&#8217;ll eventually use to scan all databases. We inject the database name from the cursor into the query to three-part qualify it, effectively neutralizing the current database context. Also, there&#8217;s a &#8220;union all&#8221; at the end that we&#8217;ll need to take care of later on</li><li>Line 25-31: Standard cursor tear-down</li><li>Line 33: Chuck the last &#8220;union all&#8221; from the query, lest it be dangling and we receive a parse error. If we were targeting re-usability, it would be smart to put the &#8220;union all&#8221; in a separate variable, rather than calculating the length of a literal</li><li>Line 35: Execute the  query. We could optionally print the results here, but they&#8217;re typically longer than what Management Studio will display before truncating</li></ul><p>It&#8217;s all quite simple and easy to toss into a stored procedure if you want to audit on a regular basis. Setting up a SQL Server Agent job to run monthly and return the results in an email would be straightforward enough. One of the issues I ran into and did not address was the sorting, which you may have noticed is absent in the extended script. This could be rectified by using &#8220;exec insert&#8221; notation, thought the results aren&#8217;t always dependable.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2011/04/11/sql-server-principals-roles-permission-audit/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>New Office Outlook 2010 Data File Menu Item</title><link>http://www.ideaexcursion.com/2011/01/05/new-office-outlook-2010-data-file-menu-item/</link> <comments>http://www.ideaexcursion.com/2011/01/05/new-office-outlook-2010-data-file-menu-item/#comments</comments> <pubDate>Wed, 05 Jan 2011 17:59:52 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[Microsoft]]></category> <category><![CDATA[quickie]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1554</guid> <description><![CDATA[How to access Office Outlook 2010's "Outlook Data File…" menu item.]]></description> <content:encoded><![CDATA[<p>Just a quick note on how to create a new Outlook data file. In Office 2010, Outlook received a ribbon revamp, moving several common menu items around. For Outlook 2007 and earlier, you can locate the appropriate option under File?Data Files. In Outlook 2010, create a new data file by drilling down through the &#8220;New Items&#8221; button on the Home tab of the ribbon. If you&#8217;re more visually inclined, here&#8217;s an image to help you locate the menu item:</p><p><span id="more-1554"></span></p><p><a href="http://static.ideaexcursion.com/wp-content/uploads/2011/01/NewOutlookDataFile.png"><img class="alignnone size-full wp-image-1555" title="New Data File Outlook 2010" src="http://static.ideaexcursion.com/wp-content/uploads/2011/01/NewOutlookDataFile.png" alt="Menu Drilldown for New Data File in Outlook 2010" width="498" height="460" /></a></p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2011/01/05/new-office-outlook-2010-data-file-menu-item/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Cache multiple values in a Map Container for fast in-memory lookup</title><link>http://www.ideaexcursion.com/2010/06/29/cache-multiple-values-in-a-map-container-for-fast-in-memory-lookup/</link> <comments>http://www.ideaexcursion.com/2010/06/29/cache-multiple-values-in-a-map-container-for-fast-in-memory-lookup/#comments</comments> <pubDate>Tue, 29 Jun 2010 21:24:15 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[Dynamics AX]]></category> <category><![CDATA[Dynamics AX 2009]]></category> <category><![CDATA[X++]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1517</guid> <description><![CDATA[Use this technique to reduce repeated trips to tables to lookup record details. Instead, cache the information once and reap speed benefits throughout your code]]></description> <content:encoded><![CDATA[<p>And thus begins my foray in to X++ development for Dynamics AX 2009. Here&#8217;s a proof of concept Job that I created to stuff multiple values into a Map using a Container. This allows me to lookup a few customer details without repeatedly making trips back to CustTable.</p><div class="wp_syntax"><div class="code"><pre class="xpp" style="font-family:monospace;"><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> MapContainerTest<span style="color: #000000;">&#40;</span>Args _args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    Map                     custNotesMap;
    <span style="color: #0000ff;">Container</span>               custContainer;
    CustTable               custTable;
    SalesSourceSystemId     admarcSystemId <span style="color: #00007f;">=</span> <span style="color: #ff0000;">&quot;DPRADM&quot;</span>;
    <span style="color: #0000ff;">Container</span>               conCustDetails;
    <span style="color: #0000ff;">str</span>                     admarcAccountId <span style="color: #00007f;">=</span> <span style="color: #ff0000;">&quot;000123456&quot;</span>;
    ;
&nbsp;
    custNotesMap <span style="color: #00007f;">=</span> <span style="color: #0000ff;">new</span> Map<span style="color: #000000;">&#40;</span>Types<span style="color: #00007f;">::</span><span style="color: #000000;">String</span><span style="color: #00007f;">,</span> Types<span style="color: #00007f;">::</span><span style="color: #0000ff;">Container</span><span style="color: #000000;">&#41;</span>;
    <span style="color: #0000ff;">while</span> <span style="color: #0000ff;">select</span> AdmarcAccountId<span style="color: #00007f;">,</span> RecId<span style="color: #00007f;">,</span> TableId<span style="color: #00007f;">,</span> dataAreaId<span style="color: #00007f;">,</span> PartyId <span style="color: #0000ff;">from</span> custTable <span style="color: #0000ff;">where</span> custTable.<span style="color: #000000;">AdmarcSystemId</span> <span style="color: #00007f;">==</span> admarcSystemId
    <span style="color: #000000;">&#123;</span>
        custContainer <span style="color: #00007f;">=</span> <span style="color: #0000ff;">conNull</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;
        custContainer <span style="color: #00007f;">=</span> <span style="color: #000000;">&#91;</span>custTable.<span style="color: #000000;">RecId</span><span style="color: #00007f;">,</span> custTable.<span style="color: #000000;">TableId</span><span style="color: #00007f;">,</span> custTable.<span style="color: #000000;">dataAreaId</span><span style="color: #00007f;">,</span> custTable.<span style="color: #000000;">PartyId</span><span style="color: #000000;">&#93;</span>;
&nbsp;
        custNotesMap.<span style="color: #000000;">insert</span><span style="color: #000000;">&#40;</span>custTable.<span style="color: #000000;">AdmarcAccountId</span><span style="color: #00007f;">,</span> custContainer<span style="color: #000000;">&#41;</span>;
    <span style="color: #000000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>custNotesMap.<span style="color: #0000ff;">exists</span><span style="color: #000000;">&#40;</span>admarcAccountId<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
        conCustDetails <span style="color: #00007f;">=</span> custNotesMap.<span style="color: #000000;">lookup</span><span style="color: #000000;">&#40;</span>admarcAccountId<span style="color: #000000;">&#41;</span>;
    <span style="color: #0000ff;">else</span>
        error<span style="color: #000000;">&#40;</span><span style="color: #ff0000;">&quot;Customer not found.&quot;</span><span style="color: #000000;">&#41;</span>;
&nbsp;
    info<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">strfmt</span><span style="color: #000000;">&#40;</span><span style="color: #ff0000;">&quot;RecId: %1&quot;</span><span style="color: #00007f;">,</span> <span style="color: #0000ff;">conpeek</span><span style="color: #000000;">&#40;</span>conCustDetails<span style="color: #00007f;">,</span> <span style="color: #000000;">1</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
    info<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">strfmt</span><span style="color: #000000;">&#40;</span><span style="color: #ff0000;">&quot;TableId: %1&quot;</span><span style="color: #00007f;">,</span> <span style="color: #0000ff;">conpeek</span><span style="color: #000000;">&#40;</span>conCustDetails<span style="color: #00007f;">,</span> <span style="color: #000000;">2</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
    info<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">strfmt</span><span style="color: #000000;">&#40;</span><span style="color: #ff0000;">&quot;dataAreaId: %1&quot;</span><span style="color: #00007f;">,</span> <span style="color: #0000ff;">conpeek</span><span style="color: #000000;">&#40;</span>conCustDetails<span style="color: #00007f;">,</span> <span style="color: #000000;">3</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
    info<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">strfmt</span><span style="color: #000000;">&#40;</span><span style="color: #ff0000;">&quot;PartyId: %1&quot;</span><span style="color: #00007f;">,</span> <span style="color: #0000ff;">conpeek</span><span style="color: #000000;">&#40;</span>conCustDetails<span style="color: #00007f;">,</span> <span style="color: #000000;">4</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;
<span style="color: #000000;">&#125;</span></pre></div></div><p>In fact, it&#8217;s pretty fast and I&#8217;m using similar caching technique all over the place to speed up large jobs.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2010/06/29/cache-multiple-values-in-a-map-container-for-fast-in-memory-lookup/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Default column value to identity of different column</title><link>http://www.ideaexcursion.com/2010/04/19/default-column-value-to-identity-of-different-column/</link> <comments>http://www.ideaexcursion.com/2010/04/19/default-column-value-to-identity-of-different-column/#comments</comments> <pubDate>Mon, 19 Apr 2010 21:09:36 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SQL Server]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1507</guid> <description><![CDATA[Given a table with one column as an identity, how you default another column to the identity of the first, while retaining the ability to change later]]></description> <content:encoded><![CDATA[<p>Thanks to my friend Paul Mayle for putting this one out there:</p><blockquote><p>Given a table with columns:<br /> A: int, primary key, identity<br /> B: int, not null</p><p>How can I set a default for column B to be the value in column A?</p></blockquote><p>This is an interesting problem on a couple levels. First, a computed column won&#8217;t work, because we need the ability to arbitrarily update column B. We could program a trigger, but I prefer to avoid them when possible. Preferably, we could actualize the purpose of the DEFAULT option. Unfortunately, this isn&#8217;t immediately an apparent choice because SQL Server doesn&#8217;t allow you to reference a column in a DEFAULT specification. In fact, according to <abbr title="Books Online">BOL</abbr>, &#8220;Only a constant value, such as a character string; a scalar function (either a  system, user-defined, or CLR function); or NULL can be used as a default.&#8221;<br /> <span id="more-1507"></span><br /> Fortunately, the column which we&#8217;re trying to set a default from had an identity property, and system functions dealing with identity values is the key to using the DEFAULT specification. First, a little code:</p><div class="wp_syntax"><div class="code"><pre class="tsql" style="font-family:monospace;"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">TABLE</span> dbo.<span style="color: #202020;">IdentDefault</span>
<span style="color: #808080;">&#40;</span>
	A <span style="color: #0000FF;">int</span> <span style="color: #808080;">NOT</span> <span style="color: #808080;">NULL</span> <span style="color: #0000FF;">IDENTITY</span> <span style="color: #808080;">&#40;</span><span style="color: #000;">1</span>, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">PRIMARY</span> <span style="color: #0000FF;">KEY</span>,
	B <span style="color: #0000FF;">int</span> <span style="color: #808080;">NOT</span> <span style="color: #808080;">NULL</span> <span style="color: #0000FF;">DEFAULT</span> <span style="color: #FF00FF;">SCOPE_IDENTITY</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span>
<span style="color: #808080;">&#41;</span>
&nbsp;
<span style="color: #0000FF;">INSERT</span> <span style="color: #0000FF;">INTO</span> dbo.<span style="color: #202020;">IdentDefault</span> <span style="color: #0000FF;">DEFAULT</span> <span style="color: #0000FF;">VALUES</span>
<span style="color: #0000FF;">INSERT</span> <span style="color: #0000FF;">INTO</span> dbo.<span style="color: #202020;">IdentDefault</span> <span style="color: #0000FF;">DEFAULT</span> <span style="color: #0000FF;">VALUES</span>
<span style="color: #0000FF;">INSERT</span> <span style="color: #0000FF;">INTO</span> dbo.<span style="color: #202020;">IdentDefault</span> <span style="color: #0000FF;">DEFAULT</span> <span style="color: #0000FF;">VALUES</span>
&nbsp;
<span style="color: #0000FF;">UPDATE</span> dbo.<span style="color: #202020;">IdentDefault</span> <span style="color: #0000FF;">SET</span> B <span style="color: #808080;">=</span> <span style="color: #000;">10</span> <span style="color: #0000FF;">WHERE</span> A <span style="color: #808080;">=</span> <span style="color: #000;">1</span>
&nbsp;
<span style="color: #0000FF;">SELECT</span> <span style="color: #808080;">*</span> <span style="color: #0000FF;">FROM</span> dbo.<span style="color: #202020;">IdentDefault</span></pre></div></div><p>And the result:</p><div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">A           B
----------- -----------
1           10
2           2
3           3</pre></div></div><p>As you can see from the above result set, column B defaults to whatever column A contains, yet we can still update column B to whatever value necessary.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2010/04/19/default-column-value-to-identity-of-different-column/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Import Excel 2007 with SQL Server Import and Export Wizard</title><link>http://www.ideaexcursion.com/2010/01/06/import-excel-2007-with-sql-server-import-and-export-wizard/</link> <comments>http://www.ideaexcursion.com/2010/01/06/import-excel-2007-with-sql-server-import-and-export-wizard/#comments</comments> <pubDate>Wed, 06 Jan 2010 15:38:02 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SQL Server]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1466</guid> <description><![CDATA[Neither SQL Server 2008 nor Office 2007 install Microsoft.ACE.OLEDB.12.0 providers. With a small tweak, we can enable connections to Excel and Access 2007.]]></description> <content:encoded><![CDATA[<p>If you need to pull in data from an external source ad hoc, using <abbr title="SQL Server Integration Services">SSIS</abbr> is often overkill. Instead, SQL Server Import and Export Wizard (called &#8220;Import and Export Data&#8221; in the Start Menu, but DTSWizard.exe in the filesystem) usually does a good job. This is especially great way to pull in data from users, which typically comes in the form of an Excel attachment. Unfortunately, the providers to import from the newer Office 2007 and 2010 XLSX  file format (also referred to as &#8220;Open Office XML&#8221;) are not available by default and will likely result in a &#8220;Microsoft.ACE.OLEDB.12.0 Provider is not registered&#8221; error. The fix is as easy as  installing the &#8220;<a title="Download Details: 2007 Office System Driver: Data Connectivity Components" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=7554F536-8C28-4598-9B72-EF94E038C891&amp;displaylang=en" target="_blank">2007 Office System Driver: Data Connectivity Components</a>&#8221; package from Microsoft. This same package will also enable access to Access 2007.<br /> <span id="more-1466"></span><br /> After installation, simply re-run DTSWizard and try to import again. If you can&#8217;t find Excel or Access in the Data Source dropdown list, remember that the providers only work in 32-bit mode, and therefore you need to run &#8220;Import and Export Data (32-bit),&#8221; which is located at &#8220;C:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\DTSWizard.exe&#8221;.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2010/01/06/import-excel-2007-with-sql-server-import-and-export-wizard/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Microsoft Office 2010 Beta posted on MSDN/TechNet</title><link>http://www.ideaexcursion.com/2009/11/16/microsoft-office-2010-beta-posted-on-msdntechnet/</link> <comments>http://www.ideaexcursion.com/2009/11/16/microsoft-office-2010-beta-posted-on-msdntechnet/#comments</comments> <pubDate>Mon, 16 Nov 2009 20:12:01 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[Microsoft]]></category> <category><![CDATA[Office]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1450</guid> <description><![CDATA[The new Office 2010 Beta just dropped on MSDN and TechNet. The package is available in both 64-bit and 32-bit flavors; download details for both appear below.]]></description> <content:encoded><![CDATA[<p>The new Office 2010 Beta was expected this week and just dropped on MSDN and TechNet. Unfortunately, it does appear to be on the faster &#8220;Top Downloads&#8221; servers &#8211; I&#8217;m getting a paltry 450KB/s. The Professional Plus 2010 package is available in both 64-bit and 32-bit flavors; download details for both appear below.<br /> <span id="more-1450"></span></p><ul><li>File Name: en_office_professional_plus_2010_beta_x64_x16-19234.exe</li><li>Size: 749.87 (MB)</li><li> Date Posted (UTC): 11/16/2009 7:21:24 AM</li><li> ISO/CRC: D5C14D40</li><li> SHA1: D07BC0DEE307E05F955CE44825F85084B94595B8</li></ul><ul><li> File Name: en_office_professional_plus_2010_beta_x86_x16-19227.exe</li><li>Size: 684.48 (MB)</li><li> Date Posted (UTC): 11/16/2009 7:21:23 AM</li><li>ISO/CRC: D3ACD2EF</li><li>SHA1: F219E1D7FE830DCD6A796FAFEA3A5D0D4662EE89</li></ul><p>(via <a title="Microsoft Office 2010 beta available on MSDN/TechNet" href="http://www.neowin.net/news/main/09/11/16/microsoft-office-2010-beta-available-on-msdntechnet" target="_blank">Neowin</a>)</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2009/11/16/microsoft-office-2010-beta-posted-on-msdntechnet/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Accessing Custom .NET Assemblies in SSIS 2008 Script Tasks</title><link>http://www.ideaexcursion.com/2009/10/14/accessing-custom-net-assemblies-in-ssis-2008-script-tasks/</link> <comments>http://www.ideaexcursion.com/2009/10/14/accessing-custom-net-assemblies-in-ssis-2008-script-tasks/#comments</comments> <pubDate>Wed, 14 Oct 2009 19:36:24 +0000</pubDate> <dc:creator>Taylor Gerring</dc:creator> <category><![CDATA[SSIS]]></category> <category><![CDATA[.NET]]></category> <category><![CDATA[C#]]></category> <category><![CDATA[SQL Server]]></category> <category><![CDATA[VB.NET]]></category><guid isPermaLink="false">http://www.ideaexcursion.com/?p=1429</guid> <description><![CDATA[If you need to access a custom .NET Assembly from an SSIS Script Task, Microsoft doesn't make things very easy - but it's still possible with a little setup.]]></description> <content:encoded><![CDATA[<p>If you need to access a custom .NET Assembly from an <abbr title="SQL Server Integration Services">SSIS</abbr> Script Task, Microsoft doesn&#8217;t make things very easy &#8211; but it&#8217;s still possible with a little setup. This is a great way to introduce custom data types or some new functionality without having to replicate that code in a new environment.<br /> <span id="more-1429"></span></p><h2>The Setup</h2><ul><li>Windows 7 64-bit</li><li>Visual Studio 2008</li><li>SQL Server 2008 64-bit</li></ul><h2>The Process</h2><ol><li>Create a signing key (See also, <a title="How to: Create a Public/Private Key Pair" href="http://msdn.microsoft.com/en-us/library/6f05ezxy.aspx " target="_blank">How to: Create a Public/Private Key Pair</a>)<ol><li>Open Visual Studio 2008 command Prompt &#8211; the regular command prompt <em>will not</em> work</li><li>Change to a friendly directory: cd %userprofile%\Desktop</li><li>Create the key file: sn -k key.snk</li></ol></li><li>Sign the assembly &#8211; There are a few ways to do this, but I found this to be the easiest. If you want to sign it some other way, check out <a title="http://msdn.microsoft.com/en-us/library/xc31ft41.aspx" href="http://msdn.microsoft.com/en-us/library/xc31ft41.aspx" target="_blank">How to: Sign an Assembly with a Strong Name</a><ol><li>Right-click the Project</li><li>Select &#8220;Properties&#8221;</li><li>Navigate to the &#8220;Signing&#8221; tab</li><li>Browse to strong name key file (which was created in the previous step)</li><li>Recompile the project</li></ol></li><li>Copy the re-compiled assembly to your <acronym title="Global Assembly Cache">GAC</acronym><ol><li>gacutil -i &#8220;C:\Path\to\CustomAssemblyName.dll&#8221;</li></ol></li><li>Copy assembly to &#8220;%programfiles(x86)%\Microsoft SQL Server\100\SDK\Assemblies&#8221;</li><li>Add reference in script task. Repeat this for <strong>every </strong>Script Task you want to access this assembly from<ol><li>Right-click References</li><li>Click &#8220;Add Reference&#8230;&#8221;<p><div id="attachment_1437" class="wp-caption alignnone" style="width: 310px"><a rel="attachment wp-att-1437" href="http://www.ideaexcursion.com/2009/10/14/accessing-custom-net-assemblies-in-ssis-2008-script-tasks/add-reference/"><img class="size-medium wp-image-1437" title="Add Reference..." src="http://static.ideaexcursion.com/wp-content/uploads/2009/10/add-reference-300x139.png" alt="Add Reference..." width="300" height="139" /></a><p class="wp-caption-text">Add Reference...</p></div></li><li>On the .NET tab, scroll to find your assembly</li><li>Press &#8220;OK&#8221;</li><li>The Assembly should now appear under the References list</li></ol></li><li> Add a reference to the assembly in code, at the top<ol><li>(C#) Using CustomAssemblyName;</li><li> (VB.NET) Imports CustomAssemblyName</li></ol></li><li>You should now have full access to the imported <abbr title="Dynamic Link Library">DLL</abbr></li></ol><h2>Caveats</h2><p>This method works pretty well, but deployment isn&#8217;t exactly seamless &#8211; you&#8217;ll have to repeat this for each server and re-register &amp; copy the <abbr title="Dynamic Link Library">DLL</abbr> separately for any updates. Additionally, there is no way to globally add the assembly reference to the entire project or package. Instead, you&#8217;ll have to repeat step 6 (adding the reference) for every Script Task.</p> ]]></content:encoded> <wfw:commentRss>http://www.ideaexcursion.com/2009/10/14/accessing-custom-net-assemblies-in-ssis-2008-script-tasks/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> </channel> </rss>
<!-- Served from: www.ideaexcursion.com @ 2012-02-04 08:23:45 by W3 Total Cache -->
