PowerShell 1.0: Adding Virtual FTP Directories to IIS 6 or 7

While my firm explores using WebDAV and SharePoint 2007 for exchanging large amounts of files, we're temporarily using FTP dropboxes to fill the void. Last Monday, I setup 11 new accounts and it took a total of one hour to complete the same 15 step process (give or take) for each account. By the time I was finished, I decided automating FTP account creation would be my first PowerShell project. What you see below is part of that project.

The code below creates a virtual directory in the "Default FTP Site" of the machine that is running the PowerShell script. The virtual directory called "NewUser" is mapped to C:\FTP\NewUser and is set to be both readable and writable. For the record, I couldn't get WMI to work (get-wmiobject) and that's the reason I decided to use the .NET's Directory Services support.

1$server = $env:computername
2$service = New-Object System.DirectoryServices.DirectoryEntry("IIS://$server/MSFTPSVC")
3$site = $service.psbase.children |Where-Object { $_.ServerComment -eq 'Default FTP Site' }
4$site = New-Object System.DirectoryServices.DirectoryEntry($site.psbase.path+"/Root") # <-- IIS 6 requires this. Not sure why. Otherwise, it never appears to commit changes. This line is not required for IIS 7. $virtualdir = $site.psbase.children.Add("NewUser","IIsFtpVirtualDir") $virtualdir.psbase.CommitChanges() $virtualdir.put("Path","C:\FTP\NewUser") $virtualdir.put("AccessRead",$true) $virtualdir.put("AccessWrite",$false) $virtualdir.psbase.CommitChanges() $service.psbase.refreshCache() # OPTIONAL

Alternatively, you could do go straight for the path if you know it (IIS 6 seems to like this):

1$service = New-Object DirectoryServices.DirectoryEntry("IIS://localhost/MSFTPSVC/1/Root")
2$virtualdir = $service.psbase.children.Add("NewUser", "IIsFtpVirtualDir")
3$virtualdir.psbase.CommitChanges()
4$virtualdir.put("Path","C:\FTP\NewUser")
5$virtualdir.put("AccessRead",$true)
6$virtualdir.put("AccessWrite",$false)
7$virtualdir.psbase.CommitChanges()

If you would like to iterate through each of the virtual directories on your FTP server, you can use the following code:

1$service = New-Object System.DirectoryServices.DirectoryEntry("IIS://$env:computername/MSFTPSVC")
2$site = $service.psbase.children | Where-Object { $_.ServerComment -eq 'Default FTP Site' }
3$virtualdirs = $site.psbase.children.Find("Root","IIsFtpVirtualDir").psbase.children
4foreach ($virtualdir in $virtualdirs) {$virtualdir.psbase.name}

This code is likely applicable to many of the objects in the IIS ADSI provider. While I've only tested this on Vista (IIS 7), this should also work for Windows XP and 2003's IIS 6 as Vista uses IIS 6's MMC for management.

Also, if you are wondering how I know when to use psbase or psbase.children, I really don't. I just fumble around until I get it to work. The 4 lines above, specifically $virtualdirs = $site.psbase.children.Find("Root","IIsFtpVirtualDir").psbase.children took me about seven hours to figure out. I hear PowerShell 2.0 will have much better support for Directory Services and hopefully that will include support the IIS FTP service.