I was recently contacted by someone who was trying to use Windows Management Instrumentation (WMI) code to stop and restart FTP websites by using code that he had written for IIS 6.0; his code was something similar to the following:
Option Explicit
On Error Resume Next
Dim objWMIService, colItems, objItem
' Attach to the IIS service.
Set objWMIService = GetObject("winmgmts:\root\microsoftiisv2")
' Retrieve the collection of FTP sites.
Set colItems = objWMIService.ExecQuery("Select * from IIsFtpServer")
' Loop through the sites collection.
For Each objItem in colItems
' Restart one single website.
If (objItem.Name = "MSFTPSVC/1") Then
Err.Clear
objItem.Stop
If (Err.Number <> 0) Then WScript.Echo Err.Number
objItem.Start
If (Err.Number <> 0) Then WScript.Echo Err.Number
End If
Next
The problem that the customer was seeing is that this query did not return the list of FTP-based websites for IIS 7.0 or IIS 7.5 (called IIS7 henceforth), although changing the class in the query from IIsFtpServer to IIsWebServer would make the script work with HTTP-based websites those versions of IIS7.
The problem with the customer's code was that he is using WMI to manage IIS7; this relies on our old management APIs that have been deprecated, although part of that model is partially available through the metabase compatibility feature in IIS7. Here's what I mean by "partially": only a portion of the old ADSI/WMI objects are available, and unfortunately FTP is not part of the objects that can be scripted through the metabase compatibility feature in IIS7.
That being said, what the customer wants to do is still possible through scripting in both IIS7 and IIS8, and the following sample shows how to loop through all of the sites, determine which sites have FTP bindings, and then stop/start FTP for each site. To use this script, copy the code into a text editor like Windows Notepad and save it with a name like "RestartAllFtpSites.vbs" to your system, then double-click the file to run it.
' Temporarily disable breaking on runtime errors.
On Error Resume Next
' Create an Admin Manager object.
Set adminManager = CreateObject("Microsoft.ApplicationHost.AdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
' Test for commit path support.
If Err.Number <> 0 Then
Err.Clear
' Create a Writable Admin Manager object.
Set adminManager = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
If Err.Number <> 0 Then WScript.Quit
End If
' Resume breaking on runtime errors.
On Error Goto 0
' Retrieve the sites collection.
Set sitesSection = adminManager.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST")
Set sitesCollection = sitesSection.Collection
' Loop through the sites collection.
For siteCount = 0 To CInt(sitesCollection.Count)-1
isFtpSite = False
' Determine if the current site is an FTP site by checking the bindings.
Set siteElement = sitesCollection(siteCount)
Set bindingsCollection = siteElement.ChildElements.Item("bindings").Collection
For bindingsCount = 0 To CInt(bindingsCollection.Count)-1
Set bindingElement = bindingsCollection(bindingsCount)
If StrComp(CStr(bindingElement.Properties.Item("protocol").Value),"ftp",vbTextCompare)=0 Then
isFtpSite = True
Exit For
End If
Next
' If it's an FTP site, start and stop the site.
If isFtpSite = True Then
Set ftpServerElement = siteElement.ChildElements.Item("ftpServer")
' Create an instance of the Stop method.
Set stopFtpSite = ftpServerElement.Methods.Item("Stop").CreateInstance()
' Execute the method to stop the FTP site.
stopFtpSite.Execute()
' Create an instance of the Start method.
Set startFtpSite = ftpServerElement.Methods.Item("Start").CreateInstance()
' Execute the method to start the FTP site.
startFtpSite.Execute()
End If
Next
And the following code sample shows how to stop/start a single FTP site. To use this script, copy the code into a text editor like Windows Notepad, rename the site name appropriately for one of your FTP sites, save it with a name like "RestartContosoFtpSite.vbs" to your system, then double-click the file to run it.
' Temporarily disable breaking on runtime errors.
On Error Resume Next
' Create an Admin Manager object.
Set adminManager = CreateObject("Microsoft.ApplicationHost.AdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
' Test for commit path support.
If Err.Number <> 0 Then
Err.Clear
' Create a Writable Admin Manager object.
Set adminManager = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
If Err.Number <> 0 Then WScript.Quit
End If
' Resume breaking on runtime errors.
On Error Goto 0
' Retrieve the sites collection.
Set sitesSection = adminManager.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST")
Set sitesCollection = sitesSection.Collection
' Locate a specific site.
siteElementPos = FindElement(sitesCollection, "site", Array("name", "ftp.contoso.com"))
If siteElementPos = -1 Then
WScript.Echo "Site was not found!"
WScript.Quit
End If
' Determine if the selected site is an FTP site by checking the bindings.
Set siteElement = sitesCollection(siteElementPos)
Set bindingsCollection = siteElement.ChildElements.Item("bindings").Collection
For bindingsCount = 0 To CInt(bindingsCollection.Count)-1
Set bindingElement = bindingsCollection(bindingsCount)
If StrComp(CStr(bindingElement.Properties.Item("protocol").Value),"ftp",vbTextCompare)=0 Then
isFtpSite = True
Exit For
End If
Next
' If it's an FTP site, start and stop the site.
If isFtpSite = True Then
Set ftpServerElement = siteElement.ChildElements.Item("ftpServer")
' Create an instance of the Stop method.
Set stopFtpSite = ftpServerElement.Methods.Item("Stop").CreateInstance()
' Execute the method to stop the FTP site.
stopFtpSite.Execute()
' Create an instance of the Start method.
Set startFtpSite = ftpServerElement.Methods.Item("Start").CreateInstance()
' Execute the method to start the FTP site.
startFtpSite.Execute()
End If
' Locate and return the index for a specific element in a collection.
Function FindElement(collection, elementTagName, valuesToMatch)
For i = 0 To CInt(collection.Count) - 1
Set elem = collection.Item(i)
If elem.Name = elementTagName Then
matches = True
For iVal = 0 To UBound(valuesToMatch) Step 2
Set prop = elem.GetPropertyByName(valuesToMatch(iVal))
value = prop.Value
If Not IsNull(value) Then
value = CStr(value)
End If
If Not value = CStr(valuesToMatch(iVal + 1)) Then
matches = False
Exit For
End If
Next
If matches Then
Exit For
End If
End If
Next
If matches Then
FindElement = i
Else
FindElement = -1
End If
End Function
I hope this helps!
Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/