Imports Microsoft.MetadirectoryServices Imports System.IO Imports System.Data.SqlClient Imports System.DirectoryServices
' CSExtension for an MA which manages Virtual Directories in IIS. ' IIS must be installed on the ILM server as code relies on iisVDir.vbs, ' however the websites can be on a remote server.
' Written by Carol Wapshere, 17th January 2008
Public Class MACallExport_StaffWebsites Implements IMAExtensibleFileImport Implements IMAExtensibleCallExport
Const IIS_SERVER As String = "dc01" Const PARENT_SHARE As String = "\\dc01\StaffWebsites\" Const PARENT_FLDR As String = "C:\StaffWebsites\" Dim LOGFILE_NAME As String = MAUtils.MAFolder & "\export.log"
Dim logfile As StreamWriter
Public Sub GenerateImportFile(ByVal filename As String, ByVal connectTo As String, ByVal user As String, ByVal password As String, ByVal configParameters As ConfigParameterCollection, ByVal fullImport As Boolean, ByVal types As TypeDescriptionCollection, ByRef customData As String) Implements IMAExtensibleFileImport.GenerateImportFile  Dim iisVdirQuery As String = RunCmd("cscript iisvdir.vbs /s " & IIS_SERVER & " /query w3svc/1/ROOT/Staff")  Dim arrVDir(,) As String  Dim i, j As Integer
 i = -1  Dim posEnd As Integer = iisVdirQuery.LastIndexOf("=")  Dim posStart As Integer = iisVdirQuery.IndexOf("/", posEnd)
 While iisVdirQuery.Substring(posStart, 1) = "/"   i = i + 1    ReDim Preserve arrVDir(1, i)   posEnd = iisVdirQuery.IndexOf(" ", posStart)   arrVDir(0, i) = iisVdirQuery.Substring(posStart, posEnd - posStart).Replace("/", "")   posStart = posStart + 35   posEnd = iisVdirQuery.IndexOf(vbCrLf, posStart)   arrVDir(1, i) = iisVdirQuery.Substring(posStart, posEnd - posStart)    posStart = posEnd + 2  End While
 Dim fw As StreamWriter   Try    'Open the output file specified in the run profile    fw = New StreamWriter(filename, False)    Catch ex As Exception    Throw New UnauthorizedAccessException("Unable to open file: " & filename)   End Try
 fw.WriteLine("alias,path")  If i >= 0 Then    For j = 0 To i      fw.WriteLine(arrVDir(0, j) & "," & arrVDir(1, j))    Next  End If  fw.Close() End Sub
Public Sub BeginExport(ByVal connectTo As String, ByVal user As String, ByVal password As String, ByVal configParameters As ConfigParameterCollection, ByVal types As TypeDescriptionCollection) Implements IMAExtensibleCallExport.BeginExport  logfile = New StreamWriter(LOGFILE_NAME, False) End Sub
Public Sub ExportEntry(ByVal modificationType As ModificationType, ByVal changedAttributes As String(), ByVal csentry As CSEntry) Implements IMAExtensibleCallExport.ExportEntry  Dim VDirAlias As String = csentry("alias").Value  If modificationType = Microsoft.MetadirectoryServices.ModificationType.Add Then    CreateVDir(VDirAlias)  ElseIf modificationType = Microsoft.MetadirectoryServices.ModificationType.Delete Then    DeleteVDir(VDirAlias)  ElseIf modificationType = Microsoft.MetadirectoryServices.ModificationType.Replace Then    RenameVDir(csentry)  End If End Sub
Public Sub EndExport() Implements IMAExtensibleCallExport.EndExport  logfile.Close() End Sub
Private Sub CreateVDir(ByRef VDirAlias As String) Dim newSharePath As String = PARENT_SHARE & VDirAlias Dim newDrivePath As String = PARENT_FLDR & VDirAlias Dim templatePath As String = PARENT_SHARE & "template"
If Not System.IO.Directory.Exists(newSharePath) Then RunCmd("xcopy /I " & templatePath & " " & newSharePath) Else logfile.WriteLine("File " & newDrivePath & " already exists.") End If RunCmd("cacls " & PARENT_SHARE & VDirAlias & " /E /G " & VDirAlias & ":C") RunCmd("cscript iisvdir.vbs /s " & IIS_SERVER & " /create w3svc/1/ROOT/Staff " & VDirAlias & " " & PARENT_FLDR & VDirAlias) End Sub
Private Sub DeleteVDir(ByRef VDirAlias As String) 'Only deletes the Virtual Directory from IIS - the folder is not touched. RunCmd("cscript iisvdir.vbs /s " & IIS_SERVER & " /delete w3svc/1/ROOT/Staff/" & VDirAlias) End Sub
Private Sub RenameVDir(ByRef csentry As CSEntry) 'Renames the folder, deletes the old VDir, and creates a new one. 'In a production environment a redirect should also be created for the old address. Dim oldDrivePath As String = csentry("path").Value Dim oldAlias As String = oldDrivePath.Substring(oldDrivePath.LastIndexOf("\") + 1) Dim oldSharePath As String = PARENT_SHARE & "\" & oldAlias Dim newAlias As String = csentry("alias").Value Dim newSharePath As String = PARENT_SHARE & "\" & newAlias Dim newDrivePath As String = PARENT_FLDR & "\" & newAlias
RunCmd("ren " & oldSharePath & " " & newSharePath) RunCmd("cscript iisvdir.vbs /s " & IIS_SERVER & " /delete w3svc/1/ROOT/Staff/" & oldAlias) RunCmd("cscript iisvdir.vbs /s " & IIS_SERVER & " /create w3svc/1/ROOT/Staff " & newAlias & " " & newDrivePath) End Sub
Private Function RunCmd(ByRef command As String) As String 'Run a command in a cmd process and returns the output
logfile.Write(command) Dim myProcess As Process = New Process() Dim s As String myProcess.StartInfo.FileName = "cmd.exe" With myProcess.StartInfo .UseShellExecute = False .CreateNoWindow = True .RedirectStandardInput = True .RedirectStandardOutput = True .RedirectStandardError = True End With myProcess.Start()
Dim sIn As StreamWriter = myProcess.StandardInput sIn.AutoFlush = True Dim sOut As StreamReader = myProcess.StandardOutput Dim sErr As StreamReader = myProcess.StandardError
sIn.Write(command & System.Environment.NewLine) sIn.Write("exit" & System.Environment.NewLine) s = sOut.ReadToEnd() If Not myProcess.HasExited Then myProcess.Kill() End If
sIn.Close() sOut.Close() sErr.Close() myProcess.Close() Return s End Function
End Class