<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Robert McMurray's Blog [MSFT] : FTP</title><link>http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx</link><description>Tags: FTP</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>IIS Videos on Dr. Dobb's Web Site</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/12/26/iis-videos-on-dr-dobb-s-web-site.aspx</link><pubDate>Sun, 27 Dec 2009 06:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9941349</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9941349.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9941349</wfw:commentRss><description>&lt;P&gt;Like many people I know, I get a lot of email from various industry-related publications; some of the emails are spam, and the others are from computer magazines that I subscribe to. (And there are several of those. ;-] )&lt;/P&gt;
&lt;P&gt;Anyway, I received an email the other day from the folks at Dr. Dobb’s, and it contained a link for a video on IIS Bitrate Throttling. It always piques my interest to see what others have to say about IIS, so I followed the link and discovered that the following page has several IIS-related videos listed:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://www.ddj.com/ddjtvmsondemand.jhtml" target=_blank mce_href="http://www.ddj.com/ddjtvmsondemand.jhtml"&gt;http://www.ddj.com/ddjtvmsondemand.jhtml&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Within the list of videos I found videos for FTP and WebDAV, so I couldn't resist watching those:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;IIS FTP Publishing Service&lt;BR&gt;&lt;A href="http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40439588001" target=_blank mce_href="http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40439588001"&gt;http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40439588001&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;IIS WebDAV&lt;BR&gt;&lt;A href="http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40444327001" target=_blank mce_href="http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40444327001"&gt;http://ddj.com/ddjtvmsondemand.jhtml?bcpid=10177845001&amp;amp;bclid=9347349001&amp;amp;bctid=40444327001&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;As I was watching those videos, the thought occurred to me that those videos were really familiar - but not in a déjà vu kind of way. As it turns out, those are the same videos that are on the IIS.NET web site:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;IIS FTP Publishing Service&lt;BR&gt;&lt;A href="http://www.iis.net/expand/ftp" target=_blank mce_href="http://www.iis.net/expand/ftp"&gt;http://www.iis.net/expand/ftp&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;IIS WebDAV&lt;BR&gt;&lt;A href="http://www.iis.net/expand/WebDAV" target=_blank mce_href="http://www.iis.net/expand/WebDAV"&gt;http://www.iis.net/expand/WebDAV&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Oh well - I was hoping for something new. But the fact remains that the folks at Dr. Dobb’s have collected a good number of IIS and Windows-related videos and put them all in one place, so it's a nice reference to have around.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9941349" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/WebDAV/default.aspx">WebDAV</category></item><item><title>IP Address Lookups for Addresses that were Blocked by FTP Dynamic IP Restrictions</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/11/29/ip-address-lookups-for-addresses-that-were-blocked-by-ftp-dynamic-ip-restrictions.aspx</link><pubDate>Mon, 30 Nov 2009 00:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9929961</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9929961.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9929961</wfw:commentRss><description>&lt;P&gt;A few months ago I wrote a blog post that was titled "&lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2009/08/19/merging-ftp-extensibility-walkthroughs-part-2.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/2009/08/19/merging-ftp-extensibility-walkthroughs-part-2.aspx"&gt;Merging FTP Extensibility Walkthroughs - Part 2&lt;/A&gt;", where I described how to merge my &lt;A href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/" target=_blank mce_href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/"&gt;FTP Dynamic IP Restrictions Authentication Provider&lt;/A&gt; walkthrough with my &lt;A href="http://learn.iis.net/page.aspx/632/how-to-use-managed-code-c-to-create-an-ftp-provider-that-sends-an-email-when-files-are-uploaded/" mce_href="http://learn.iis.net/page.aspx/632/how-to-use-managed-code-c-to-create-an-ftp-provider-that-sends-an-email-when-files-are-uploaded/"&gt;FTP Provider that Sends an Email when Files are Uploaded&lt;/A&gt; walkthrough. The result of this code combination was a custom FTP authentication provider that provides support for dynamic IP restrictions that sends me an email every time a new IP address is blocked. I deployed this custom FTP authentication provider on one of my public-facing FTP sites when I wrote the blog post, and in the three months that I have been using that provider it has blocked 88 IP addresses.&lt;/P&gt;
&lt;P&gt;Recently it seems that every day I receive a new email that another IP address has been blocked. If you've seen my &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/tags/LogParser/default.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/tags/LogParser/default.aspx"&gt;LogParser&lt;/A&gt; and other log-related blog posts you'll realize that I'm kind of a log analysis geek, so I thought that it might be interesting to at least show something of a breakdown for the information that I've been seeing. For privacy reasons I can't distribute the list of IP addresses, so I'll just show a list of countries that I've seen in my dynamic IP restriction provider's SQL database since I deployed my provider.&lt;/P&gt;
&lt;P&gt;The method that I employed for obtaining the location information was to write a couple of small scripts that dumped the list of IP addresses from my dynamic IP restriction provider's SQL database to a text file and then perform an IP address lookup to count the various countries from where the various hacking attempts have been originating. This gave me the following country-by-country information:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE style="BORDER-COLLAPSE: collapse" border=1 cellSpacing=1 borderColorLight=#000000 borderColorDark=#000000 cellPadding=4 bgColor=#ffffff&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH vAlign=top noWrap align=left&gt;Country&lt;/TH&gt;
&lt;TH noWrap align=right&gt;Total&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;UNITED STATES&lt;/TD&gt;
&lt;TD noWrap align=right&gt;23&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;CHINA&lt;/TD&gt;
&lt;TD noWrap align=right&gt;20&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;[&lt;I&gt;unknown&lt;/I&gt;]&lt;/TD&gt;
&lt;TD noWrap align=right&gt;15&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;GERMANY&lt;/TD&gt;
&lt;TD noWrap align=right&gt;5&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;REPUBLIC OF KOREA&lt;/TD&gt;
&lt;TD noWrap align=right&gt;4&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;FRANCE&lt;/TD&gt;
&lt;TD noWrap align=right&gt;3&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;CZECH REPUBLIC&lt;/TD&gt;
&lt;TD noWrap align=right&gt;3&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;SPAIN&lt;/TD&gt;
&lt;TD noWrap align=right&gt;3&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;POLAND&lt;/TD&gt;
&lt;TD noWrap align=right&gt;2&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;BRAZIL&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;CYPRUS&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;SAUDI ARABIA&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;ARGENTINA&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;NETHERLANDS&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;JAPAN&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;THAILAND&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;SWITZERLAND&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;UKRAINE&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=top noWrap align=left&gt;INDIA&lt;/TD&gt;
&lt;TD noWrap align=right&gt;1&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TH vAlign=top noWrap align=left&gt;Total&lt;/TH&gt;
&lt;TH noWrap align=right&gt;88&lt;/TH&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I can't give out the name of the site that I used for the IP lookups, but there are several IP locator, geotargeting, or IP mapping sites available; a simple Internet search should provide you with a list of those sites. Once I choose one of those sites, writing a script to pull the IP addresses from my dynamic IP restriction provider's SQL database and perform the lookup was simple. The code that I wrote for the IP lookups was in VBScript, which I have included below. To use this script, you would need to populate a file named "IP_Addresses.txt" with the IP addresses to query, change the value of IP_LOOKUP_STUB in the example below to one of the available IP lookup URLs, then run the script, which will create a file named "IP_Addresses.log" with the resulting IP lookup information:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #008000"&gt;' ****************************************&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Option&lt;/SPAN&gt; Explicit
&lt;SPAN style="COLOR: #008000"&gt;
' ****************************************&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Const&lt;/SPAN&gt; MAX_ATTEMPTS   = 10    &lt;SPAN style="COLOR: #008000"&gt;' the number of times to keep retrying to get a file&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Const&lt;/SPAN&gt; FAILURE_SLEEP  = 1000  &lt;SPAN style="COLOR: #008000"&gt;' the number of milliseconds to sleep between retries&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Const&lt;/SPAN&gt; SUCCESS_SLEEP  = 1000  &lt;SPAN style="COLOR: #008000"&gt;' the number of milliseconds to sleep between successes
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Const&lt;/SPAN&gt; IP_LOOKUP_STUB = "&lt;SPAN style="COLOR: #8b0000"&gt;http://www.example.com/page?ip=&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #008000"&gt;
' ****************************************&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objFSO
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objFile
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; strLookupURL
&lt;SPAN style="COLOR: #008000"&gt;
' ****************************************&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objFSO = WScript.CreateObject("&lt;SPAN style="COLOR: #8b0000"&gt;Scripting.FileSystemObject&lt;/SPAN&gt;")
&lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objFile = objFSO.OpenTextFile("&lt;SPAN style="COLOR: #8b0000"&gt;IP_Addresses.txt&lt;/SPAN&gt;")
&lt;SPAN style="COLOR: #0000ff"&gt;Do&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;While&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Not&lt;/SPAN&gt; objFile.AtEndOfStream
  strLookupURL = IP_LOOKUP_STUB &amp;amp; Trim(objFile.ReadLine)
  &lt;SPAN style="COLOR: #0000ff"&gt;Call&lt;/SPAN&gt; IpLookup(strLookupURL)
&lt;SPAN style="COLOR: #0000ff"&gt;Loop&lt;/SPAN&gt;
objFile.Close
WScript.Quit
&lt;SPAN style="COLOR: #008000"&gt;
' ****************************************&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Function&lt;/SPAN&gt; IpLookup(tmpURL)
  &lt;SPAN style="COLOR: #0000ff"&gt;On&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Next&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; intTempAttempt
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; blnTempStatus
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objTempFSO
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objTempFile
  &lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objTempFSO = CreateObject("&lt;SPAN style="COLOR: #8b0000"&gt;Scripting.FileSystemObject&lt;/SPAN&gt;")
  blnTempStatus = &lt;SPAN style="COLOR: #0000ff"&gt;False&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objHTTP
  &lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objHTTP = CreateObject("&lt;SPAN style="COLOR: #8b0000"&gt;MSXML2.ServerXMLHTTP&lt;/SPAN&gt;")
  &lt;SPAN style="COLOR: #0000ff"&gt;For&lt;/SPAN&gt; intTempAttempt = 1 &lt;SPAN style="COLOR: #0000ff"&gt;To&lt;/SPAN&gt; MAX_ATTEMPTS
    objHTTP.Open "&lt;SPAN style="COLOR: #8b0000"&gt;GET&lt;/SPAN&gt;", tmpURL, &lt;SPAN style="COLOR: #0000ff"&gt;False&lt;/SPAN&gt;
    objHTTP.Send
    &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; (objHTTP.Status = 200) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
      &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; Err.Number = 0 &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
        blnTempStatus = &lt;SPAN style="COLOR: #0000ff"&gt;True&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objTempFile = objTempFSO.OpenTextFile("&lt;SPAN style="COLOR: #8b0000"&gt;IP_Addresses.log&lt;/SPAN&gt;",8,&lt;SPAN style="COLOR: #0000ff"&gt;True&lt;/SPAN&gt;)
        objTempFile.WriteLine &lt;SPAN style="COLOR: #0000ff"&gt;String&lt;/SPAN&gt;(80,"&lt;SPAN style="COLOR: #8b0000"&gt;=&lt;/SPAN&gt;")
        objTempFile.WriteLine tmpURL
        objTempFile.WriteLine objHTTP.responseText
        objTempFile.Close
        &lt;SPAN style="COLOR: #0000ff"&gt;Exit&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;For&lt;/SPAN&gt;
      &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;
    WScript.Sleep FAILURE_SLEEP * intTempAttempt
  &lt;SPAN style="COLOR: #0000ff"&gt;Next&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objHTTP = &lt;SPAN style="COLOR: #0000ff"&gt;Nothing&lt;/SPAN&gt;
  IpLookup = blnTempStatus
&lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Function&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;If you would rather use managed-code, a great example that you could use as a starting point is the &lt;A href="http://www.codeproject.com/KB/cs/KBSoftIPLocator.aspx" target=_blank mce_href="http://www.codeproject.com/KB/cs/KBSoftIPLocator.aspx"&gt;KBSoft IP Locator&lt;/A&gt; example by Alexandr Golovanov, which also includes the URLs for a couple of IP locator services. Sometime in the future I think that I might write an ASP.NET application that replaces the VBScript code with a web-based interface, or I might add the IP locator logic to my dynamic IP restriction provider&amp;nbsp;through an asynchronous function so that I have the information readily available whenever I want, but for the moment I'm content with my low-tech solution. ;-]&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9929961" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>eWeek Reviews for IIS 7.5 and FTP 7.5</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/09/23/eweek-reviews-for-iis-7-5-and-ftp-7-5.aspx</link><pubDate>Thu, 24 Sep 2009 01:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9898705</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9898705.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9898705</wfw:commentRss><description>&lt;P&gt;One of my coworkers, Vijay Sen, just forwarded the following eWeek review of IIS 7.5 to me:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.eweek.com/c/a/Windows/REVIEW-Microsoft-IIS-75-Improves-Management-Deployment-Options-822018/" target=_blank mce_href="http://www.eweek.com/c/a/Windows/REVIEW-Microsoft-IIS-75-Improves-Management-Deployment-Options-822018/"&gt;http://www.eweek.com/c/a/Windows/REVIEW-Microsoft-IIS-75-Improves-Management-Deployment-Options-822018/&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The review was written by &lt;A href="http://www.eweek.com/cp/bio/Jim-Rapoza/" target=_blank mce_href="http://www.eweek.com/cp/bio/Jim-Rapoza/"&gt;Jim Rapoza&lt;/A&gt;, and he said some great things about IIS 7.5, which ships with both Windows Server 2008 R2 and Windows 7 client. But what really made my day was the following things that he said about FTP 7.5:&lt;/P&gt;
&lt;BLOCKQUOTE style="BACKGROUND-COLOR: #eeeeee; COLOR: #000000"&gt;
&lt;P&gt;&lt;EM&gt;Another welcome change in IIS 7.5 is the elevation of FTP as a full-fledged part of the server. In previous versions, setup and management of an FTP server in IIS were done pretty much separately from Web server management. In IIS 7.5, FTP administration is fully integrated into the IIS Management Console.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;I found this to be a very good implementation of FTP, making it possible to quickly set up secure FTP servers and tie them to my Websites. Especially nice was the ability to easily use virtual host names for the FTP sites. All in all, the FTP implementation in IIS 7.5 is one of the best I’ve seen, even when compared with dedicated FTP server products.&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;It’s great to see all of our hard work being recognized!&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif"&gt;&lt;/P&gt;
&lt;P&gt;My thanks once again to everyone on the FTP and IIS feature teams that helped make this version of the FTP service: &lt;A href="http://blogs.iis.net/jaroslad/" mce_href="http://blogs.iis.net/jaroslad/"&gt;Jaroslav&lt;/A&gt;, Emily, &lt;A href="http://blogs.msdn.com/danielvl/" mce_href="http://blogs.msdn.com/danielvl/"&gt;Daniel&lt;/A&gt;, Umer, &lt;A href="http://blogs.iis.net/suDt/" mce_href="http://blogs.iis.net/suDt/"&gt;Suditi&lt;/A&gt;, Ciprian, Jeong, &lt;A href="http://blogs.iis.net/davcox/" mce_href="http://blogs.iis.net/davcox/"&gt;Dave&lt;/A&gt;, Andrew, &lt;A href="http://blogs.msdn.com/carlosag/" mce_href="http://blogs.msdn.com/carlosag/"&gt;Carlos&lt;/A&gt;, &lt;A href="http://blogs.iis.net/bdela/" mce_href="http://blogs.iis.net/bdela/"&gt;Brian&lt;/A&gt;, &lt;A href="http://blogs.iis.net/wadeh/" mce_href="http://blogs.iis.net/wadeh/"&gt;Wade&lt;/A&gt;, Ulad, &lt;A href="http://blogs.iis.net/nazim/" mce_href="http://blogs.iis.net/nazim/"&gt;Nazim&lt;/A&gt;, Reagan, Claudia, Rick, Tim, &lt;A href="http://blogs.iis.net/TobinTitus/" mce_href="http://blogs.iis.net/TobinTitus/"&gt;Tobin&lt;/A&gt;, Kern, Jenny, Nitasha, Venkat, Vijay. (I hope that I didn't leave anyone out!)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9898705" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>FTP 7.5 Extensibility and Visual Studio Express Editions</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/09/17/ftp-7-5-extensibility-and-visual-studio-express-editions.aspx</link><pubDate>Thu, 17 Sep 2009 21:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9896442</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9896442.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9896442</wfw:commentRss><description>&lt;P&gt;In earlier blog posts I have mentioned that I written the several walkthroughs to help developers get started writing providers for the FTP 7.5 service, all of which available on Microsoft's &lt;A href="http://learn.iis.net/" target=_blank mce_href="http://learn.iis.net/"&gt;learn.iis.net&lt;/A&gt; Web site under the "&lt;A href="http://learn.iis.net/page.aspx/590/developing-for-ftp-75/" target=_blank mce_href="http://learn.iis.net/page.aspx/590/developing-for-ftp-75/"&gt;Developing for FTP 7.5&lt;/A&gt;" section. In each of these walkthroughs I wrote the steps as if you were using Visual Studio 2008.&lt;/P&gt;
&lt;P&gt;Following up on that, I received a great question yesterday from a customer, Paul Dowdle, who wondered if it was possible to write an extensibility provider for the FTP 7.5 service using one of the Visual Studio Express Editions. By way of coincidence, I used to install Visual C# Express Edition on my laptop when I was traveling around the world to speak at events like &lt;A href="http://www.msteched.com/" target=_blank mce_href="http://www.msteched.com/"&gt;TechEd&lt;/A&gt;. I usually did this because the Express Edition took up less hard drive space than a full installation of Visual Studio, and I was only writing code in C# on my laptop.&lt;/P&gt;
&lt;P&gt;To answer Paul's question, the short answer is - yes, you can use Visual Studio Express Editions to develop custom providers for the FTP 7.5 service, with perhaps a few small changes from my walkthroughs.&lt;/P&gt;
&lt;P&gt;For example, if you look at my "&lt;A href="http://learn.iis.net/page.aspx/598/how-to-use-managed-code-c-to-create-a-simple-ftp-authentication-provider/" target=_blank&gt;How to Use Managed Code (C#) to Create a Simple FTP Authentication Provider&lt;/A&gt;" walkthrough, in the section that is titled "Step 1: Set up the Project Environment", there is an optional step 6 for adding a custom build event to register the DLL automatically in the Global Assembly Cache (GAC) on your development computer.&lt;/P&gt;
&lt;P&gt;When I installed Microsoft Visual C# 2008 Express Edition on a new computer, I didn't have the "%VS90COMNTOOLS%" environment variable or the "vsvars32.bat" file, so I had to update the custom build event to the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;net stop ftpsvc
"%ProgramFiles%\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe" /if "$(TargetPath)"
net start ftpsvc&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Once I made that change, the rest of the walkthrough worked as written.&lt;/P&gt;
&lt;P&gt;So, to reiterate my earlier statement - you can use Visual Studio Express Editions to develop custom providers for the FTP 7.5 service. My thanks to Paul for the great question!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9896442" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Hiding your FTP Server Type and Preventing Unauthorized Access</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/09/10/hiding-your-ftp-server-type-and-preventing-unauthorized-access.aspx</link><pubDate>Thu, 10 Sep 2009 23:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9893855</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9893855.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9893855</wfw:commentRss><description>&lt;P&gt;As evidenced by my &lt;A href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions" target=_blank mce_href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions"&gt;How to Use Managed Code (C#) to Create an FTP Authentication Provider with Dynamic IP Restrictions&lt;/A&gt; walkthrough and my other FTP authentication extensibility walkthroughs, I spend a lot of time trying to find ways to prevent unauthorized access to my FTP server while still allowing valid users to have easy access to their site content. Today's blog discusses several of the ideas that I like to use on my FTP servers.&lt;/P&gt;
&lt;H4&gt;Preventing Unauthorized Access&lt;/H4&gt;
&lt;P&gt;To start things off, I globally disable FTP Basic Authentication on my server and I only use custom authentication providers. Since my FTP users do not have actual accounts on my server or my domain, that helps prevent access to my physical server. It was for this reason that I wrote the authentication provider that I discuss in my &lt;A href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-using-an-xml-database/" target=_blank mce_href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-using-an-xml-database/"&gt;How to Use Managed Code (C#) to Create an FTP Authentication Provider using an XML Database&lt;/A&gt; walkthrough; I can hand out accounts with FTP access for sites that are hosted on my servers, but those accounts are stored in an XML file and not in the security accounts database on my server or my domain.&lt;/P&gt;
&lt;P&gt;But there are other ways to help secure your FTP server. For example, I wrote an earlier blog post about &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2008/12/17/ftp-clients-part-3-creating-a-global-listener-ftp-site.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/2008/12/17/ftp-clients-part-3-creating-a-global-listener-ftp-site.aspx"&gt;Creating a Global Listener FTP Site&lt;/A&gt;. On my servers I like to create a global listener site and disable all of the built-in authentication methods.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://y7b40a.blu.livefilestore.com/y1po9uDXUnvLNqdZK2dEzQWsLqaXG7inoFz_H881H8J--X-hwo41dWJ3_eHb50XzagqsV_RP9VLJiSFaDgHhAod6i0EICF7SzL2/global%20listener%20site.jpg" target=_blank mce_href="http://y7b40a.blu.livefilestore.com/y1po9uDXUnvLNqdZK2dEzQWsLqaXG7inoFz_H881H8J--X-hwo41dWJ3_eHb50XzagqsV_RP9VLJiSFaDgHhAod6i0EICF7SzL2/global%20listener%20site.jpg"&gt;&lt;IMG border=3 src="http://y7b40a.blu.livefilestore.com/y1po9uDXUnvLNqdZK2dEzQWsLqaXG7inoFz_H881H8J--X-hwo41dWJ3_eHb50XzagqsV_RP9VLJiSFaDgHhAod6i0EICF7SzL2/global%20listener%20site.jpg" width="50%" height="50%" mce_src="http://y7b40a.blu.livefilestore.com/y1po9uDXUnvLNqdZK2dEzQWsLqaXG7inoFz_H881H8J--X-hwo41dWJ3_eHb50XzagqsV_RP9VLJiSFaDgHhAod6i0EICF7SzL2/global%20listener%20site.jpg"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Once that has been completed I add the custom authentication provider from my &lt;A href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions" target=_blank mce_href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions"&gt;How to Use Managed Code (C#) to Create an FTP Authentication Provider with Dynamic IP Restrictions&lt;/A&gt; walkthrough, but I don't create any accounts in the database - I just want to log and block the IP addresses of would-be attackers that are attempting to brute force their way into my server. Configuring the authentication options is accomplished through the &lt;B&gt;FTP Authentication&lt;/B&gt; feature in IIS Manager.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://y7b40a.blu.livefilestore.com/y1pnRv7mOVfWdg6rqBSthl45xDuJRnaqxFGxoknchIvknjoE68WE45N0Zte2euTZx2x-MmrZFCz5qtcASgMgOVM2Q/custom%20authentication.jpg" target=_blank mce_href="http://y7b40a.blu.livefilestore.com/y1pnRv7mOVfWdg6rqBSthl45xDuJRnaqxFGxoknchIvknjoE68WE45N0Zte2euTZx2x-MmrZFCz5qtcASgMgOVM2Q/custom%20authentication.jpg"&gt;&lt;IMG border=3 src="http://y7b40a.blu.livefilestore.com/y1pnRv7mOVfWdg6rqBSthl45xDuJRnaqxFGxoknchIvknjoE68WE45N0Zte2euTZx2x-MmrZFCz5qtcASgMgOVM2Q/custom%20authentication.jpg" width="50%" height="50%" mce_src="http://y7b40a.blu.livefilestore.com/y1pnRv7mOVfWdg6rqBSthl45xDuJRnaqxFGxoknchIvknjoE68WE45N0Zte2euTZx2x-MmrZFCz5qtcASgMgOVM2Q/custom%20authentication.jpg"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Ever since I wrote and deployed my dynamic IP address restriction authentication provider, it has faithfully blocked dozens of would-be attackers.&lt;/P&gt;
&lt;H4&gt;Hiding your FTP Server Type&lt;/H4&gt;
&lt;P&gt;The next approach that I take is "Security through Obscurity", where I hide the easily recognizable signatures that identify my FTP server. The first step is to suppress the default banner and add a custom FTP banner. This is accomplished through the &lt;B&gt;FTP Messages&lt;/B&gt; feature in IIS Manager.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://y7b40a.blu.livefilestore.com/y1pkwDMrU610dFt0Ug2OZmoqQJtBHCvs7dpjxkg-5UGYdkKDuoaQ0RUwwriheMaJfsjw37mKU0-86yebF1hhmCNbA/messages.jpg" target=_blank mce_href="http://y7b40a.blu.livefilestore.com/y1pkwDMrU610dFt0Ug2OZmoqQJtBHCvs7dpjxkg-5UGYdkKDuoaQ0RUwwriheMaJfsjw37mKU0-86yebF1hhmCNbA/messages.jpg"&gt;&lt;IMG border=3 src="http://y7b40a.blu.livefilestore.com/y1pkwDMrU610dFt0Ug2OZmoqQJtBHCvs7dpjxkg-5UGYdkKDuoaQ0RUwwriheMaJfsjw37mKU0-86yebF1hhmCNbA/messages.jpg" width="50%" height="50%" mce_src="http://y7b40a.blu.livefilestore.com/y1pkwDMrU610dFt0Ug2OZmoqQJtBHCvs7dpjxkg-5UGYdkKDuoaQ0RUwwriheMaJfsjw37mKU0-86yebF1hhmCNbA/messages.jpg"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Next, switch your directory listing style to Unix format. All FTP clients that I have tested understand this format, but it hides the fact that your server can do MS-DOS listings. Configuring your directory listing style is accomplished through the &lt;B&gt;FTP Directory Browsing &lt;/B&gt;feature in IIS Manager.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://y7b40a.blu.livefilestore.com/y1pF7d1kpsjM9VBLgUc2GuWw_Ukko9FUQU_JtdKrKgDFaiD-tTp3UoVfgsyNfltgAADqmM-m7JjlkL64edKdU09iQ/directory%20browsing.jpg" target=_blank mce_href="http://y7b40a.blu.livefilestore.com/y1pF7d1kpsjM9VBLgUc2GuWw_Ukko9FUQU_JtdKrKgDFaiD-tTp3UoVfgsyNfltgAADqmM-m7JjlkL64edKdU09iQ/directory%20browsing.jpg"&gt;&lt;IMG border=3 src="http://y7b40a.blu.livefilestore.com/y1pF7d1kpsjM9VBLgUc2GuWw_Ukko9FUQU_JtdKrKgDFaiD-tTp3UoVfgsyNfltgAADqmM-m7JjlkL64edKdU09iQ/directory%20browsing.jpg" width="50%" height="50%" mce_src="http://y7b40a.blu.livefilestore.com/y1pF7d1kpsjM9VBLgUc2GuWw_Ukko9FUQU_JtdKrKgDFaiD-tTp3UoVfgsyNfltgAADqmM-m7JjlkL64edKdU09iQ/directory%20browsing.jpg"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;After implementing these changes, it might now resemble the following example FTP session when you log in with FTP:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE style="BACKGROUND-COLOR: #000000; COLOR: #ffffff"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;PRE&gt;CMD&amp;gt;ftp localhost

Connected to DESKTOP.domain.local.
220 Welcome to my server!
User (DESKTOP.domain.local:(none)): foobar
331 Password required for foobar.
Password:
230 User logged in.
ftp&amp;gt; dir
200 EPRT command successful.
125 Data connection already open; Transfer starting.
drwxrwxrwx   1 owner    group               0 Jan 22 11:45 App_Code
drwxrwxrwx   1 owner    group               0 Sep 10 10:32 App_Data
drwxrwxrwx   1 owner    group               0 Aug 17 13:35 bin
-rwxrwxrwx   1 owner    group             689 May  8  2008 iisstart.htm
-rwxrwxrwx   1 owner    group            2714 Jan 22 11:54 web.config
-rwxrwxrwx   1 owner    group          184946 May  8  2008 welcome.png
226 Transfer complete.
ftp: 418 bytes received in 0.02Seconds 83.00Kbytes/sec.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The last step that I take is to block the FTP infrastructure commands &lt;B&gt;SYST&lt;/B&gt; and &lt;B&gt;FEAT&lt;/B&gt; on the global listener FTP site. These commands respectively display your operating system and list of FTP features. Blocking these commands helps to further obfuscate your server type from attackers.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: It is important that you block these two commands only on your global listener FTP site and not on your other FTP sites, because some FTP clients may depend on these commands in order to interact properly with your other FTP sites. That said, if you are working with a small set of FTP clients and none of them seem to have a problem with suppressing the &lt;B&gt;SYST&lt;/B&gt; command, you could probably suppress that globally. Most clients that I have tested seem to have no problem with that, especially if you are using Unix directory listings.&lt;/P&gt;
&lt;P&gt;In any event, you block the &lt;B&gt;SYST&lt;/B&gt; and &lt;B&gt;FEAT&lt;/B&gt; commands through the &lt;B&gt;FTP Request Filtering &lt;/B&gt;feature in IIS Manager.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://y7b40a.blu.livefilestore.com/y1pyRKiOzDCI1bIKmYbXQPEMbdt80pRsnwJ-mw83yyp9UUtFP3Li67R3egteQT6MDhD1JCF8ofHxKt8IWLZ0ZruBA/request%20filtering.jpg" target=_blank mce_href="http://y7b40a.blu.livefilestore.com/y1pyRKiOzDCI1bIKmYbXQPEMbdt80pRsnwJ-mw83yyp9UUtFP3Li67R3egteQT6MDhD1JCF8ofHxKt8IWLZ0ZruBA/request%20filtering.jpg"&gt;&lt;IMG border=3 src="http://y7b40a.blu.livefilestore.com/y1pyRKiOzDCI1bIKmYbXQPEMbdt80pRsnwJ-mw83yyp9UUtFP3Li67R3egteQT6MDhD1JCF8ofHxKt8IWLZ0ZruBA/request%20filtering.jpg" width="50%" height="50%" mce_src="http://y7b40a.blu.livefilestore.com/y1pyRKiOzDCI1bIKmYbXQPEMbdt80pRsnwJ-mw83yyp9UUtFP3Li67R3egteQT6MDhD1JCF8ofHxKt8IWLZ0ZruBA/request%20filtering.jpg"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now when you log in with FTP and attempt to use the &lt;B&gt;SYST&lt;/B&gt; and &lt;B&gt;FEAT&lt;/B&gt; commands, it should look like the following example FTP session:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE style="BACKGROUND-COLOR: #000000; COLOR: #ffffff" id=table1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;PRE&gt;CMD&amp;gt;ftp localhost

Connected to DESKTOP.domain.local.
220 Welcome to my server!
User (DESKTOP.domain.local:(none)): foobar
331 Password required for foobar.
Password:
230 User logged in.
ftp&amp;gt; quote SYST
500 'SYST': command not allowed.
ftp&amp;gt; quote FEAT
500 'FEAT': command not allowed.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H4&gt;Summary&lt;/H4&gt;
&lt;P&gt;The steps in this blog are certainly not all-inclusive, and I keep coming up with other ideas as time goes on, but following these steps should help to prevent unauthorized access to your FTP service. All of the normal warnings about using strong passwords, changing your passwords often, using SSL whenever you can, and keeping your hotfixes up-to-date will always apply.&lt;/P&gt;
&lt;P&gt;But that being said, one of the ways that I keep finding new things to block is by simply watching my FTP log files to see what attackers are trying to do. By using some of the techniques that I discuss in my &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2009/06/11/using-logparser-with-ftp-7-x-sessions.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/2009/06/11/using-logparser-with-ftp-7-x-sessions.aspx"&gt;Using LogParser with FTP 7.x Sessions&lt;/A&gt; blog, you can monitor your FTP log files in order to analyze what would-be attackers are trying to do.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9893855" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Creating Recursive Directory Listing Files for FTP Clients</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/09/05/creating-recursive-directory-listing-files-for-ftp-clients.aspx</link><pubDate>Sat, 05 Sep 2009 22:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9891823</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9891823.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9891823</wfw:commentRss><description>&lt;P&gt;One of the changes that we made in FTP 7.0 and FTP 7.5 was to remove recursive directory listings, which are commonly retrieved by typing "&lt;CODE&gt;ls -lR&lt;/CODE&gt;" from a command-line FTP client, which should send a command like "&lt;CODE&gt;NLST -lR&lt;/CODE&gt;" over FTP to the server. There were several reasons why we decided to remove recursive directory listings, but the main reason was simply to reduce CPU usage on the server; recursive directory listing requests take a lot of resources to fulfill. With that in mind, both FTP 7.0 and FTP 7.5 will ignore the recursive switch on directory requests.&lt;/P&gt;
&lt;P&gt;That being said - quite often it's pretty handy to have a full directory listing from an FTP server. From a client perspective you could probably write script to automate an FTP client to create a recursive listing, but that's a lot of work. Back in my younger days when I ran FTP sites on Unix servers, I would always create two types of list files on my FTP servers for FTP clients to retrieve:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;"&lt;STRONG&gt;ls-lr.txt&lt;/STRONG&gt;" - I would create only one file of this type for my entire FTP server, which would go in the root of my FTP site and it would contain a full recursive listing of all files in my FTP site. &lt;/LI&gt;
&lt;LI&gt;"&lt;STRONG&gt;00index.txt&lt;/STRONG&gt;" - I would create one file of this type in each folder of my FTP site, and each index file would contain a listing of files and their descriptions for that folder. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Of course, anyone that's been around the Internet since the days before we had HTTP and the world-wide-web should know that I didn't come up with this idea on my own - I learned it from other FTP site administrators. (And anyone who remembers those days should also recognize those two files with a strange sense of nostalgia. 00index.txt files of course led to index.htm files when WWW sites came along later, but that's another story.)&lt;/P&gt;
&lt;P&gt;In any event, as I continued to host FTP sites over the years I have written various scripts to create recursive directory listings, and I thought that one of my scripts might make a good blog post. With that in mind, here is a Windows Script Host file that I created, which I named "ls-lr.vbs", and this script will create a recursive directory listing for an FTP site. I choose the Unix directory listing style for this script since that's the format that I have used for years and the broader number of FTP clients and users should recognize it.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: #000000"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;Option&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Explicit&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;On&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Error&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Resume&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Next
&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;' Declare all variables.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objArguments
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; strBaseFolder
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objFSO
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objFile
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objFolder
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objSubFolder
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; objSubFile
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; lngFolderCount
&lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; lngBaseCount
&lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objArguments = WScript.Arguments

&lt;SPAN style="COLOR: #008000"&gt;' Determine the number of command-line arguments.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Select&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Case&lt;/SPAN&gt; objArguments.Count
  &lt;SPAN style="COLOR: #0000ff"&gt;Case&lt;/SPAN&gt; 0:
    strBaseFolder = WScript.ScriptFullName
    strBaseFolder = Left(strBaseFolder,InStrRev(strBaseFolder,"&lt;SPAN style="COLOR: #8b0000"&gt;\"))
&lt;/SPAN&gt;  &lt;SPAN style="COLOR: #0000ff"&gt;Case&lt;/SPAN&gt; 1:
    strBaseFolder = objArguments(0)
  &lt;SPAN style="COLOR: #0000ff"&gt;Case&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Else&lt;/SPAN&gt;:
    MsgBox "&lt;SPAN style="COLOR: #8b0000"&gt;This script takes a single argument for the&lt;/SPAN&gt;" &amp;amp; vbCrLf &amp;amp; _
      "&lt;SPAN style="COLOR: #8b0000"&gt;starting directory, or specify no arguments&lt;/SPAN&gt;" &amp;amp; vbCrLf &amp;amp; _
      "&lt;SPAN style="COLOR: #8b0000"&gt;to use the current directory.&lt;/SPAN&gt;", vbInformation
&lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Select
&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;' Create a file system object.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objFSO = WScript.CreateObject("&lt;SPAN style="COLOR: #8b0000"&gt;Scripting.FileSystemObject&lt;/SPAN&gt;")

&lt;SPAN style="COLOR: #008000"&gt;' Test if the base folder exists.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; Right(strBaseFolder,1) &amp;lt;&amp;gt; "&lt;SPAN style="COLOR: #8b0000"&gt;\" Then strBaseFolder = strBaseFolder &amp;amp; &lt;/SPAN&gt;"\"&lt;SPAN style="COLOR: #8b0000"&gt;
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; objFSO.FolderExists(strBaseFolder) = &lt;SPAN style="COLOR: #0000ff"&gt;False&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    MsgBox "&lt;SPAN style="COLOR: #8b0000"&gt;The specified folder does not exist.&lt;/SPAN&gt;", vbCritical
    WScript.Quit
&lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If
&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;' Open the output file for the directory listing.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objFile = objFSO.CreateTextFile(strBaseFolder &amp;amp; "&lt;SPAN style="COLOR: #8b0000"&gt;ls-lr.txt&lt;/SPAN&gt;")
     
&lt;SPAN style="COLOR: #008000"&gt;' Define the initial values for the folder counters.&lt;/SPAN&gt;
lngFolderCount = 1
lngBaseCount = 0
  
&lt;SPAN style="COLOR: #008000"&gt;' Dimension an array to hold the folder names.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;ReDim&lt;/SPAN&gt; strFolders(1)
  
&lt;SPAN style="COLOR: #008000"&gt;' Store the root folder in the array.&lt;/SPAN&gt;
strFolders(lngFolderCount) = strBaseFolder
    
&lt;SPAN style="COLOR: #008000"&gt;' Loop while we still have folders to process.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;While&lt;/SPAN&gt; lngFolderCount &amp;lt;&amp;gt; lngBaseCount
  &lt;SPAN style="COLOR: #008000"&gt;' Set up a folder object to a base folder.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Set&lt;/SPAN&gt; objFolder = objFSO.GetFolder(strFolders(lngBaseCount+1))
  
  &lt;SPAN style="COLOR: #008000"&gt;' Output the folder name to the listing file.&lt;/SPAN&gt;
  objFile.WriteLine vbCrLf &amp;amp; _
    Replace(Mid(strFolders(lngBaseCount+1),Len(strBaseFolder)),"&lt;SPAN style="COLOR: #8b0000"&gt;\",&lt;/SPAN&gt;"/"&lt;SPAN style="COLOR: #8b0000"&gt;) &amp;amp; _
&lt;/SPAN&gt;    vbCrLf
  
  &lt;SPAN style="COLOR: #008000"&gt;' Loop through the collection of subfolders for the base folder.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;For&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Each&lt;/SPAN&gt; objSubFolder &lt;SPAN style="COLOR: #0000ff"&gt;In&lt;/SPAN&gt; objFolder.SubFolders
    &lt;SPAN style="COLOR: #008000"&gt;' Increment the folder count.&lt;/SPAN&gt;
    lngFolderCount = lngFolderCount + 1
    &lt;SPAN style="COLOR: #008000"&gt;' Increase the array size&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;ReDim&lt;/SPAN&gt; Preserve strFolders(lngFolderCount)
    &lt;SPAN style="COLOR: #008000"&gt;' Store the folder name in the array.&lt;/SPAN&gt;
    strFolders(lngFolderCount) = objSubFolder.Path
    &lt;SPAN style="COLOR: #008000"&gt;' Output the folder to the listing file.&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;Call&lt;/SPAN&gt; WriteEntry(objSubFolder)
  &lt;SPAN style="COLOR: #0000ff"&gt;Next&lt;/SPAN&gt;
  
  &lt;SPAN style="COLOR: #008000"&gt;' Loop through the collection of subfolders for the base folder.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;For&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Each&lt;/SPAN&gt; objSubFile &lt;SPAN style="COLOR: #0000ff"&gt;In&lt;/SPAN&gt; objFolder.Files
    &lt;SPAN style="COLOR: #008000"&gt;' Output the file to the listing file.&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;Call&lt;/SPAN&gt; WriteEntry(objSubFile)
  &lt;SPAN style="COLOR: #0000ff"&gt;Next&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #008000"&gt;' Increment the base folder counter.&lt;/SPAN&gt;
  lngBaseCount = lngBaseCount + 1
&lt;SPAN style="COLOR: #0000ff"&gt;Wend
&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Sub&lt;/SPAN&gt; WriteEntry(tmpObject)
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; tmpAttributes
  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; tmpSize
  
  &lt;SPAN style="COLOR: #008000"&gt;' Test for a symbolic link.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 1024) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;lrwxrwxrwx&lt;/SPAN&gt;"
    tmpSize = 0
  &lt;SPAN style="COLOR: #008000"&gt;' Test for a directory.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;ElseIf&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 16) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;drwxrwxrwx&lt;/SPAN&gt;"
    tmpSize = 0
  &lt;SPAN style="COLOR: #008000"&gt;' Otherwise - it's a file.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Else&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;-rwxrwxrwx&lt;/SPAN&gt;"
    tmpSize = tmpObject.Size
  &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;
  
  &lt;SPAN style="COLOR: #008000"&gt;' Test for a read-only object.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 1) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpAttributes = Replace(tmpAttributes,"&lt;SPAN style="COLOR: #8b0000"&gt;w&lt;/SPAN&gt;","&lt;SPAN style="COLOR: #8b0000"&gt;-&lt;/SPAN&gt;")
  &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;
  
  &lt;SPAN style="COLOR: #008000"&gt;' Write the list entry to the output file.&lt;/SPAN&gt;
  objFile.WriteLine tmpAttributes &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt;   1 owner    group &lt;/SPAN&gt;" &amp;amp; _
    Right(&lt;SPAN style="COLOR: #0000ff"&gt;String&lt;/SPAN&gt;(15,Chr(32)) &amp;amp; &lt;SPAN style="COLOR: #0000ff"&gt;CStr&lt;/SPAN&gt;(tmpSize),15) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt; &lt;/SPAN&gt;" &amp;amp; FormatDate(tmpObject.DateLastModified) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt; &lt;/SPAN&gt;" &amp;amp; tmpObject.Name
&lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Sub
&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;Function&lt;/SPAN&gt; FormatDate(tmpDate)
  FormatDate = &lt;SPAN style="COLOR: #0000ff"&gt;CStr&lt;/SPAN&gt;(Year(tmpDate)) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt;-&lt;/SPAN&gt;" &amp;amp; Right("&lt;SPAN style="COLOR: #8b0000"&gt;00&lt;/SPAN&gt;" &amp;amp; &lt;SPAN style="COLOR: #0000ff"&gt;CStr&lt;/SPAN&gt;(Month(tmpDate)),2) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt;-&lt;/SPAN&gt;" &amp;amp; Right("&lt;SPAN style="COLOR: #8b0000"&gt;00&lt;/SPAN&gt;" &amp;amp; &lt;SPAN style="COLOR: #0000ff"&gt;CStr&lt;/SPAN&gt;(Day(tmpDate)),2)
&lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;Function&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;To use the script, copy the code into Windows Notepad and save it to your computer as "ls-lr.vbs." If you double-click the script it will use the current folder to create a recursive folder listing, and if you run this script from a command-line it can take a single argument of a folder path, or you can pass no arguments to the script in order to use the current folder. In either case it will create a file named "ls-lr.txt" in the root of the destination folder that contains the recursive directory listing in Unix format.&lt;/P&gt;
&lt;P&gt;For example, the following listing was created from a folder in my music collection on my desktop computer:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;/

drwxrwxrwx   1 owner    group               0 2009-07-30 Against the Silence
dr-xr-xr-x   1 owner    group               0 2009-07-30 Collective
drwxrwxrwx   1 owner    group               0 2009-07-30 Speakeasy
-rwxrwxrwx   1 owner    group            2741 2009-09-05 ls-lr.txt

/Against the Silence

-rwxrwxrwx   1 owner    group         9386309 2009-07-30 01-Against the Silence.wma
-rwxrwxrwx   1 owner    group         3974684 2009-07-30 02-Side-Stage Syndrome.wma
-rwxrwxrwx   1 owner    group         7539014 2009-07-30 03-The Dash on my Headstone.wma
-rwxrwxrwx   1 owner    group         7244819 2009-07-30 04-Teeth Like Knives.wma
-rwxrwxrwx   1 owner    group         9910687 2009-07-30 05-The Band Played on.wma

/Collective

-r-xr-xr-x   1 owner    group         2767821 2009-03-05 At the Moment.wma
-r-xr-xr-x   1 owner    group         5259473 2009-03-05 Colt . 45.wma
-r-xr-xr-x   1 owner    group         2572687 2009-03-05 El Mariachi.wma
-r-xr-xr-x   1 owner    group         2395577 2009-03-05 Gold and Silver.wma
-r-xr-xr-x   1 owner    group         2269487 2009-03-05 Keep Waiting.wma
-r-xr-xr-x   1 owner    group         2050335 2009-03-05 Nighttown.wma
-r-xr-xr-x   1 owner    group         1458931 2009-03-05 Rise.wma
-r-xr-xr-x   1 owner    group         3140077 2009-03-05 Rivers Underneath.wma
-r-xr-xr-x   1 owner    group         2278489 2009-03-05 Sad Parade.wma
-r-xr-xr-x   1 owner    group         1909249 2009-03-05 The Hungry Wolf.wma
-r-xr-xr-x   1 owner    group         2467613 2009-03-05 Threshold.wma
-r-xr-xr-x   1 owner    group          795501 2009-03-05 Tranewreck.wma
-r-xr-xr-x   1 owner    group          417239 2009-03-05 Zzyzx.wma

/Speakeasy

-rwxrwxrwx   1 owner    group         4004604 2009-03-05 01-Minuteman.wma
-rwxrwxrwx   1 owner    group         6309752 2009-03-05 02-Sundown Motel.wma
-rwxrwxrwx   1 owner    group         5504122 2009-03-05 03-Keep Waiting.wma
-rwxrwxrwx   1 owner    group         2766262 2009-03-05 04-You Know How It Is.wma
-rwxrwxrwx   1 owner    group         7495952 2009-03-05 05-Rivers Underneath.wma
-rwxrwxrwx   1 owner    group         6294888 2009-03-05 06-Gold and Silver.wma
-rwxrwxrwx   1 owner    group         8062882 2009-03-05 07-Freefall.wma
-rwxrwxrwx   1 owner    group         4437286 2009-03-05 08-[Untitled].wma
-rwxrwxrwx   1 owner    group         3355592 2009-03-05 09-St. Eriksplan.wma
-rwxrwxrwx   1 owner    group         4966942 2009-03-05 10-Disquiet.wma
-rwxrwxrwx   1 owner    group         4788302 2009-03-05 11-Fascination Street.wma
-rwxrwxrwx   1 owner    group         7950944 2009-03-05 12-This Love.wma&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;SMALL&gt;(&lt;B&gt;Note/Disclaimer/etc.&lt;/B&gt;: It may or may not be obvious that this listing is for music from the band &lt;A href="http://en.wikipedia.org/wiki/Stavesacre" target=_blank mce_href="http://en.wikipedia.org/wiki/Stavesacre"&gt;Stavesacre&lt;/A&gt;, but just to be clear and avoid any RIAA entanglements - these files aren't actually hosted on any of my FTP sites; I used the script on my desktop computer to create a listing as an example for this blog.)&lt;/SMALL&gt;&lt;/P&gt;
&lt;P&gt;&lt;SMALL&gt;&lt;IMG src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/wink_smile.gif" mce_src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/wink_smile.gif"&gt;&lt;/SMALL&gt;&lt;/P&gt;
&lt;H3&gt;Customizing the Script Output&lt;/H3&gt;
&lt;P&gt;There are several customizations that you can do with this script, each of which has it's own benefits and drawbacks.&lt;/P&gt;
&lt;H4&gt;Adding Directory Sizes&lt;/H4&gt;
&lt;P&gt;It is trivial from a coding perspective to have the code calculate directory sizes since the &lt;I&gt;Folder&lt;/I&gt; object that I use has as &lt;I&gt;Size &lt;/I&gt;property, but it slows down the script exponentially to calculate that. That being said, if you're willing to take the performance hit, you can modify the highlighted section of the &lt;CODE&gt;WriteEntry()&lt;/CODE&gt; function as follows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: #000000"&gt;  &lt;SPAN style="COLOR: #008000"&gt;' Test for a symbolic link.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 1024) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;lrwxrwxrwx&lt;/SPAN&gt;"
    tmpSize = 0
  &lt;SPAN style="COLOR: #008000"&gt;' Test for a directory.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;ElseIf&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 16) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;drwxrwxrwx&lt;/SPAN&gt;"
    &lt;SPAN style="BACKGROUND-COLOR: #ffff99"&gt;tmpSize = tmpObject.Size&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #008000"&gt;' Otherwise - it's a file.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;Else&lt;/SPAN&gt;
    tmpAttributes = "&lt;SPAN style="COLOR: #8b0000"&gt;-rwxrwxrwx&lt;/SPAN&gt;"
    tmpSize = tmpObject.Size
  &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;This will insert the folder size into the output, but once again it will make the script much slower and take up considerably more CPU time to compute.&lt;/P&gt;
&lt;H4&gt;Uppercase Folder Names&amp;nbsp; and Lowercase File Names&lt;/H4&gt;
&lt;P&gt;Since Windows is a case-insensitive operating system, you can easily choose to display all of your folder names in all uppercase characters and your file names in all lowercase characters without causing any client confusion. This can be accomplished by adding the first highlighted section and modifying the second highlighted section of the &lt;CODE&gt;WriteEntry()&lt;/CODE&gt; function as follows:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffff99; COLOR: #000000"&gt;  &lt;SPAN style="COLOR: #0000ff"&gt;Dim&lt;/SPAN&gt; tmpName
  
  &lt;SPAN style="COLOR: #008000"&gt;' Test for a directory.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt; (tmpObject.Attributes &lt;SPAN style="COLOR: #0000ff"&gt;And&lt;/SPAN&gt; 16) &lt;SPAN style="COLOR: #0000ff"&gt;Then&lt;/SPAN&gt;
    tmpName = UCase(tmpObject.Name)
  &lt;SPAN style="COLOR: #0000ff"&gt;Else&lt;/SPAN&gt;
    tmpName = LCase(tmpObject.Name)
  &lt;SPAN style="COLOR: #0000ff"&gt;End&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;If&lt;/SPAN&gt;&lt;/PRE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: #000000"&gt;  &lt;SPAN style="COLOR: #008000"&gt;' Write the list entry to the output file.&lt;/SPAN&gt;
  objFile.WriteLine tmpAttributes &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt;   1 owner    group &lt;/SPAN&gt;" &amp;amp; _
    Right(&lt;SPAN style="COLOR: #0000ff"&gt;String&lt;/SPAN&gt;(15,Chr(32)) &amp;amp; &lt;SPAN style="COLOR: #0000ff"&gt;CStr&lt;/SPAN&gt;(tmpSize),15) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt; &lt;/SPAN&gt;" &amp;amp; FormatDate(tmpObject.DateLastModified) &amp;amp; _
    "&lt;SPAN style="COLOR: #8b0000"&gt; &lt;/SPAN&gt;" &amp;amp; &lt;SPAN style="BACKGROUND-COLOR: #ffff99"&gt;tmpName&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Parting Thoughts&lt;/H3&gt;
&lt;P&gt;There are other customizations that you can easily make, such as creating a string array to sort the files and folders for each folder listing as a single list rather than listing folders first and files second as the currently script does. But that slows down the script way too much, and I prefer to see folders listed before files anyway. (Which is why I always use &lt;KBD&gt;SET DIRCMD=/OGN&lt;/KBD&gt; for my command prompt sessions as well.)&lt;/P&gt;
&lt;P&gt;Another easy customization would be to change the &lt;CODE&gt;FormatDate()&lt;/CODE&gt; function to change the date format for the output file, which is why I used a function to do my date formatting. For example, you could easily use the &lt;CODE&gt;FormatDate()&lt;/CODE&gt; function as a wrapper for VBScript's built-in &lt;CODE&gt;FormatDateTime()&lt;/CODE&gt; function, and then use any of the &lt;CODE&gt;vbGeneralDate&lt;/CODE&gt;, &lt;CODE&gt;vbLongDate&lt;/CODE&gt;, &lt;CODE&gt;vbShortDate&lt;/CODE&gt;, etc. options to specify the format. You can also use your own customized logic to return the date string, so you don't need to feel limited by my examples.&lt;/P&gt;
&lt;P&gt;Another useful customization would be to compute the actual size for the resulting "ls-lr.txt" file and modify the output file to contain the correct file size. Currently the script in this blog adds an entry to the listing for the "ls-lr.txt" file, but that contains the temporary size of the output file as the script is running so it will seldom be accurate. (I usually run my script and update the "ls-lr.txt" file manually, but in some versions of this script I have had it ignore the "ls-lr.txt" file and remove it from the output listings.)&lt;/P&gt;
&lt;P&gt;In closing, this script may be doing more than it might actually need to do by way of checking for symbolic links and read-only attributes, which our FTP service doesn’t actually do, but it was very easy to add that code and it runs just as fast either way.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9891823" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Merging FTP Extensibility Walkthroughs - Part 2</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/08/19/merging-ftp-extensibility-walkthroughs-part-2.aspx</link><pubDate>Thu, 20 Aug 2009 06:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9876281</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9876281.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9876281</wfw:commentRss><description>&lt;P&gt;I had not intended to do a series on this subject when I wrote my original &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2009/07/23/merging-ftp-extensibility-walkthroughs.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/2009/07/23/merging-ftp-extensibility-walkthroughs.aspx"&gt;Merging FTP Extensibility Walkthroughs&lt;/A&gt; blog post, but I came up with a scenario that I felt was worth sharing. I recently posted the following walkthrough on the &lt;A href="http://learn.iis.net/" target=_blank mce_href="http://learn.iis.net/"&gt;learn.iis.net&lt;/A&gt; web site:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/" target=_blank mce_href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/"&gt;How to Use Managed Code (C#) to Create an FTP Authentication Provider with Dynamic IP Restrictions&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;We have had many customer requests for a dynamic IP restrictions provider for the FTP server, and I wanted to get that out to customers as soon as I could. That being said, like several of my extensibility walkthroughs in the past, I wrote and tested the provider in that walkthrough on one of the servers that I manage. To show how effective it was, within the first couple of hours the provider had caught and blocked its first script kiddie who was attempting a brute force attack on my FTP server. Over the next few days the provider caught its next hacker, and over the past few weeks it has continued to do so.&lt;/P&gt;
&lt;P&gt;That being said, I thought that it might be nice to know when an IP address was blocked, and I had already written the following walkthrough:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://learn.iis.net/page.aspx/632/how-to-use-managed-code-c-to-create-an-ftp-provider-that-sends-an-email-when-files-are-uploaded/" target=_blank mce_href="http://learn.iis.net/page.aspx/632/how-to-use-managed-code-c-to-create-an-ftp-provider-that-sends-an-email-when-files-are-uploaded/"&gt;How to Use Managed Code (C#) to Create an FTP Provider that Sends an Email when Files are Uploaded&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;With that in mind, merging the two walkthroughs seemed like a simple thing to do.&lt;/P&gt;
&lt;P&gt;Before continuing I need to reiterate the notice that I added to the dynamic IP restrictions walkthrough:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;IMPORTANT NOTE&lt;/B&gt;: The latest version of the FTP 7.5 service &lt;U&gt;&lt;B&gt;must be&lt;/B&gt;&lt;/U&gt; installed in order to use the provider in this walkthrough. A version FTP 7.5 was released on August 3, 2009 that addressed an issue where the local and remote IP addresses in the &lt;B&gt;IFtpLogProvider.Log()&lt;/B&gt; method were incorrect. Because of this, using an earlier version of the FTP service will prevent this provider from working.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;With that warning out of the way, here are the steps that you need to follow in order to merge the two walkthroughs:&lt;/P&gt;
&lt;H5&gt;Step 1 - Create the project&lt;/H5&gt;
&lt;P&gt;Create a new C# project following all of the steps in the &lt;A href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/" target=_blank mce_href="http://learn.iis.net/page.aspx/673/how-to-use-managed-code-c-to-create-an-ftp-authentication-provider-with-dynamic-ip-restrictions/"&gt;How to Use Managed Code (C#) to Create an FTP Authentication Provider with Dynamic IP Restrictions&lt;/A&gt; walkthrough.&lt;/P&gt;
&lt;H5&gt;Step 2 - Merge global variables&lt;/H5&gt;
&lt;P&gt;In this step you need to merge the global variables from the two walkthroughs. In my provider this looked like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: black"&gt;&lt;SPAN style="COLOR: #008000"&gt;// Define the default values - these are only&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// used if the configuration settings are not set.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;const&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; defaultLogonAttempts = 5;
&lt;SPAN style="COLOR: #0000ff"&gt;const&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; defaultFloodSeconds = 30;
&lt;SPAN style="COLOR: #0000ff"&gt;const&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; defaultSmtpPort = 25;

&lt;SPAN style="COLOR: #008000"&gt;// Define a connection string with no default.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _connectionString;

&lt;SPAN style="COLOR: #008000"&gt;// Initialize the private variables with the default values.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; _logonAttempts = defaultLogonAttempts;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; _floodSeconds = defaultFloodSeconds;

&lt;SPAN style="COLOR: #008000"&gt;// Flag the application as uninitialized.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;bool&lt;/SPAN&gt; _initialized = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;

&lt;SPAN style="COLOR: #008000"&gt;// Define a list that will contain the list of flagged sessions.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; List&amp;lt;&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;&amp;gt; _flaggedSessions;

&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _smtpServerName;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _smtpFromAddress;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _smtpToAddress;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; _smtpServerPort;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;Step 3 - Merge the Initialize() methods&lt;/H5&gt;
&lt;P&gt;In this step you need to merge the Initialize() methods from the two walkthroughs so that all of the settings are retrieved from the IIS configuration file when the provider is loaded by the FTP service. In my provider this looked like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: black"&gt;&lt;SPAN style="COLOR: #008000"&gt;// Initialize the provider.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;protected&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Initialize(StringDictionary config)
{
    &lt;SPAN style="COLOR: #008000"&gt;// Test if the application has already been initialized.&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (_initialized == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: #008000"&gt;// Create the flagged sessions list.&lt;/SPAN&gt;
        _flaggedSessions = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; List&amp;lt;&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;&amp;gt;();
        
        &lt;SPAN style="COLOR: #008000"&gt;// Retrieve the connection string for the database connection.&lt;/SPAN&gt;
        _connectionString = config[&lt;SPAN style="COLOR: #800000"&gt;"connectionString"&lt;/SPAN&gt;];
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_connectionString))
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Raise an exception if the connection string is missing or empty.&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(
                &lt;SPAN style="COLOR: #800000"&gt;"Missing connectionString value in configuration."&lt;/SPAN&gt;);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Determine whether the database is a Microsoft Access database.&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (_connectionString.Contains(&lt;SPAN style="COLOR: #800000"&gt;"Microsoft.Jet"&lt;/SPAN&gt;))
            {
                &lt;SPAN style="COLOR: #008000"&gt;// Throw an exception if the database is a Microsoft Access database.&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ProviderException(&lt;SPAN style="COLOR: #800000"&gt;"Microsoft Access databases are not supported."&lt;/SPAN&gt;);
            }
        }
        
        &lt;SPAN style="COLOR: #008000"&gt;// Retrieve the number of failures before an IP&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #008000"&gt;// address is locked out - or use the default value.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.TryParse(config[&lt;SPAN style="COLOR: #800000"&gt;"logonAttempts"&lt;/SPAN&gt;], &lt;SPAN style="COLOR: #0000ff"&gt;out&lt;/SPAN&gt; _logonAttempts) == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Set to the default if the number of logon attempts is not valid.&lt;/SPAN&gt;
            _logonAttempts = defaultLogonAttempts;
        }
        
        &lt;SPAN style="COLOR: #008000"&gt;// Retrieve the number of seconds for flood&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #008000"&gt;// prevention - or use the default value.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.TryParse(config[&lt;SPAN style="COLOR: #800000"&gt;"floodSeconds"&lt;/SPAN&gt;], &lt;SPAN style="COLOR: #0000ff"&gt;out&lt;/SPAN&gt; _floodSeconds) == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Set to the default if the number of logon attempts is not valid.&lt;/SPAN&gt;
            _floodSeconds = defaultFloodSeconds;
        }
        
        &lt;SPAN style="COLOR: #008000"&gt;// Test if the number is a positive integer and less than 10 minutes.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ((_floodSeconds &amp;lt;= 0) || (_floodSeconds &amp;gt; 600))
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Set to the default if the number of logon attempts is not valid.&lt;/SPAN&gt;
            _floodSeconds = defaultFloodSeconds;
        }
        
        &lt;SPAN style="COLOR: #008000"&gt;// Retrieve the email settings from configuration.&lt;/SPAN&gt;
        _smtpServerName = config[&lt;SPAN style="COLOR: #800000"&gt;"smtpServerName"&lt;/SPAN&gt;];
        _smtpFromAddress = config[&lt;SPAN style="COLOR: #800000"&gt;"smtpFromAddress"&lt;/SPAN&gt;];
        _smtpToAddress = config[&lt;SPAN style="COLOR: #800000"&gt;"smtpToAddress"&lt;/SPAN&gt;];
        
        &lt;SPAN style="COLOR: #008000"&gt;// Detect and handle any mis-configured settings.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (!&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.TryParse(config[&lt;SPAN style="COLOR: #800000"&gt;"smtpServerPort"&lt;/SPAN&gt;], &lt;SPAN style="COLOR: #0000ff"&gt;out&lt;/SPAN&gt; _smtpServerPort))
        {
            _smtpServerPort = defaultSmtpPort;
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_smtpServerName))
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(
                &lt;SPAN style="COLOR: #800000"&gt;"Missing smtpServerName value in configuration."&lt;/SPAN&gt;);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_smtpFromAddress))
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(
                &lt;SPAN style="COLOR: #800000"&gt;"Missing smtpFromAddress value in configuration."&lt;/SPAN&gt;);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_smtpToAddress))
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(
                &lt;SPAN style="COLOR: #800000"&gt;"Missing smtpToAddress value in configuration."&lt;/SPAN&gt;);
        }
        
        &lt;SPAN style="COLOR: #008000"&gt;// Initial garbage collection.&lt;/SPAN&gt;
        GarbageCollection(&lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;);
        
        &lt;SPAN style="COLOR: #008000"&gt;// Flag the provider as initialized.&lt;/SPAN&gt;
        _initialized = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;
    }
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;Step 4 - Add a SendEmail() method&lt;/H5&gt;
&lt;P&gt;For this step I copied some of my code from the email walkthrough and used it as the foundation for a new SendEmail() method that I added to the provider. In my provider this looked like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: black"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; SendEmail(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; emailSubject, &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; emailMessage)
{
    &lt;SPAN style="COLOR: #008000"&gt;// Create an SMTP message.&lt;/SPAN&gt;
    SmtpClient smtpClient = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; SmtpClient(_smtpServerName, _smtpServerPort);
    MailAddress mailFromAddress = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; MailAddress(_smtpFromAddress);
    MailAddress mailToAddress = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; MailAddress(_smtpToAddress);
    
    &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; (MailMessage mailMessage = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; MailMessage(mailFromAddress, mailToAddress))
    {
        &lt;SPAN style="COLOR: #0000ff"&gt;try&lt;/SPAN&gt;
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Format the SMTP message as UTF8.&lt;/SPAN&gt;
            mailMessage.BodyEncoding = Encoding.UTF8;
            &lt;SPAN style="COLOR: #008000"&gt;// Add the subject.&lt;/SPAN&gt;
            mailMessage.Subject = emailSubject;
            &lt;SPAN style="COLOR: #008000"&gt;// Add the body.&lt;/SPAN&gt;
            mailMessage.Body = emailMessage;
            &lt;SPAN style="COLOR: #008000"&gt;// Send the email message.&lt;/SPAN&gt;
            smtpClient.Send(mailMessage);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; (SmtpException ex)
        {
            &lt;SPAN style="COLOR: #008000"&gt;// Send an exception message to the debug&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #008000"&gt;// channel if the email fails to send.&lt;/SPAN&gt;
            Debug.WriteLine(ex.Message);
        }
    }
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: This uses the settings that you store in your IIS applicationHost.config file and are loaded by the Initialize() method.&lt;/P&gt;
&lt;H5&gt;Step 5 - Add email functionality to the BanAddress() method&lt;/H5&gt;
&lt;P&gt;In this step you add the functionality to send an email whenever an IP address is added to the list of banned IP addresses. In my provider this looked like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="BACKGROUND-COLOR: #ffffff; COLOR: black"&gt;&lt;SPAN style="COLOR: #008000"&gt;// Mark an IP address as banned.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; BanAddress(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; ipAddress)
{
    &lt;SPAN style="COLOR: #008000"&gt;// Check if the IP address is already banned.&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (IsAddressBanned(ipAddress) == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)
    {
        &lt;SPAN style="COLOR: #008000"&gt;// Ban the IP address if it is not already banned.&lt;/SPAN&gt;
        InsertDataIntoTable(&lt;SPAN style="COLOR: #800000"&gt;"[BannedAddresses]"&lt;/SPAN&gt;,
            &lt;SPAN style="COLOR: #800000"&gt;"[IPAddress]"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #800000"&gt;"'"&lt;/SPAN&gt; + ipAddress + &lt;SPAN style="COLOR: #800000"&gt;"'"&lt;/SPAN&gt;);
        &lt;SPAN style="COLOR: #008000"&gt;// Send an email for the banned address.&lt;/SPAN&gt;
        SendEmail(&lt;SPAN style="COLOR: #800000"&gt;"Banned IP Address"&lt;/SPAN&gt;,
            &lt;SPAN style="COLOR: #800000"&gt;"The IP address "&lt;/SPAN&gt; + ipAddress + &lt;SPAN style="COLOR: #800000"&gt;" was banned."&lt;/SPAN&gt;);
    }
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;Step 6 - Methods that are &lt;U&gt;&lt;I&gt;not&lt;/I&gt;&lt;/U&gt; changed&lt;/H5&gt;
&lt;P&gt;I need to point out that there are several methods that require no changes. These methods are listed here for reference:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Dispose() &lt;/LI&gt;
&lt;LI&gt;AuthenticateUser() &lt;/LI&gt;
&lt;LI&gt;Log() &lt;/LI&gt;
&lt;LI&gt;IsValidUser() &lt;/LI&gt;
&lt;LI&gt;IsAddressBanned() &lt;/LI&gt;
&lt;LI&gt;IsSessionFlagged() &lt;/LI&gt;
&lt;LI&gt;FlagSession() &lt;/LI&gt;
&lt;LI&gt;GarbageCollection &lt;/LI&gt;
&lt;LI&gt;GetRecordCountByCriteria() &lt;/LI&gt;
&lt;LI&gt;InsertDataIntoTable() &lt;/LI&gt;
&lt;LI&gt;DeleteRecordsByCriteria() &lt;/LI&gt;
&lt;LI&gt;ExecuteQuery() &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: You could easily add the email functionality to the FlagSession() method so you will see when a banned IP address is trying to access your server, but depending on the number of sessions that are flagged on your server you might receive more emails than you really need.&lt;/P&gt;
&lt;H5&gt;Step 7 - Register the provider and configure your settings&lt;/H5&gt;
&lt;P&gt;In this last step you add the provider to your IIS configuration settings using the AppCmd utility, and you specify the values for the various settings that the provider requires:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;KBD&gt;cd %SystemRoot%\System32\Inetsrv &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"[name='FtpAddressRestrictionAuthentication',type='FtpAddressRestrictionAuthentication,FtpAddressRestrictionAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='smtpServerName',value='localhost']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='smtpServerPort',value='25']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='smtpFromAddress',value='someone@contoso.com']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='smtpToAddress',value='someone@contoso.com']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='connectionString',value='Server=localhost;Database=FtpAuthentication;User ID=FtpLogin;Password=P@ssw0rd']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='logonAttempts',value='5']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpAddressRestrictionAuthentication'].[key='floodSeconds',value='30']" /commit:apphost&lt;/KBD&gt; &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: You need to update the above syntax using the managed type information for your provider and the configuration settings for your SMTP server, email addresses, and database connection string.&lt;/P&gt;
&lt;H5&gt;Step 8 - Add the provider to a site&lt;/H5&gt;
&lt;P&gt;In this last step you add the provider to a site. If you were adding the provider to your Default Web Site that would look like the following:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;KBD&gt;AppCmd.exe set config -section:system.applicationHost/sites /"[name='Default Web Site'].ftpServer.security.authentication.basicAuthentication.enabled:False" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd.exe set config -section:system.applicationHost/sites /+"[name='Default Web Site'].ftpServer.security.authentication.customAuthentication.providers.[name='FtpAddressRestrictionAuthentication',enabled='True']" /commit:apphost &lt;BR&gt;&lt;BR&gt;AppCmd set site "Default Web Site" /+ftpServer.customFeatures.providers.[name='FtpAddressRestrictionAuthentication',enabled='true'] /commit:apphost &lt;/KBD&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;H4&gt;Summary&lt;/H4&gt;
&lt;P&gt;That wraps it up for today's post, and I hope you find it useful. &lt;IMG alt=Smile src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif" mce_src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif"&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9876281" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Automatically Creating Checksum Files for FTP Uploads</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/07/30/automatically-creating-checksum-files-for-ftp-uploads.aspx</link><pubDate>Fri, 31 Jul 2009 04:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9853914</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9853914.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9853914</wfw:commentRss><description>&lt;P&gt;I had a great question in the publishing forums on &lt;A href="http://forums.iis.net/" mce_href="http://forums.iis.net/"&gt;forums.iis.net&lt;/A&gt;, where someone was asking if FTP 7 supported the XCRC command. The short answer is that the XCRC command is not supported, but I came up with a way to create an FTP provider that supports something &lt;I&gt;like&lt;/I&gt; it. Since it was a rather fun code sample to write, I thought that I'd turn it into a blog. &lt;/P&gt;
&lt;P&gt;The sample FTP provider code in this blog post will automatically calculate an MD5 checksum from a file that is uploaded and store it in a file with a "*.MD5.TXT" file name extension. You can then compare the uploaded checksum with a local checksum on the client to verify the uploaded file's integrity.&lt;/P&gt;
&lt;P&gt;There are a few points that I need to discuss before I present the code sample:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;I chose to use MD5 because it is built-in to the .NET System.Security.Cryptography namespace and I often like to use MD5 for file checksums. I could just have easily implemented SHA1, SHA256, or any of the other built-in hashing algorithms. Unfortunately, CRC32 is not a built-in algorithm for .NET, but a quick search around the Internet yielded several CRC32 samples in C# from various developers, so if you specifically need the CRC32 algorithm you can find it pretty quickly and substitute it for MD5 in my example. (&lt;A href="http://www.bing.com/search?q=C%23+CRC32" target=_blank mce_href="http://www.bing.com/search?q=C%23+CRC32"&gt;You can click here to search for examples&lt;/A&gt;.) You could go one step further and have your provider support multiple checksum algorithms, but that's going way outside the scope of this blog.&lt;/LI&gt;
&lt;LI&gt;There are a couple of security considerations for this provider: 
&lt;UL&gt;
&lt;LI&gt;The provider needs to calculate the path of the uploaded file, and to do so requires calling into the IIS configuration APIs. As I mention in the code remarks: 
&lt;UL&gt;
&lt;LI&gt;The FTP service will host the compiled assembly in the "Microsoft FTP Service Extensibility Host" COM+ package (DLLHOST.EXE), which runs by default as NETWORK SERVICE.&lt;/LI&gt;
&lt;LI&gt;Also by default, the NETWORK SERVICE account does not have sufficient privileges to read the IIS configuration settings. As such, you must either grant READ permissions to NETWORK SERVICE for the IIS configuration files, or configure the COM+ package to run as a user that has at least READ access to the files in the InetSrv\config folder.&lt;/LI&gt;
&lt;LI&gt;By default, the NETWORK SERVICE account may not have WRITE permission to the folder where your files are uploaded, so the checksum files cannot be written. As such, you will need to grant READ/WRITE access to the destination where the checksum files will be written.&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;The above steps are not generally recommended practices; but if you choose to grant NETWORK SERVICE permission to the configuration files, the remarks section in the code sample provides the details that you need.&lt;/LI&gt;
&lt;LI&gt;Alternatively, you could skip the path lookup and always store the checksum files in a known location. This allows you to remove the &lt;B&gt;MapSiteRootPath()&lt;/B&gt; and &lt;B&gt;FindElement()&lt;/B&gt; methods from the code sample, and you need only grant the NETWORK SERVICE account permission for the known location.&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;The &lt;B&gt;MapSiteRootPath()&lt;/B&gt; method in the provider sample calculates the path of the site's root, then uses the relative path of the uploaded file to compute the full path to the checksum file. This does not take into account any paths that include virtual directories; as such, you would need to accommodate for any virtual paths in your site's hierarchy. (That's too much code for this blog post.)&lt;/LI&gt;
&lt;LI&gt;The provider defines a 1 GB constant for the maximum file size for computing checksums. I specified this value so that large files would not tie up your system's resources. You can increase or decrease that value, you could make that a parameter that is stored in the provider's settings, or you can remove the functionality completely. This provider runs synchronously, so larger files will obviously take more time. While it's outside the scope of this blog, you could implement some form of asynchronous functionality. (When discussing this provider with &lt;A href="http://blogs.msdn.com/danielvl/" target=_blank mce_href="http://blogs.msdn.com/danielvl/"&gt;Daniel Vasquez Lopez&lt;/A&gt;, he suggested using MSMQ - but that's &lt;I&gt;really&lt;/I&gt; going way beyond the scope of what I wanted to accomplish with this blog.)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;All of that being said, this provider follows the same development path as the provider in my &lt;A href="http://learn.iis.net/page.aspx/602/how-to-use-managed-code-c-to-create-a-simple-ftp-logging-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/602/how-to-use-managed-code-c-to-create-a-simple-ftp-logging-provider/"&gt;How to Use Managed Code (C#) to Create a Simple FTP Logging Provider&lt;/A&gt; walkthrough, so if you follow the steps in that walkthrough and substitute "&lt;B&gt;FtpUploadChecksumDemo&lt;/B&gt;" every place that you see "&lt;B&gt;FtpLoggingDemo&lt;/B&gt;" and add a reference to &lt;B&gt;Microsoft.Web.Administration&lt;/B&gt;, you should have all of the steps that you need in order to use this provider.&lt;/P&gt;
&lt;P&gt;So without further discussion, here's the code for the provider:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Configuration.Provider;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.IO;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Security.Cryptography;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Text;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; Microsoft.Web.Administration;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; Microsoft.Web.FtpServer;

&lt;SPAN style="COLOR: #008000"&gt;// NOTE: This code is provided "as-is" and comes with the following security&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// considerations. The FTP service will host the compiled assembly in the&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// "Microsoft FTP Service Extensibility Host" COM+ package (DLLHOST.EXE),&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// which runs by default as NETWORK SERVICE. By default, this account does not&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// have sufficient privileges to read the IIS configuration settings. As such,&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// you must either grant READ permissions to NETWORK SERVICE for the configuration&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// files, or configure the COM+ package to run as a user that has at least READ&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// access to the files in the InetSrv\config folder and READ/WRITE access to the&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// destination where the checksum file will be written. However, these are not&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// generally recommended practices.&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// If you choose to grant NETWORK SERVICE permission to the configuration files,&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// the following three commands should accomplish the requisite permissions:&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//  cacls "%SystemRoot%\System32\inetsrv\config" /G "Network Service":R /E&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//  cacls "%SystemRoot%\System32\inetsrv\config\redirection.config" /G "Network Service":R /E&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//  cacls "%SystemRoot%\System32\inetsrv\config\applicationHost.config" /G "Network Service":R /E&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;//&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// NOTE: You will need to do something similar for your content directory so that&lt;/SPAN&gt;
&lt;SPAN style="COLOR: #008000"&gt;// the checksum files can be created.&lt;/SPAN&gt;

&lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;sealed&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; FtpUploadChecksumDemo : BaseProvider, IFtpLogProvider
{
  &lt;SPAN style="COLOR: #008000"&gt;// Implement the logging method.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; IFtpLogProvider.Log(FtpLogEntry loggingParameters)
  {
    &lt;SPAN style="COLOR: #008000"&gt;// Test for a successful file upload operation.&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ((loggingParameters.Command == &lt;SPAN style="COLOR: #800000"&gt;"STOR"&lt;/SPAN&gt;) &amp;amp;&amp;amp; 
      (loggingParameters.FtpStatus == 226))
    {
      &lt;SPAN style="COLOR: #0000ff"&gt;try&lt;/SPAN&gt;
      {
        &lt;SPAN style="COLOR: #008000"&gt;// Define a 1GB maximum length - to prevent system hogging.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;const&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; maxLength = 0x3fffffff;

        &lt;SPAN style="COLOR: #008000"&gt;// Map the path to the site root.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; fullPath = MapSiteRootPath(loggingParameters.SiteName);
        &lt;SPAN style="COLOR: #008000"&gt;// Append the relative path of the uploaded file.&lt;/SPAN&gt;
        fullPath += loggingParameters.FullPath;
        &lt;SPAN style="COLOR: #008000"&gt;// Expand any environment variables.&lt;/SPAN&gt;
        fullPath = Environment.ExpandEnvironmentVariables(fullPath);
        &lt;SPAN style="COLOR: #008000"&gt;// Convert forward slashes to back slashes&lt;/SPAN&gt;
        fullPath = fullPath.Replace(&lt;SPAN style="COLOR: #800000"&gt;@"/"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #800000"&gt;@"\"&lt;/SPAN&gt;);

        &lt;SPAN style="COLOR: #008000"&gt;// Open the uploaded file to create a CRC.&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; (FileStream input = File.Open(
          fullPath,
          FileMode.Open,
          FileAccess.Read,
          FileShare.Read))
        {
          &lt;SPAN style="COLOR: #008000"&gt;// Test the input file length.&lt;/SPAN&gt;
          &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (input.Length &amp;gt; maxLength)
          {
            &lt;SPAN style="COLOR: #008000"&gt;// Throw an execption if the file is too big.&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ProviderException(
              String.Format(&lt;SPAN style="COLOR: #800000"&gt;"Input file is too large: {0}"&lt;/SPAN&gt;,
              input.Length.ToString()));
          }
          &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;
          {
            &lt;SPAN style="COLOR: #008000"&gt;// Open the hash file for output.&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; (StreamWriter output = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; StreamWriter(
              fullPath + &lt;SPAN style="COLOR: #800000"&gt;".MD5.txt"&lt;/SPAN&gt;,
              &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;))
            {
              &lt;SPAN style="COLOR: #008000"&gt;// Create an MD5 object.&lt;/SPAN&gt;
              MD5 md5 = MD5.Create();
              &lt;SPAN style="COLOR: #008000"&gt;// Retrieve the hash byte array.&lt;/SPAN&gt;
              &lt;SPAN style="COLOR: #0000ff"&gt;byte&lt;/SPAN&gt;[] byteArray = md5.ComputeHash(input);
              &lt;SPAN style="COLOR: #008000"&gt;// Create a new string builder for the ASCII hash string.&lt;/SPAN&gt;
              StringBuilder stringBuilder =
                &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; StringBuilder(byteArray.Length * 2);
              &lt;SPAN style="COLOR: #008000"&gt;// Loop through the hash.&lt;/SPAN&gt;
              &lt;SPAN style="COLOR: #0000ff"&gt;foreach&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;byte&lt;/SPAN&gt; byteMember &lt;SPAN style="COLOR: #0000ff"&gt;in&lt;/SPAN&gt; byteArray)
              {
                &lt;SPAN style="COLOR: #008000"&gt;// Append each ASCII hex byte to the hash string.&lt;/SPAN&gt;
                stringBuilder.AppendFormat(&lt;SPAN style="COLOR: #800000"&gt;"{0:x2}"&lt;/SPAN&gt;, byteMember);
              }
              &lt;SPAN style="COLOR: #008000"&gt;// Write the hash string to the output file.&lt;/SPAN&gt;
              output.Write(stringBuilder);
            }
          }
        }
      }
      &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt;(Exception ex)
      {
        &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ProviderException(ex.Message);
      }
    }
  }

  &lt;SPAN style="COLOR: #008000"&gt;// This method is almost 100% from scripts that were created&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #008000"&gt;// by the IIS Manager Configuration Editor admin pack tool.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; MapSiteRootPath(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; siteName)
  {
    &lt;SPAN style="COLOR: #0000ff"&gt;try&lt;/SPAN&gt;
    {
      &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; (ServerManager serverManager = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ServerManager())
      {
        Configuration config =
          serverManager.GetApplicationHostConfiguration();
        ConfigurationSection sitesSection =
          config.GetSection(&lt;SPAN style="COLOR: #800000"&gt;"system.applicationHost/sites"&lt;/SPAN&gt;);
        ConfigurationElementCollection sitesCollection =
          sitesSection.GetCollection();
        ConfigurationElement siteElement =
          FindElement(sitesCollection, &lt;SPAN style="COLOR: #800000"&gt;"site"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #800000"&gt;"name"&lt;/SPAN&gt;, siteName);
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (siteElement == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
        {
          &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; InvalidOperationException(&lt;SPAN style="COLOR: #800000"&gt;"Element not found!"&lt;/SPAN&gt;);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;
        {
          ConfigurationElementCollection siteCollection =
            siteElement.GetCollection();
          ConfigurationElement applicationElement =
            FindElement(siteCollection,
            &lt;SPAN style="COLOR: #800000"&gt;"application"&lt;/SPAN&gt;,
            &lt;SPAN style="COLOR: #800000"&gt;"path"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #800000"&gt;@"/"&lt;/SPAN&gt;);
          &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (applicationElement == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
          {
            &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; InvalidOperationException(&lt;SPAN style="COLOR: #800000"&gt;"Element not found!"&lt;/SPAN&gt;);
          }
          &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;
          {
            ConfigurationElementCollection applicationCollection =
              applicationElement.GetCollection();
            ConfigurationElement virtualDirectoryElement =
              FindElement(applicationCollection,
              &lt;SPAN style="COLOR: #800000"&gt;"virtualDirectory"&lt;/SPAN&gt;,
              &lt;SPAN style="COLOR: #800000"&gt;"path"&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #800000"&gt;@"/"&lt;/SPAN&gt;);
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (virtualDirectoryElement == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
            {
              &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; InvalidOperationException(&lt;SPAN style="COLOR: #800000"&gt;"Element not found!"&lt;/SPAN&gt;);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;
            {
              &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; virtualDirectoryElement[&lt;SPAN style="COLOR: #800000"&gt;"physicalPath"&lt;/SPAN&gt;].ToString();
            }
          }
        }
      }
    }
    &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; (Exception ex)
    {
      &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ProviderException(ex.Message);
    }
  }

  &lt;SPAN style="COLOR: #008000"&gt;// This method is almost 100% from scripts that were created&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #008000"&gt;// by the IIS Manager Configuration Editor admin pack tool.&lt;/SPAN&gt;
  &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; ConfigurationElement FindElement(
    ConfigurationElementCollection collection,
    &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; elementTagName,
    &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;[] keyValues)
  {
    &lt;SPAN style="COLOR: #0000ff"&gt;foreach&lt;/SPAN&gt; (ConfigurationElement element &lt;SPAN style="COLOR: #0000ff"&gt;in&lt;/SPAN&gt; collection)
    {
      &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (String.Equals(element.ElementTagName,
        elementTagName,
        StringComparison.OrdinalIgnoreCase))
      {
        &lt;SPAN style="COLOR: #0000ff"&gt;bool&lt;/SPAN&gt; matches = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;

        &lt;SPAN style="COLOR: #0000ff"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; keyValues.Length; i += 2)
        {
          &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; o = element.GetAttributeValue(keyValues[i]);
          &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;value&lt;/SPAN&gt; = &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;;
          &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (o != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
          {
            &lt;SPAN style="COLOR: #0000ff"&gt;value&lt;/SPAN&gt; = o.ToString();
          }

          &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (!String.Equals(&lt;SPAN style="COLOR: #0000ff"&gt;value&lt;/SPAN&gt;,
            keyValues[i + 1],
            StringComparison.OrdinalIgnoreCase))
          {
            matches = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;
            &lt;SPAN style="COLOR: #0000ff"&gt;break&lt;/SPAN&gt;;
          }
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (matches)
        {
          &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; element;
        }
      }
    }
    &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;;
  }
}
&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;That wraps it up for today's post.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif" mce_src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif"&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9853914" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Merging FTP Extensibility Walkthroughs</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/07/23/merging-ftp-extensibility-walkthroughs.aspx</link><pubDate>Thu, 23 Jul 2009 19:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9846647</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9846647.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9846647</wfw:commentRss><description>&lt;P&gt;Over the past several months I’ve been publishing a series of walkthroughs that use the extensibility in FTP 7.5 to create a several custom providers for a variety of scenarios, and today I posted my most recent entry in the series:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/" target=_blank mce_href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/"&gt;How to Use Managed Code to Create an FTP Authentication Provider using an XML Database&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As a piece of behind-the-scenes trivia, some of these walkthroughs were based off custom providers that I had actually written for my FTP servers, and I used the samples that I wrote for some of the other walkthroughs as a starting point for custom providers that I currently use. With that in mind, I’d like to use today’s blog to talk about some of the ways that I combine what you see in a few of these walkthroughs into some useful scenarios.&lt;/P&gt;
&lt;P&gt;One of the common providers that I use is a combination of the code that you see in these two walkthroughs:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/" target=_blank mce_href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/"&gt;How to Use Managed Code to Create an FTP Authentication Provider using an XML Database&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/600/how-to-use-managed-code-to-create-a-simple-ftp-home-directory-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/600/how-to-use-managed-code-to-create-a-simple-ftp-home-directory-provider/"&gt;How to Use Managed Code to Create a Simple FTP Home Directory Provider&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Here's the way that I create the provider - I start with a single provider class that implements the &lt;B&gt;IFtpHomeDirectoryProvider&lt;/B&gt;, &lt;B&gt;IFtpAuthenticationProvider&lt;/B&gt;, and &lt;B&gt;IFtpRoleProvider&lt;/B&gt; interfaces, and I create a few global variables that I'll use later.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; FtpXmlAuthentication : BaseProvider,
    IFtpHomeDirectoryProvider,
    IFtpAuthenticationProvider,
    IFtpRoleProvider
{
    &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _XmlFileName;

    &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; _HomeDirectory;

    &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; Dictionary&amp;lt;&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;, XmlUserData&amp;gt; _XmlUserData =
        &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; Dictionary&amp;lt;&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;, XmlUserData&amp;gt;(
            StringComparer.InvariantCultureIgnoreCase);
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I add an &lt;B&gt;Initialize()&lt;/B&gt; method to the class, where I load the values named &lt;B&gt;xmlFileName&lt;/B&gt; and &lt;B&gt;homeDirectory&lt;/B&gt; from the configuration settings.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;protected&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Initialize(StringDictionary config)
{
    _XmlFileName = config[&lt;SPAN style="COLOR: #800000"&gt;"xmlFileName"&lt;/SPAN&gt;];
    _HomeDirectory = config[&lt;SPAN style="COLOR: #800000"&gt;"homeDirectory"&lt;/SPAN&gt;];
    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_XmlFileName))
    {
        &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(&lt;SPAN style="COLOR: #800000"&gt;"Missing xmlFileName value in configuration."&lt;/SPAN&gt;);
    }
}&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I recycle the provider across a bunch of different FTP sites, and I don't always use the custom home directory feature, so my &lt;B&gt;GetUserHomeDirectoryData()&lt;/B&gt; method has to accommodate for that. (Note: this means that your FTP site has to use a method of User Isolation other than "Custom". You can find more information about User Isolation on the &lt;A href="http://technet.microsoft.com/en-us/library/dd722768(WS.10).aspx" target=_blank mce_href="http://technet.microsoft.com/en-us/library/dd722768(WS.10).aspx"&gt;FTP User Isolation Page&lt;/A&gt;.)&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; IFtpHomeDirectoryProvider.GetUserHomeDirectoryData(
    &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; sessionId,
    &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; siteName,
    &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; userName)
{
    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(_HomeDirectory))
    {
        &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; ArgumentException(&lt;SPAN style="COLOR: #800000"&gt;"Missing homeDirectory value in configuration."&lt;/SPAN&gt;);
    }
    &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; _HomeDirectory;
}&lt;/PRE&gt;
&lt;P&gt;(Note: While it may seem that I could throw the &lt;B&gt;ArgumentException()&lt;/B&gt; in the &lt;B&gt;Initialize()&lt;/B&gt; method, since I don't always need this value for providers that don't implement the home directory lookup it's best to throw the exception in the &lt;B&gt;GetUserHomeDirectoryData()&lt;/B&gt; method.)&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The last thing that I do for the provider is to copy the &lt;B&gt;AuthenticateUser()&lt;/B&gt;, &lt;B&gt;IsUserInRole()&lt;/B&gt;, &lt;B&gt;ReadXmlDataStore()&lt;/B&gt;, &lt;B&gt;GetInnerText()&lt;/B&gt; methods and &lt;B&gt;XmlUserData&lt;/B&gt; class from the &lt;A href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/" target=_blank mce_href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/"&gt;How to Use Managed Code to Create an FTP Authentication Provider using an XML Database&lt;/A&gt; walkthrough. This gives me a custom FTP authentication provider that provides user, role, and home directory lookups. This means the XML file for the provider registration has to vary a little from the walkthroughs in order to define settings for the &lt;B&gt;xmlFileName&lt;/B&gt; and &lt;B&gt;homeDirectory&lt;/B&gt; values. Here's an example of that that might look like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;system.ftpServer&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerDefinitions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="ContosoXmlAuthentication"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FtpXmlAuthentication,FtpXmlAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;activation&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="ContosoXmlAuthentication"&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="xmlFileName"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.contoso.com\Users.xml"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="homeDirectory"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.contoso.com\ftproot"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;activation&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerDefinitions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;

    &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- Other XML goes here --&amp;gt;&lt;/SPAN&gt;

&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;system.ftpServer&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The last thing that you need to do is to create the XML file that contains the usernames and passwords, which you can copy from the &lt;A href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/" target=_blank mce_href="http://learn.iis.net/page.aspx/669/how-to-use-managed-code-to-create-an-ftp-authentication-provider-using-an-xml-database/"&gt;How to Use Managed Code to Create an FTP Authentication Provider using an XML Database&lt;/A&gt; walkthrough.&lt;/P&gt;
&lt;P&gt;I use this provider on multiple FTP sites, so I simply re-register the provider under a different name and specify different values for the &lt;B&gt;xmlFileName&lt;/B&gt; and &lt;B&gt;homeDirectory&lt;/B&gt; values:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE style="COLOR: black; BACKGROUND-COLOR: #ffffff"&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;system.ftpServer&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerDefinitions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="ContosoXmlAuthentication"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FtpXmlAuthentication,FtpXmlAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FabrikamXmlAuthentication"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FtpXmlAuthentication,FtpXmlAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="WingTipToysXmlAuthentication"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FtpXmlAuthentication,FtpXmlAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;activation&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="ContosoXmlAuthentication"&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="xmlFileName"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.Contoso.com\Users.xml"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="homeDirectory"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.Contoso.com\ftproot"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="FabrikamXmlAuthentication"&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="xmlFileName"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.Fabrikam.com\Users.xml"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="homeDirectory"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.Fabrikam.com\ftproot"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="WingTipToysXmlAuthentication"&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="xmlFileName"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.WingTipToys.com\Users.xml"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
                &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;add&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;key&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="homeDirectory"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;="C:\Inetpub\www.WingTipToys.com\ftproot"&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;/&amp;gt;&lt;/SPAN&gt;
            &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
        &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;activation&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;providerDefinitions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;

    &lt;SPAN style="COLOR: #008000"&gt;&amp;lt;!-- Other XML goes here --&amp;gt;&lt;/SPAN&gt;

&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #800000"&gt;system.ftpServer&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;So in the end I have a provider that provides unique users, roles, and home directory for each FTP site. I point the FTP root to a path that is outside of the HTTP root, so my users can upload files for an application like a photo gallery that I provide them, but they can't access the actual ASP.NET files for the application. Since they're using accounts from the XML file, I don't have to hand out physical accounts on my servers or my domain. (The security-paranoid side of my personality really likes that.)&lt;/P&gt;
&lt;P&gt;For some sites I use the XML file for ASP.NET membership by following the instructions in the &lt;A href="http://learn.iis.net/page.aspx/528/how-to-use-the-sample-read-only-xml-membership-and-role-providers-with-iis-70" target=_blank mce_href="http://learn.iis.net/page.aspx/528/how-to-use-the-sample-read-only-xml-membership-and-role-providers-with-iis-70"&gt;How to use the Sample Read-Only XML Membership and Role Providers with IIS 7.0&lt;/A&gt; walkthrough. In those cases, I move the XML file into the App_Data folder of the web site. Once again, since the FTP root is different than the HTTP root, this prevents any of my FTP users from accessing the XML file and making changes to it. (Although you could do that if you wanted to allow one of your users to update the list of FTP users for their site. But as you can imagine, the security-paranoid side of my personality really &lt;U&gt;&lt;B&gt;does not&lt;/B&gt;&lt;/U&gt; like that.)&lt;/P&gt;
&lt;P&gt;All that being said, I hope that this helps you to get an idea for other ways that you can use some of the walkthroughs that I've been writing. I have several additional providers and walkthroughs that I’m working on for the &lt;A href="http://www.iis.net/" target=_blank mce_href="http://www.iis.net/"&gt;IIS.NET&lt;/A&gt; web site, but I’ll keep those as a secret for now. ;-]&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9846647" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>Using LogParser with FTP 7.x Sessions</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/06/11/using-logparser-with-ftp-7-x-sessions.aspx</link><pubDate>Fri, 12 Jun 2009 05:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9728698</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9728698.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9728698</wfw:commentRss><description>&lt;P&gt;One of the great features that we added to our W3C logging enhancements in FTP 7.0 and FTP 7.5 is the ability to track unique sessions, which are represented by GUIDs in a field that is named &lt;I&gt;&lt;B&gt;x-session&lt;/B&gt;&lt;/I&gt;. Because of this addition, you can do some interesting things with LogParser when analyzing your FTP logs.&lt;/P&gt;
&lt;P&gt;The purpose of today's blog is to show a couple of the scripts that I use to analyze some of the session-based information that I'm interested in from time to time.&lt;/P&gt;
&lt;H3&gt;Using LogParser to Count FTP Sessions&lt;/H3&gt;
&lt;P&gt;Since the new FTP service tracks unique sessions, it is now possible to generate reports that show the number of unique FTP sessions you served by day. The following batch file accomplishes this in two parts: first it creates a temporary tab-separated-value file that contains the unique sessions by day, then it calculates the number of sessions by day and writes the totals to a tab-separated-value file that is named &lt;I&gt;Sessions.tsv&lt;/I&gt;, which you can open using an application like Microsoft Excel.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;TT&gt;@echo off&lt;BR&gt;&lt;BR&gt;set LOGPATTERN=u_ex*.log&lt;BR&gt;&lt;BR&gt;logparser.exe "SELECT DISTINCT date,x-session INTO '%~n0.tmp' from %LOGPATTERN%" -i:w3c -o:tsv -headers:ON&lt;BR&gt;&lt;BR&gt;if exist "%~n0.tmp" (&lt;BR&gt;logparser.exe "SELECT date,COUNT(x-session) AS sessions INTO sessions.tsv FROM '%~n0.tmp' GROUP BY date" -i:tsv -o:tsv -headers:ON&lt;BR&gt;del "%~n0.tmp"&lt;BR&gt;)&lt;BR&gt;&lt;BR&gt;set LOGPATTERN=&lt;/TT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Using LogParser to Split FTP Log Files into Unique Session Activity Logs&lt;/H3&gt;
&lt;P&gt;I use the following script when I am testing various FTP scenarios that will split my FTP log files into individual log files that are named after the GUID for each session. (&lt;B&gt;Note&lt;/B&gt;: Please bear in mind, this may generate a lot of log files, so use it sparingly!) You can then analyze the resulting log files to see the list of client activity that was unique to each session.&lt;/P&gt;
&lt;P&gt;This script accomplishes its objective in two parts: first it creates a temporary tab-separated-value file with the list of unique session IDs, then it loops through each session ID and creates a W3C log file for each session's activity.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;TT&gt;@echo off&lt;BR&gt;&lt;BR&gt;set LOGPATTERN=u_ex*.log&lt;BR&gt;&lt;BR&gt;logparser.exe "select distinct x-session into '%~n0.tmp' from '%LOGPATTERN%'" -i:w3c -o:tsv -headers:off &lt;BR&gt;&lt;BR&gt;if exist "%~n0.tmp" (&lt;BR&gt;for /f "delims=|" %%a in (%~n0.tmp) do (&lt;BR&gt;logparser.exe "select date,time,c-ip,cs-username,s-ip,s-port,cs-method,cs-uri-stem,sc-status,sc-win32-status,sc-substatus,x-session,x-fullpath into '%%a.log' from '%LOGPATTERN%' where x-session='%%a' order by date,time" -i:w3c -o:w3c&lt;BR&gt;)&lt;BR&gt;del "%~n0.tmp"&lt;BR&gt;)&lt;BR&gt;&lt;BR&gt;set LOGPATTERN=&lt;/TT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;That about does it for today - I hope this helps!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9728698" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/LogParser/default.aspx">LogParser</category></item><item><title>FTP Clients - Part 6: Core FTP LE</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/05/01/ftp-clients-part-6-core-ftp-le.aspx</link><pubDate>Sat, 02 May 2009 02:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9583119</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9583119.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9583119</wfw:commentRss><description>&lt;P&gt;For this installment in my series about FTP Clients, I'd like to take a look at the Core FTP client. For this blog post I used Core FTP Lite Edition (LE) version 1.3c (build 1447) and version 2.1 (build 1603), although all of my screen shots are from version 2.1. Core FTP is available from the following URL:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.coreftp.com/"&gt;http://www.coreftp.com/&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;At the time of this blog post, Core FTP provides the LE for free and charges a small fee for a professional version.&lt;/P&gt;
&lt;P&gt;Like most graphical FTP clients, the Core FTP LE user interface is pretty easy to use and rather straight-forward - you have separate windows for your local and remote files/folders, as well as a logging window that lists the FTP commands that are sent and the FTP server's responses:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1p2oc7h-AOjpqzlSt1vktdR94GTRDsAW6Rsn5qr_KB3PiZ6Q5vUZs6HF4k-0cu4sxGO_vKbJAgqd1iVO06mAD_9me3Oji5bAZt/CoreFtp1.jpg" target=_blank&gt;&lt;IMG height=450 src="http://yy3flw.blu.livefilestore.com/y1p2oc7h-AOjpqzlSt1vktdR94GTRDsAW6RaK-UHQqTUNxQo4FQRGtRc9cGSSg0QRquMKy_5OXuNrERrfOQ_eaD0Uko5Q6McK-P/CoreFtp1.jpg" width=600 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Core FTP LE has a great Site Manager feature, which allows you to store commonly-used connections to FTP sites:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pq2PaChNVilw0Jz5PYR1rVWF2k1DFxqLRlAKrsQmXqJilox5eGyeuW0ihixQAzXTGNGWYh45ZGnHdAuPp4Tb7AQ/CoreFtp2.jpg" target=_blank&gt;&lt;IMG height=450 src="http://yy3flw.blu.livefilestore.com/y1pq2PaChNVilw0Jz5PYR1rVeBMAtm_0LLHWQArcz_XQwQfcaF9aOynPbZMsr69A7vjN0zWjerkexHAOT9zvpYWXg/CoreFtp2.jpg" width=477 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Clicking on the &lt;B&gt;Advanced&lt;/B&gt; button gives you a great deal of additional configuration settings, and I'll say more about that later:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pPv2A5QUnG1_QvuDOPwhf-sbkEtAlWkLNNBJO6kSys4bvwxOxg1_xRYhhiN8cSPkKWVEH5xp6WFZa8b_cL_jmNg/CoreFtp3.jpg" target=_blank&gt;&lt;IMG height=406 src="http://yy3flw.blu.livefilestore.com/y1pPv2A5QUnG1_QvuDOPwhf-kYLxppBGQ8bpcs4KjenUFEar9LftdcgP31fGhlUbgWsd2LI__0Olk6bS43pt9MNCA/CoreFtp3.jpg" width=548 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H4&gt;Command-Line Support&lt;/H4&gt;
&lt;P&gt;This is one of my favorite Core FTP LE features: &lt;I&gt;command-line support&lt;/I&gt;. Yes - I'm a geek - and I like being able to script things and run batch jobs to automate whatever I can, so command-line support is always a plus for me. That said, the interface for the Core FTP LE command-line client is not an interactive experience like you get with the built-in Windows FTP.EXE or &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2009/01/06/ftp-clients-part-5-moveit-freely-command-line-secure-ftp-client.aspx" target=_blank&gt;MOVEit Freely&lt;/A&gt; command-line clients. The Core FTP LE command-line client is provided as via the Corecmd.exe file that is installed in the main the Core FTP LE application directory, and is used for a single FTP operation like GET or PUT - although you can pass the name of a script file to execute several commands before/after logging in or before/after a file transfer.&lt;/P&gt;
&lt;P&gt;So my final judgment is that the Core FTP LE client doesn't have great command-line support, but it's still really nice to have.&lt;/P&gt;
&lt;H3&gt;Using FTP over SSL (FTPS)&lt;/H3&gt;
&lt;P&gt;The Core FTP LE client supports both &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2008/11/10/ftp-clients-part-2-explicit-ftps-versus-implicit-ftps.aspx" target=_blank&gt;Implicit and Explicit FTPS&lt;/A&gt;, so the choice is up to you which method to use. When creating a connection to a server, Core FTP LE has three FTP options that you can use with FTP7:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;AUTH SSL&lt;/LI&gt;
&lt;LI&gt;AUTH TLS&lt;/LI&gt;
&lt;LI&gt;FTPS (SSL DIRECT)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;It's important to choose this option correctly, otherwise you will run into problems when trying access a site using FTPS. If you'll recall from my "&lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2008/11/10/ftp-clients-part-2-explicit-ftps-versus-implicit-ftps.aspx" target=_blank&gt;FTP Clients - Part 2: Explicit FTPS versus Implicit FTPS&lt;/A&gt;" and my other FTP client blog posts, Explicit FTPS allows the client to initiate SSL/TLS whenever it wants, but for most FTP clients that will be when logging in to your FTP site, and in that regard it may almost seem like Implicit FTPS, but behind the scenes the FTP client and server are communicating differently.&lt;/P&gt;
&lt;P&gt;In the case of FTP7, the following rules apply:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;If you enable FTPS in FTP7 and you assign the FTP site to port 990, you are using &lt;B&gt;Implicit FTPS&lt;/B&gt; - Core FTP LE refers to this as &lt;B&gt;FTPS (SSL DIRECT)&lt;/B&gt;. (&lt;B&gt;Note&lt;/B&gt;: make sure that you configure your FTP client to connect on port 990.)&lt;/LI&gt;
&lt;LI&gt;If you enable FTPS in FTP7 and you assign the FTP site to any port other than port 990, you are using &lt;B&gt;Explicit FTPS&lt;/B&gt; - Core FTP LE allows you to configure your connection to use &lt;B&gt;AUTH SSL&lt;/B&gt; or &lt;B&gt;AUTH TLS&lt;/B&gt; for the explicit connection.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The type of FTPS is specified on the &lt;B&gt;Connection&lt;/B&gt; drop-down menu:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pUvSuPf1uY9MJ8RPaS6U1W2QYsG27D0CbzTqW3QX6jbeYxA65nhAl747sox7p-4ox5tBO8ibEszKuPOjGXi_3bQ/CoreFtp4.jpg" target=_blank&gt;&lt;IMG height=450 src="http://yy3flw.blu.livefilestore.com/y1pUvSuPf1uY9MJ8RPaS6U1W09ILkzYYQ8Rs5TfmRZqgBvKzbh_gyjolTvIEHHOymmitGxOilImoYRzXpbNrBm3ww/CoreFtp4.jpg" width=477 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Once you have chosen an FTPS connection, the Core FTP LE client offers you additional options where you can customize which parts of the session will be encrypted:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pAhNYDZTTgG8K15iSBkTQyp911vG01D5LvxSdbCdu2Zw25Im5-DWAFJ4EYiymHYrFp4BlrhVadAS0_M_uMATvSg/CoreFtp5.jpg" target=_blank&gt;&lt;IMG height=450 src="http://yy3flw.blu.livefilestore.com/y1pAhNYDZTTgG8K15iSBkTQyrGMAiOyvcydU-q_Z2cncnRYROF9VZFFyfR7SzXoiIIjs0Wq-tS4SugYkS6tdnEjvA/CoreFtp5.jpg" width=477 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;You can combine the Core FTP SSL options with the advanced SSL policies for your FTP7 sites to customize your security level:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1p4fBz3NYQ9ZfH5EgsjrFj8Y4hifzio778a9VYJfgFsTki-Bu53pLj-szre0yeec7RAuN6ASxmNIw3_vigaakrdg/CoreFtp6.jpg" target=_blank&gt;&lt;IMG height=360 src="http://yy3flw.blu.livefilestore.com/y1p4fBz3NYQ9ZfH5EgsjrFj8eaVXCOL3_wXo4o7ik3JjafNTfBUTkUmaMD6uzGrAHkPFUihfeTCYguCvyFLieanUQ/CoreFtp6.jpg" width=600 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H3&gt;Using FTP Virtual Hosts&lt;/H3&gt;
&lt;P&gt;Because Core FTP LE's site manager allows you to specify the virtual host name as part of the user credentials, Core FTP LE works great with FTP7's virtual host names. All that you need to do is use the "ftp.example.com|username" syntax when specifying your username, and when you connect to the FTP7 server it will route your requests to the correct FTP virtual host site.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pSmbFAU_qjHH-5_6usShQZuUoAlHEml39LuGDeFcfpzHQVkwCgmVCmeOAaU9C569wYf1sCLwd8lc1ifS4oBBxDA/CoreFtp7.jpg" target=_blank&gt;&lt;IMG height=450 src="http://yy3flw.blu.livefilestore.com/y1p-tl22lkzVwbPUwLLUHrBrUbw8ZYv8u9LIdlZ05nA34NIN43H-5EqnhYhKoCwCX_TNRzUAs6w4PAlzyQR2X-P0w/CoreFtp7.jpg" width=477 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H3&gt;Using True FTP Hosts&lt;/H3&gt;
&lt;P&gt;A really great feature of Core FTP LE is the ability to send pre-login commands, and since this feature allows you to enter custom commands you can specify the actual FTP HOST command as part of your login:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://yy3flw.blu.livefilestore.com/y1pgEnNmRPYRbGCD1pc5bs8G3gArhk8uhHHW23L0dFGseCxnPSLOHu39PBKSvgxXmT4sheZGIcPq4wU9tcJ_atFuA/CoreFtp8.jpg" target=_blank&gt;&lt;IMG height=406 src="http://yy3flw.blu.livefilestore.com/y1pgEnNmRPYRbGCD1pc5bs8G9TB5x7v5ORRPmg1A-kcRnDQycwKhcflCWyaF6uuo7Ger0mFRzLWNldPHQBTw36G6w/CoreFtp8.jpg" width=548 border=2&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;This is a tremendous feature if you're hosting multiple FTP sites on the same IP address, and gives Core FTP LE some of the best support for true FTP HOSTs.&lt;/P&gt;
&lt;H3&gt;Scorecard for Core FTP LE&lt;/H3&gt;
&lt;P&gt;That wraps it up for our quick round-trip for some of Core FTP LE's features, and here's the scorecard results:&lt;/P&gt;
&lt;TABLE class="" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="" noWrap&gt;Client Name&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;Directory&lt;BR&gt;Browsing&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Explicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Implicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;Virtual&lt;BR&gt;Hosts&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;True&lt;BR&gt;HOSTs&lt;/A&gt;&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;Core FTP LE 1.3&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Rich&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y &lt;SUP&gt;1&lt;/SUP&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;Core FTP LE 2.1&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Rich&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y &lt;SUP&gt;1&lt;/SUP&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=left colSpan=6&gt;&lt;SUP&gt;1&lt;/SUP&gt; As noted earlier, true FTP HOSTs are available in Site Manager using pre-login commands.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: Keeping with my standard disclaimer, there are a great number of additional features that Core FTP LE provides - and I just focused on the topic areas that apply to FTP7.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9583119" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>BLOG - FTP 7.5 Service Extensibility References</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/04/23/blog-ftp-7-5-service-extensibility-references.aspx</link><pubDate>Fri, 24 Apr 2009 03:23:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9565757</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9565757.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9565757</wfw:commentRss><description>&lt;P&gt;As I pointed out in my recent blog post that was titled "&lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2009/03/18/ftp-7-5-and-webdav-7-5-have-been-released.aspx" target=_blank mce_href="http://blogs.msdn.com/robert_mcmurray/archive/2009/03/18/ftp-7-5-and-webdav-7-5-have-been-released.aspx"&gt;FTP 7.5 and WebDAV 7.5 have been released&lt;/A&gt;", one of the great new features of the FTP 7.5 service is extensibility. In that blog post I mentioned that I wrote the following walkthroughs to help developers get started writing providers for the FTP 7.5 service, and these walkthroughs are all available on Microsoft's &lt;A href="http://learn.iis.net/" target=_blank mce_href="http://learn.iis.net/"&gt;learn.iis.net&lt;/A&gt; Web site:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;For Managed Code Developers: 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/598/how-to-use-managed-code-to-create-a-simple-ftp-authentication-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/598/how-to-use-managed-code-to-create-a-simple-ftp-authentication-provider/"&gt;How to Use Managed Code to Create a Simple FTP Authentication Provider&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/600/how-to-use-managed-code-to-create-a-simple-ftp-home-directory-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/600/how-to-use-managed-code-to-create-a-simple-ftp-home-directory-provider/"&gt;How to Use Managed Code to Create a Simple FTP Home Directory Provider&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/602/how-to-use-managed-code-to-create-a-simple-ftp-logging-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/602/how-to-use-managed-code-to-create-a-simple-ftp-logging-provider/"&gt;How to Use Managed Code to Create a Simple FTP Logging Provider&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For Native Code Developers: 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/599/how-to-use-native-code-to-create-a-simple-ftp-authentication-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/599/how-to-use-native-code-to-create-a-simple-ftp-authentication-provider/"&gt;How to Use Native Code to Create a Simple FTP Authentication Provider&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/601/how-to-use-native-code-to-create-a-simple-ftp-home-directory-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/601/how-to-use-native-code-to-create-a-simple-ftp-home-directory-provider/"&gt;How to Use Native Code to Create a Simple FTP Home Directory Provider&lt;/A&gt; &lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/603/how-to-use-native-code-to-create-a-simple-ftp-logging-provider/" target=_blank mce_href="http://learn.iis.net/page.aspx/603/how-to-use-native-code-to-create-a-simple-ftp-logging-provider/"&gt;How to Use Native Code to Create a Simple FTP Logging Provider&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;We have also recently published the &lt;A href="http://msdn.microsoft.com/en-us/library/dd723667.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd723667.aspx"&gt;FTP Service Extensibility Reference&lt;/A&gt; on Microsoft's MSDN Web site, and here is a list of all the reference topics that we have written for FTP 7.5 service extensibility:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692905.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692905.aspx"&gt;FTP Managed-Code Extensibility API Reference&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692904.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692904.aspx"&gt;FTP Managed-Code Extensibility Interfaces&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692892.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692892.aspx"&gt;IFtpAuthenticationProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692879.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692879.aspx"&gt;IFtpAuthenticationProvider.AuthenticateUser Method&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692902.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692902.aspx"&gt;IFtpAuthenticationProvider.Initialize Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692893.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692893.aspx"&gt;IFtpHomeDirectoryProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692881.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692881.aspx"&gt;IFtpHomeDirectoryProvider.GetUserHomeDirectoryData Method&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692886.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692886.aspx"&gt;IFtpHomeDirectoryProvider.Initialize Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692885.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692885.aspx"&gt;IFtpLogProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692894.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692894.aspx"&gt;IFtpLogProvider.Log Method&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692887.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692887.aspx"&gt;IFtpLogProvider.Initialize Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692895.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692895.aspx"&gt;IFtpRoleProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692899.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692899.aspx"&gt;IFtpRoleProvider.IsUserInRole Method&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692875.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692875.aspx"&gt;IFtpRoleProvider.Initialize Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692896.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692896.aspx"&gt;FTP Managed-Code Extensibility Structures&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692903.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692903.aspx"&gt;FtpLogEntry Class&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692882.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692882.aspx"&gt;FTP Native-Code Extensibility API Reference&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692898.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692898.aspx"&gt;FTP Native-Code Extensibility Interfaces&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692889.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692889.aspx"&gt;IFtpAuthenticationProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692897.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692897.aspx"&gt;IFtpAuthenticationProvider::AuthenticateUser Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692900.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692900.aspx"&gt;IFtpHomeDirectoryProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692880.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692880.aspx"&gt;IFtpHomeDirectoryProvider::GetUserHomeDirectoryData Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692877.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692877.aspx"&gt;IFtpLogProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692876.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692876.aspx"&gt;IFtpLogProvider::Log Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692908.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692908.aspx"&gt;IFtpProviderConstruct Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692891.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692891.aspx"&gt;IFtpProviderConstruct::Construct Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692883.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692883.aspx"&gt;IFtpRoleProvider Interface&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692907.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692907.aspx"&gt;IFtpRoleProvider::IsUserInRole Method&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692901.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692901.aspx"&gt;FTP Native-Code Extensibility Structures&lt;/A&gt; 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/dd692906.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/dd692906.aspx"&gt;LOGGING_PARAMETERS Structure&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I hope this helps!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9565757" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/IIS+Topics/default.aspx">IIS Topics</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>FTP 7.5 and WebDAV 7.5 have been released!</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/03/18/ftp-7-5-and-webdav-7-5-have-been-released.aspx</link><pubDate>Wed, 18 Mar 2009 10:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9486224</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9486224.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9486224</wfw:commentRss><description>&lt;P&gt;Over the next few days you're going to hear a lot of details about many of the great new IIS extensions that the IIS feature team is releasing for the &lt;A class="" href="http://www.microsoft.com/events/mix/default.mspx" target=_blank mce_href="http://www.microsoft.com/events/mix/default.mspx"&gt;2009 MIX Conference&lt;/A&gt; in Las Vegas later today. I don't want to spoil any surprises by talking about anyone else’s feature areas, but I’m about to board a plane to head out on vacation (to Peru!) and I'm not taking a computer with me (believe it or not!) so I thought that I’d take a moment to highlight just a few of the features that are in the FTP 7.5 and WebDAV 7.5 releases.&lt;/P&gt;
&lt;P&gt;&lt;BIG&gt;&lt;U&gt;&lt;B&gt;FTP 7.5&lt;/B&gt;&lt;/U&gt;&lt;/BIG&gt;&lt;/P&gt;
&lt;P&gt;One of the great new features in FTP 7.5 is &lt;I&gt;extensibility&lt;/I&gt;. We had some extensibility features that were partially implemented in FTP 7.0, and we used those for the ASP.NET and IIS Manager authentication providers, but FTP extensibility was not officially supported in the 7.0 release. With FTP 7.5 extensibility is fully supported, so you can now write providers that implement custom functionality for authentication/authorization, home directory lookups, and logging.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/photos/robert_mcmurray/images/9486115/original.aspx" target=_blank&gt;&lt;IMG height=480 src="http://blogs.msdn.com/photos/robert_mcmurray/images/9486115/493x480.aspx" width=493&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;To help developers get started writing providers for FTP 7.5, I wrote the following walkthroughs that are available on Microsoft's &lt;A href="http://learn.iis.net/" target=_blank&gt;learn.iis.net&lt;/A&gt; web site:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;For Managed Code Developers: 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/598/how-to-use-managed-code-to-create-a-simple-ftp-authentication-provider/" target=_blank&gt;How to Use Managed Code to Create a Simple FTP Authentication Provider&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/600/how-to-use-managed-code-to-create-a-simple-ftp-home-directory-provider/" target=_blank&gt;How to Use Managed Code to Create a Simple FTP Home Directory Provider&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/602/how-to-use-managed-code-to-create-a-simple-ftp-logging-provider/" target=_blank&gt;How to Use Managed Code to Create a Simple FTP Logging Provider&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;For Native Code Developers: 
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/599/how-to-use-native-code-to-create-a-simple-ftp-authentication-provider/" target=_blank&gt;How to Use Native Code to Create a Simple FTP Authentication Provider&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/601/how-to-use-native-code-to-create-a-simple-ftp-home-directory-provider/" target=_blank&gt;How to Use Native Code to Create a Simple FTP Home Directory Provider&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://learn.iis.net/page.aspx/603/how-to-use-native-code-to-create-a-simple-ftp-logging-provider/" target=_blank&gt;How to Use Native Code to Create a Simple FTP Logging Provider&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Another highlight in FTP 7.5 is the addition of a user interface for the FTP Request Filtering features. We shipped request filtering with FTP 7.0 while the request filtering user interface was still in development, and the 7.5 version seemed like a great time to release it.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/photos/robert_mcmurray/images/9486127/original.aspx" target=_blank&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9486127/500x260.aspx"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For those of you that are unfamiliar with FTP request filtering, it allows you to add rules that allow or deny specific file extensions, hidden segments, URL sequences, and even FTP commands.&lt;/P&gt;
&lt;P&gt;For more information about the features in the new FTP service, see the following page on the &lt;A href="http://www.iis.net/" target=_blank&gt;http://www.iis.net/&lt;/A&gt; web site:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.iis.net/extensions/FTP" target=_blank&gt;http://www.iis.net/extensions/FTP&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BIG&gt;&lt;U&gt;&lt;B&gt;WebDAV 7.5&lt;/B&gt;&lt;/U&gt;&lt;/BIG&gt;&lt;/P&gt;
&lt;P&gt;One of the big changes in WebDAV 7.5 is the inclusion of WebDAV locks, which are implemented through a simple locking mechanism. Our lock implementation was still in development when we shipped the WebDAV 7.0 release, and this release should help publishing scenarios where WebDAV locks are required.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/photos/robert_mcmurray/images/9486130/original.aspx" target=_blank&gt;&lt;IMG height=260 src="http://blogs.msdn.com/photos/robert_mcmurray/images/9486130/500x260.aspx" width=500&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;To help you get started using locks with WebDAV 7.5, I wrote the following walkthrough that is available on Microsoft's &lt;A href="http://learn.iis.net/"&gt;learn.iis.net&lt;/A&gt; web site:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://learn.iis.net/page.aspx/596/how-to-use-webdav-locks/" target=_blank&gt;How to Use WebDAV Locks&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For more information about the features in the new WebDAV module, see the following page on the &lt;A href="http://www.iis.net/" target=_blank&gt;http://www.iis.net/&lt;/A&gt; web site:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.iis.net/extensions/WebDAV" target=_blank&gt;http://www.iis.net/extensions/WebDAV&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;BIG&gt;&lt;U&gt;&lt;B&gt;In Closing...&lt;/B&gt;&lt;/U&gt;&lt;/BIG&gt;&lt;/P&gt;
&lt;P&gt;So that about wraps it up for some of the major highlights for FTP and WebDAV; for news about everything else that's coming out for IIS, watch the news items on the &lt;A href="http://www.iis.net/" target=_blank&gt;http://www.iis.net/&lt;/A&gt; home page!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9486224" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/WebDAV/default.aspx">WebDAV</category></item><item><title>FTP Clients - Part 5: MOVEit Freely Command-Line Secure FTP Client</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2009/01/06/ftp-clients-part-5-moveit-freely-command-line-secure-ftp-client.aspx</link><pubDate>Wed, 07 Jan 2009 09:10:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9286876</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9286876.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9286876</wfw:commentRss><description>&lt;P&gt;For this installment in my series about FTP Clients, I'd like to take a look at the MOVEit Freely Command-Line Secure FTP Client ("FTPS.EXE") from Ipswitch. For this blog post I used MOVEit Freely FTP Client version 5.0.0.0, and it is available from the following URL:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A href="http://www.ipswitchft.com/products/moveit/client/freely/" target=_blank&gt;http://www.ipswitchft.com/products/moveit/client/freely/&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;At the time of this blog post, Ipswitch is providing the MOVEit Freely FTP client for free, although you are required to fill out a registration page with a short questionnaire. For more information on the license for the MOVEit Freely command-line FTP client, please see &lt;A href="http://www.ipswitchft.com/" target=_blank&gt;Ipswitch's web site&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;If you're like me and you like to script a lot of batch jobs on your servers, the MOVEit Freely command-line FTP client can be quite handy. The command set for the MOVEit Freely FTP client is a greatly-enhanced superset of the commands that are available with the command-line FTP.EXE client that is built-in to Windows, with added features that make additional functionality possible, such as SSL, passive FTP, resumable downloads, etc. There is a manual available with the MOVEit Freely FTP client, and I highly recommend using the manual as a reference when writing automation scripts because there are a lot of options that are available to you.&lt;/P&gt;
&lt;H3&gt;Active and Passive FTP&lt;/H3&gt;
&lt;P&gt;One of the great things about the MOVEit Freely command-line FTP client is the ability to use either Passive or Active connections, and you can switch between the two connection types using the "passive" command in the FTP session. This helps immensely when working with firewalls and such. The following example shows what that might look like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE class="" style="COLOR: #ffffff; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #000000" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;&lt;PRE&gt;CMD&amp;gt;ftps.exe ftp.example.com

220 Microsoft FTP Service
Connected to ftp.example.com.
User: administrator
331 Password required for administrator.
Password: ********
230 User logged in.
ftp&amp;gt; passive
Passive mode  On .
ftp&amp;gt; put foobar.txt
227 Entering Passive Mode (192,168,0,1,224,39).
150 Opening ASCII mode data connection.
226 Transfer complete.
ftp: 8 bytes sent in 0.06Seconds 0.13Kbytes/sec.
ftp&amp;gt; passive
Passive mode  Off .
ftp&amp;gt; put foobar.txt
200 PORT command successful.
125 Data connection already open; Transfer starting.
226 Transfer complete.
ftp: 8 bytes sent in 0.01Seconds 0.78Kbytes/sec.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Using FTP over SSL (FTPS)&lt;/H3&gt;
&lt;P&gt;The MOVEit Freely command-line FTP client supports both &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2008/11/10/ftp-clients-part-2-explicit-ftps-versus-implicit-ftps.aspx" target=_blank&gt;Implicit and Explicit FTPS&lt;/A&gt;, so the choice is up to you which one to use, but I generally use Explicit FTPS since Implicit FTPS should be considered obsolete. The SSL mode is specified using the "-e:" parameter on the command-line, and the 5.0.0.0 version of the MOVEit Freely command-line FTP supports the following values for that parameter:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE class="" style="BORDER-RIGHT: #000000 1px solid; BORDER-TOP: #000000 1px solid; BORDER-LEFT: #000000 1px solid; BORDER-BOTTOM: #000000 1px solid; BORDER-COLLAPSE: collapse" cellSpacing=1 cellPadding=3 width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="" vAlign=top noWrap align=left&gt;Parameter&lt;/TH&gt;
&lt;TH class="" vAlign=top noWrap align=left&gt;FTPS Mode&lt;/TH&gt;
&lt;TH class="" vAlign=top noWrap align=left&gt;Description&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;off&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;n/a&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that no encryption will be used on either the control channel or data channel. 
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: This is the default behavior.&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;on&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Explicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that both the control channel and data channel will use encryption over an explicit FTPS connection. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This uses the AUTH TLS, PBSZ 0, and PROT P commands when establishing a connection.&lt;/LI&gt;
&lt;LI&gt;You can use "prot on" and "prot off" to specify whether encryption will be used. (See Note 1 below.)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;on-ccc&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Explicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies the control channel will use encryption over an explicit FTPS connection during login, but the control channel will switch to unencrypted after a login has been established. Data channel connections will still be encrypted. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This uses the AUTH TLS, PBSZ 0, and PROT P commands to enable encryption when establishing a connection, then uses the CCC command after the username and password are successfully negotiated. (See Note 2 below.)&lt;/LI&gt;
&lt;LI&gt;The USER and PASS commands are the only commands that will be encrypted; all other FTP commands are unencrypted.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;tls-p&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Explicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that both control and data channel will use encryption over an explicit FTPS connection. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This uses the AUTH TLS and PROT P commands when establishing a connection.&lt;/LI&gt;
&lt;LI&gt;You can use "prot on" and "prot off" to specify whether encryption will be used. (See Note 3 below.)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;tls-c&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Explicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that only the control connection will use encryption over an explicit FTPS connection. Data channel connections will be unencrypted. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;: 
&lt;UL&gt;
&lt;LI&gt;This uses only the AUTH TLS to enable encryption when establishing a connection.&lt;/LI&gt;
&lt;LI&gt;You must manually send a PBSZ command before you can use the "prot on" and "prot off" to specify whether encryption will be used. (See Note 1 and Note 3 below.)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;tls-c-ccc&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Explicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that only the control connection will use encryption over an explicit FTPS connection during login, but the control channel will switch to unencrypted after a login has been established. Data connections will be unencrypted. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This uses only the AUTH TLS to enable encryption when establishing a connection, then uses the CCC command after the username and password are successfully negotiated.&lt;/LI&gt;
&lt;LI&gt;The USER and PASS commands are the only commands that will be encrypted; all other FTP commands are unencrypted.&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;implicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Implicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that both the control channel and data channel will use encryption over an implicit FTPS connection, which can only be on port 990 for the FTP7 service. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;: 
&lt;UL&gt;
&lt;LI&gt;The implicit FTPS connection will encrypt both the control channel and data channel without the use of an AUTH command.&lt;/LI&gt;
&lt;LI&gt;You can use "prot on" and "prot off" to specify whether encryption will be used. (See Note 3 below.)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;B&gt;implicit-ccc&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top noWrap&gt;&lt;B&gt;Implicit&lt;/B&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top&gt;Specifies that the control channel would use encryption over an implicit FTPS connection during login and switch the control channel to unencrypted after login, but this is &lt;B&gt;&lt;U&gt;not supported in FTP7&lt;/U&gt;&lt;/B&gt;. The implicit FTPS connection will succeed, but the FTP7 service will return an error when the CCC command is sent. You can ignore the error and continue to use the session. 
&lt;P&gt;&lt;B&gt;Notes&lt;/B&gt;: 
&lt;UL&gt;
&lt;LI&gt;Implicit FTPS connections require encryption for the command channel. (See Note 4 below.)&lt;/LI&gt;
&lt;LI&gt;You can use "prot on" and "prot off" to specify whether encryption will be used. (See Note 3 below.)&lt;/LI&gt;&lt;/UL&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The following notes should be considered:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Encryption of the data connection can be changed during the session with MOVEit Freely's "prot" command. You can use the "prot on" to specify that data connections will be encrypted, and "prot off" to specify that data connections will be unencrypted; these commands will respectively send the PROT P and PROT C commands over FTP.&lt;/LI&gt;
&lt;LI&gt;The "on-ccc", "tls-c-ccc", and "implicit-ccc" parameters are useful with firewalls that inspect FTP traffic. Switching the control channel back to unencrypted allows the firewall to inspect and possibly modify the FTP commands. For example, firewalls that are performing Network Address Translation (NAT) may need to modify the PORT and PASV commands.&lt;/LI&gt;
&lt;LI&gt;"RFC 2228 - FTP Security Extensions" states that FTP clients are required to send an FTP PBSZ command before sending an FTP PROT command, and unfortunately the MOVEit Freely 5.0.0.0 FTP client does not send this command, so you get a "503 Bad sequence of commands" error. You can work around this by issuing a literal command to the server using the FTP client's "quote" command, which appears to work. See the following example for more information. The following example shows what that might look like: 
&lt;BLOCKQUOTE&gt;&lt;I&gt;Note: I turned on debugging for this example with the "-d" option so you can see the sequence of commands.&lt;/I&gt; 
&lt;TABLE class="" style="COLOR: #ffffff; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #000000" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;&lt;PRE&gt;CMD&amp;gt;ftps.exe -e:tls-c -d ftp.example.com

220 Microsoft FTP Service
---&amp;gt; AUTH TLS
234 AUTH command ok. Expecting TLS Negotiation.
Connected to ftp.example.com.
User: administrator
---&amp;gt; USER administrator
331 Password required for administrator.
Password: ********
---&amp;gt; PASS (hidden)
230 User logged in.
---&amp;gt; SYST
215 Windows_NT
ftp&amp;gt; prot on
---&amp;gt; PROT P
503 Bad sequence of commands.
Data connections will still NOT be encrypted
ftp&amp;gt; quot PBSZ 0
---&amp;gt; PBSZ 0
200 PBSZ command successful.
ftp&amp;gt; prot on
---&amp;gt; PROT P
200 PROT command successful.
Data connections will be encrypted
ftp&amp;gt; bye
---&amp;gt; QUIT
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;&lt;/LI&gt;
&lt;LI&gt;The FTP7 service treats implicit FTPS connections as though the SSL policy for the control is set to "Require".&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;One last note about FTPS, if you are using a certificate with trust issues, you will see the following prompt displayed:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9286660/original.aspx"&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;You can get around this certificate prompt when writing scripts by using the "-z" switch. The following example shows what that might look like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;I&gt;Note: For this example I bypassed a certificate prompt with the "-z" switch, and I specified passive FTP with the "passive" command.&lt;/I&gt; 
&lt;TABLE class="" style="COLOR: #ffffff; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #000000" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;&lt;PRE&gt;CMD&amp;gt;ftps.exe -z -e:on ftp.example.com

220 Microsoft FTP Service
234 AUTH command ok. Expecting TLS Negotiation.
Connected to ftp.example.com.
User: administrator
331 Password required for administrator.
Password: ********
230 User logged in.
200 PBSZ command successful.
200 PROT command successful.
215 Windows_NT
ftp&amp;gt; passive
Passive mode On .
ftp&amp;gt; ls -l
227 Entering Passive Mode (192,168,0,1,224,97).
150 Opening ASCII mode data connection.
03-10-08 10:41AM &amp;lt;DIR&amp;gt; App_Data
09-04-08 11:41AM &amp;lt;DIR&amp;gt; aspnet_client
09-04-08 11:41AM &amp;lt;DIR&amp;gt; bin
12-17-02 11:47AM 2360 default.aspx
ftp: 128 bytes received in 0.03Seconds 83.25Kbytes/sec.
226 Transfer complete.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Using FTP Virtual Hosts&lt;/H3&gt;
&lt;P&gt;Since everything is happening from a command-line, you can use both FTP7's Virtual Hosts and the actual FTP HOST command. Once again, see my &lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2007/08/28/virtual-hosts-and-host-names-in-ftp7.aspx" target=_blank&gt;Virtual Hosts and Host Names in FTP7&lt;/A&gt; blog post for more information about FTP Virtual Host Names and FTP True Host Names, and see &lt;A href="https://datatracker.ietf.org/drafts/draft-hethmon-mcmurray-ftp-hosts/"&gt;https://datatracker.ietf.org/drafts/draft-hethmon-mcmurray-ftp-hosts/&lt;/A&gt; for more information about status of the FTP HOST command.&lt;/P&gt;
&lt;P&gt;In any event, FTP7 virtual hosts are supported by using the "&lt;I&gt;ftp.example.com|username&lt;/I&gt;" syntax when specifying your username, and when you connect to the FTP7 server it will route your requests to the correct FTP virtual host site. The following example shows what that might look like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE class="" style="COLOR: #ffffff; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #000000" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;&lt;PRE&gt;CMD&amp;gt;ftps.exe ftp.example.com

220 Microsoft FTP Service
Connected to ftp.example.com.
User: ftp.contoso.com|administrator
331 Password required for ftp.contoso.com|administrator.
Password: ********
230-Directory has 104,857,600 bytes of disk space available.
230 User logged in.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;True FTP hosts can be used by specifying the FTP HOST command before the client sends the USER and PASS credentials. This is accomplished in two parts:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You need to suppress the automatic username prompt MOVEit client by using the "-n" switch on the command-line.&lt;/LI&gt;
&lt;LI&gt;You need to specify the host name using the MOVEit client's "quote" command, which allows you to send custom FTP commands. The syntax for this would be "quote HOST ftp.example.com".&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The following example shows what that might look like:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;TABLE class="" style="COLOR: #ffffff; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #000000" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;&lt;PRE&gt;CMD&amp;gt;ftps.exe -n ftp.example.com

220 Microsoft FTP Service
Connected to ftp.example.com.
ftp&amp;gt; quote HOST ftp.contoso.com
220 Host accepted.
ftp&amp;gt; USER administrator
331 Password required for administrator.
Password: ********
230-Directory has 104,857,600 bytes of disk space available.
230 User logged in.
ftp&amp;gt; bye
221 Goodbye.

CMD&amp;gt;&lt;/PRE&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/BLOCKQUOTE&gt;
&lt;H3&gt;Scorecard for the MOVEit Freely command-line FTP client&lt;/H3&gt;
&lt;P&gt;This concludes our quick look at some of the features that are available with the MOVEit Freely command-line FTP client, and here's the scorecard results:&lt;/P&gt;
&lt;TABLE class="" width=500 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="" noWrap&gt;Client Name&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;Directory&lt;BR&gt;Browsing&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Explicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Implicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;Virtual&lt;BR&gt;Hosts&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;True&lt;BR&gt;HOSTs&lt;/A&gt;&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;A href="http://www.ipswitchft.com/" target=_blank&gt;MOVEit Freely 5.0.0.0&lt;/A&gt;&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;n/a&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y &lt;SUP&gt;1&lt;/SUP&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=left colSpan=6&gt;&lt;SUP&gt;1&lt;/SUP&gt; As noted earlier, true FTP HOSTs are available when using the "quote HOST ftp.example.com" syntax.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: Keeping with my standard disclaimer, there are a great number of additional features that the MOVEit Freely command-line FTP client provides - I'm just keeping the focus on those topic areas that apply to FTP7.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9286876" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item><item><title>FTP Clients - Part 4: FileZilla</title><link>http://blogs.msdn.com/robert_mcmurray/archive/2008/12/17/ftp-clients-part-4-filezilla.aspx</link><pubDate>Thu, 18 Dec 2008 02:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9232415</guid><dc:creator>robert_mcmurray</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/robert_mcmurray/comments/9232415.aspx</comments><wfw:commentRss>http://blogs.msdn.com/robert_mcmurray/commentrss.aspx?PostID=9232415</wfw:commentRss><description>&lt;P&gt;For this next installment in my FTP Clients series, I'd like to take a look at the FileZilla FTP client. For this blog post I was using FileZilla version 3.1.6.&lt;/P&gt;
&lt;P&gt;There are a lot of places where you can find FileZilla, but the best location is the official FileZilla web site at &lt;A href="http://filezilla-project.org/"&gt;http://filezilla-project.org/&lt;/A&gt;. The FileZilla FTP client is free, so you can't beat the price. ;-]&lt;/P&gt;
&lt;P&gt;The user interface is pretty straight-forward: you have separate windows for your local and remote files/folders, as well as a logging window that lists the FTP commands that are sent and the FTP server's responses.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/photos/robert_mcmurray/images/9232065/original.aspx" target=_blank&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9232065/598x480.aspx"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;FileZilla has a great Site Manager feature, which allows you to store commonly-used connections to FTP sites.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9232091/original.aspx"&gt;&lt;/P&gt;
&lt;H3&gt;Using FTP over SSL (FTPS)&lt;/H3&gt;
&lt;P&gt;When creating a connection to an FTPS server, FileZilla has two options: FTPS and FTPES. It's important to have this option configured correctly, otherwise you will run into problems when trying access a site using FTPS. If you'll recall from my "&lt;A href="http://blogs.msdn.com/robert_mcmurray/archive/2008/11/10/ftp-clients-part-2-explicit-ftps-versus-implicit-ftps.aspx" target=_blank&gt;FTP Clients - Part 2: Explicit FTPS versus Implicit FTPS&lt;/A&gt;" blog post, Explicit FTPS allows the client to initiate SSL/TLS whenever it wants, but for most FTP clients that will be when logging in to your FTP site, and in that regard it may almost seem like Implicit FTPS, but behind the scenes the FTP client and server are communicating differently.&lt;/P&gt;
&lt;P&gt;In the case of FTP7, the following rules apply:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;If you enable FTPS and you assign the FTP site to port 990, you are using &lt;B&gt;Implicit SSL&lt;/B&gt; - FileZilla refers to this as &lt;B&gt;FTPS&lt;/B&gt;.&lt;/LI&gt;
&lt;LI&gt;If you enable FTPS and you assign the FTP site to any port other than port 990, you are using &lt;B&gt;Explicit SSL&lt;/B&gt; - FileZilla refers to this as &lt;B&gt;FTPES&lt;/B&gt;.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9232117/original.aspx"&gt;&lt;/P&gt;
&lt;H3&gt;Using FTP Virtual Hosts&lt;/H3&gt;
&lt;P&gt;Because FileZilla's site manager allows you to specify the virtual host name as part of the user credentials, FileZilla works great with FTP7's virtual host names. All that you need to do is use the "&lt;I&gt;ftp.example.com|username&lt;/I&gt;" syntax when specifying your username, and when you connect to the FTP7 server it will route your requests to the correct FTP virtual host site.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9232175/original.aspx"&gt;&lt;/P&gt;
&lt;P&gt;Unfortunately, even though FileZilla allows you to send custom commands, you cannot send custom commands outside of an established FTP session, so you can't send the FTP HOST command as part of your login, therefore true FTP hosts are not supported.&lt;/P&gt;
&lt;H3&gt;Directory Browsing&lt;/H3&gt;
&lt;P&gt;Using MS-DOS or UNIX directory listings in FTP7 didn't have any impact on whether FileZilla could render directory listings, nor did configuring any of the other options such as four-digit years, etc. When I create FTP connections in FileZilla's site manager it defaults to auto-detecting the FTP server type, which makes the directory browsing behavior transparent to the client. (Behind the scenes FileZilla is sending an FTP SYST command, which allows FileZilla to detect the operating system.)&lt;/P&gt;
&lt;P&gt;You can customize the server type in the advanced settings for your FTP connection, so you can match up your FTP7 directory listing options and the server type that FileZilla expects, but personally I have had no problems with auto-detection so I prefer to use that option.&lt;/P&gt;
&lt;P&gt;On a side note, if you intentionally misconfigure FileZilla's server type settings, you can cause FileZilla to behave strangely. For example, choosing a VMS server type and configuring FTP7 to use MS-DOS directory listings will not work, but then again - I wouldn't expect that to work. ;-]&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/robert_mcmurray/images/9232275/original.aspx"&gt;&lt;/P&gt;
&lt;H3&gt;Scorecard for FileZilla&lt;/H3&gt;
&lt;P&gt;So - that concludes our quick round-trip for some of FileZilla's features, and here's the scorecard results:&lt;/P&gt;
&lt;TABLE class="" border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="" noWrap&gt;Client Name&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;Directory&lt;BR&gt;Browsing&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Explicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89117" mce_href="http://go.microsoft.com/fwlink/?LinkId=89117"&gt;Implicit&lt;BR&gt;FTPS&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;Virtual&lt;BR&gt;Hosts&lt;/A&gt;&lt;/TH&gt;
&lt;TH class="" noWrap width=75&gt;&lt;A href="http://go.microsoft.com/fwlink/?LinkId=89119" mce_href="http://go.microsoft.com/fwlink/?LinkId=89119"&gt;True&lt;BR&gt;HOSTs&lt;/A&gt;&lt;/TH&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top noWrap align=left&gt;&lt;A href="http://filezilla-project.org/" target=_blank&gt;FileZilla 3.1.6&lt;/A&gt;&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Rich&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;Y&lt;/TD&gt;
&lt;TD class="" noWrap align=middle width=75&gt;N&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;&lt;B&gt;Note&lt;/B&gt;: As with all of the FTP clients in this blog series, there are a great number of additional features that FileZilla provides - I'm just keeping the focus on a few specific topic areas that apply to FTP7.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9232415" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/robert_mcmurray/archive/tags/FTP/default.aspx">FTP</category></item></channel></rss>