{"id":213,"date":"2007-01-17T00:00:00","date_gmt":"2007-01-17T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/quick-tip-performing-an-ftp-rename-in-a-ssis-script-task\/"},"modified":"2021-06-03T16:45:30","modified_gmt":"2021-06-03T16:45:30","slug":"quick-tip-performing-an-ftp-rename-in-a-ssis-script-task","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/bi-sql-server\/quick-tip-performing-an-ftp-rename-in-a-ssis-script-task\/","title":{"rendered":"Quick Tip: Performing an FTP rename in a SSIS script task"},"content":{"rendered":"<p>A common requirement is to process files from an FTP directory. Often this is done by processing every file in the directory and moving each file to an archive directory after processing. Therefore, on the next run, the &#8220;live&#8221; directory will only contain unprocessed files and the &#8220;archive&#8221; directory will provide a record of the files processed.<\/p>\n<p>The FTP command to move files is &#8220;rename&#8221;, in effect renaming the file path. Unfortunately a rename isn&#8217;t included in the commands available in the FTP task in SQL Server Integration Services (SSIS). This is quite a problem for a project that wishes to keep all processing within SSIS.<\/p>\n<p>Implementing a single FTP instruction in a script task is pretty straightforward, but a search for code to implement this &#8220;rename&#8221; repeatedly turned up an implementation of an FTP class &#8211; giving a complete instruction set wrapper and interpreting return codes.<\/p>\n<p>However, I finally found a simple FTP script to perform a file <b>get<\/b> here:<\/p>\n<p><a href=\"http:\/\/p2p.wrox.com\/topic.asp?TOPIC_ID=1500\">http:\/\/p2p.wrox.com\/topic.asp?TOPIC_ID=1500<\/a><\/p>\n<p>All I needed to do was change the command and I had a technique that accomplished FTP renames very easily. The following script will move a hard coded file:<\/p>\n<pre><\/pre>\n<p>Public Class ScriptMain<\/p>\n<p>\u00a0\u00a0 Private Declare Function InternetCloseHandle Lib &#8220;wininet.dll&#8221;<br \/>\n(ByVal HINet As Integer) As Integer<\/p>\n<p>\u00a0\u00a0 Private Declare Function InternetOpen Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;InternetOpenA&#8221;<br \/>\n(ByVal sAgent As String,<br \/>\nByVal lAccessType As Integer,<br \/>\nByVal sProxyName As String,<br \/>\nByVal sProxyBypass As String,<br \/>\nByVal lFlags As Integer)<br \/>\nAs Integer<\/p>\n<p>\u00a0\u00a0 Private Declare Function InternetConnect Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;InternetConnectA&#8221;<br \/>\n(ByVal hInternetSession As Integer,<br \/>\nByVal sServerName As String,<br \/>\nByVal nServerPort As Integer,<br \/>\nByVal sUsername As String,<br \/>\nByVal sPassword As String,<br \/>\nByVal lService As Integer,<br \/>\nByVal lFlags As Integer,<br \/>\nByVal lContext As Integer)<br \/>\nAs Integer<\/p>\n<p>\u00a0\u00a0 Private Declare Function FtpRenameFile Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;FtpRenameFileA&#8221;<br \/>\n(ByVal hFtpSession As Integer,<br \/>\nByVal lpszExisting As String,<br \/>\nByVal lpszNew As String)<br \/>\nAs Boolean<\/p>\n<p>\u00a0\u00a0 Public Sub Main()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim INet, INetConn As Integer<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dim RC As Boolean<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 INet = InternetOpen(&#8220;MyFTP Control&#8221;, 1, vbNullString,<br \/>\n vbNullString, 0)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 INetConn = InternetConnect(INet, &#8220;FTPServer&#8221;, 0,<br \/>\n&#8220;UserName&#8221;, &#8220;Password&#8221;, 1, 0, 0)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 RC = FtpRenameFile(INetConn, &#8220;\/myfilepath\/myfile&#8221;,<br \/>\n&#8220;\/mydestfilepath\/myfile&#8221;)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 InternetCloseHandle(INetConn)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 InternetCloseHandle(INet)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.TaskResult = Dts.Results.Success<\/p>\n<p>\u00a0\u00a0 End Sub<\/p>\n<p>End Class<\/p>\n<p>Of course, for a real world implementation we need to get the FTP site credentials, file paths and file names from variables in the SSIS package. The following code (which would be part of a <b>for each<\/b> file loop in the package) could be used to retrieve all information from variables in the package.<\/p>\n<p>The complete package would retrieve all files from the FTP directory with an FTP task and then process each of the files with a <b>for each<\/b> file loop &#8211; setting the variable <b>strMyFileNamePath<\/b> to the file path and name. The path for the file is held in <b>strLocalPath<\/b> and used to set the FTP directory path in the <b>replace<\/b> statement (see below).<\/p>\n<p>This FTP move script would be one of the last tasks in the loop, to indicate that processing for that file is complete.<\/p>\n<pre><\/pre>\n<p class=\"MsoNormal\">Imports System<br \/>\nImports System.Data<br \/>\nImports System.Math<br \/>\nImports Microsoft.SqlServer.Dts.Runtime<\/p>\n<p>Public Class ScriptMain<br \/>\n\u00a0\u00a0 Private Declare Function InternetCloseHandle Lib &#8220;wininet.dll&#8221;<br \/>\n(ByVal HINet As Integer) As Integer<br \/>\n\u00a0\u00a0 Private Declare Function InternetOpen Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;InternetOpenA&#8221;<br \/>\n(ByVal sAgent As String,<br \/>\nByVal lAccessType As Integer,<br \/>\nByVal sProxyName As String,<br \/>\nByVal sProxyBypass As String,<br \/>\nByVal lFlags As Integer<br \/>\n) As Integer<br \/>\n\u00a0\u00a0 Private Declare Function InternetConnect Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;InternetConnectA&#8221;<br \/>\n(ByVal hInternetSession As Integer,<br \/>\nByVal sServerName As String,<br \/>\nByVal nServerPort As Integer,<br \/>\nByVal sUsername As String,<br \/>\nByVal sPassword As String,<br \/>\nByVal lService As Integer,<br \/>\nByVal lFlags As Integer,<br \/>\nByVal lContext As Integer<br \/>\n) As Integer<br \/>\n\u00a0\u00a0 Private Declare Function FtpRenameFile Lib &#8220;wininet.dll&#8221;<br \/>\nAlias &#8220;FtpRenameFileA&#8221;<br \/>\n(ByVal hFtpSession As Integer,<br \/>\nByVal lpszExisting As String,<br \/>\nByVal lpszNew As String<br \/>\n) As Boolean<\/p>\n<p>\u00a0\u00a0 Public Sub Main()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim INet, INetConn As Integer<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dim RC As Boolean<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim vars As Variables<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strMyFileNamePath As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strMyFileNamePath&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strMyFileNamePath = vars(&#8220;strMyFileNamePath&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strFTPServer As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strFTPServer&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strFTPServer = vars(&#8220;strFTPServer&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strFTPUser As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strFTPUser&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strFTPUser = vars(&#8220;strFTPUser&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strFTPPassword As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strFTPPassword&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strFTPPassword = vars(&#8220;strFTPPassword&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strFTPPath As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strFTPPath&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strFTPPath = vars(&#8220;strFTPPath&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strFTPPathProcessed As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strFTPPathProcessed&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strFTPPathProcessed = vars(&#8220;strFTPPathProcessed&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strLocalPath As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.VariableDispenser.LockOneForRead(&#8220;strLocalPath&#8221;, vars)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strLocalPath = vars(&#8220;strLocalPath&#8221;).Value.ToString()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 vars.Unlock()<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strMyFileNamePathOld As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strMyFileNamePathOld = <b>Replace<\/b>(strMyFileNamePath,<br \/>\n strLocalPath, strFTPPath)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strMyFileNamePathOld = <b>Replace<\/b>(strMyFileNamePathOld, &#8220;\\&#8221;, &#8220;\/&#8221;)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Dim strMyFileNamePathNew As String<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 strMyFileNamePathNew = <b>Replace<\/b>(strMyFileNamePathOld,<br \/>\n strFTPPath, strFTPPathProcessed)<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 INet = InternetOpen(&#8220;MyFTP Control&#8221;, 1, vbNullString,<br \/>\n vbNullString, 0)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 INetConn = InternetConnect(INet, strFTPServer, 0, strFTPUser,<br \/>\n strFTPPassword, 1, 0, 0)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 RC = FtpRenameFile(INetConn, strMyFileNamePathOld,<br \/>\n strMyFileNamePathNew)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 InternetCloseHandle(INetConn)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 InternetCloseHandle(INet)<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 MsgBox(strMyFileNamePathOld &amp; &#8220;_&#8221; &amp; strMyFileNamePathNew)<\/p>\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0 If RC &lt;&gt; True Then<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.TaskResult = Dts.Results.Failure<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 Else<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Dts.TaskResult = Dts.Results.Success<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 End If<br \/>\n\u00a0\u00a0 End Sub<\/p>\n<p>End Class<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nigel Rivett provides a technique for moving files from one FTP directory to another, and for performing this processing from SQL Server Integration Services.&hellip;<\/p>\n","protected":false},"author":223267,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143528],"tags":[4612,4613,4150,4151,4306],"coauthors":[48340],"class_list":["post-213","post","type-post","status-publish","format-standard","hentry","category-bi-sql-server","tag-ftp-rename","tag-processing-ftp-files","tag-sql","tag-sql-server","tag-ssis"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/223267"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=213"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/213\/revisions"}],"predecessor-version":[{"id":74818,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/213\/revisions\/74818"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=213"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}