Microsoft Bob

Just a short, simple blog for Bob to share some tips and tricks.

Be sure to check out my non-technical blog at www.bobsbasement.net.

Month List

Day 2 of IIS at TechEd IT Forum in Barcelona

Today was the second day of Microsoft Tech∙Ed: IT Forum 2006 in Barcelona. So far everything seems to be going well, and I've had the chance to talk with some great customers. Once again, the customers that visited our booth are most concerned with Clustering/Load Balancing/Replication and IIS/PHP integration. But that being said, I had the chance to demo some great functionality for customers that dropped by.

Today I was joined by Isaac Roybal from Microsoft, who is a Product Manager in Windows Server Marketing, and we shared the booth with Eric Lawrence, who is a Program Manager for Internet Explorer:

I delivered the first of my presentations today to a crowd of 175, and my feedback scores for the presentation were about the average for the connected systems infrastructure track. The main points that attendees wanted me to do better was to not go so deep in my topics and to slow down a little. (Sigh.)

After we had finished up for the day, Sergei, Isaac, several members of the PowerShell team and I met for dinner with a couple of the guys from MySpace. Here's a shot of Sergei talking with Michael Coates, who is an evangelist on the Platform Evangelism team.

Tomorrow I don't have any presentations, so I should be hanging around the booth most of the day.

Posted: Nov 15 2006, 20:23 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Day 1 of IIS at TechEd IT Forum in Barcelona

Today was the first official day of the 2006 Microsoft Tech∙Ed: IT Forum in Barcelona. I caught Bob Muglia's opening keynote address, and there were some great demos: Vista, Office 2007, SharePoint 2007, etc., but the best demo from an IIS perspective was when they managed a web farm of IIS 7 servers using PowerShell. They also discussed the new FastCGI technology in IIS and how it can be used for faster PHP or other CGI technologies.

Sergei Anatov and I were joined at the IIS "Ask The Experts" booth today by Ivan Gonzalez Vilaboa, who is an IIS MVP from spain. (Thanks, Ivan!)

Based on the customers that visited our booth, here are the pressing questions that seemed to be on most everyone's mind regarding the future of IIS:

  • Clustering/Load Balancing/Replication - People want to know what IIS is going to do about these technologies.
    I discussed replication in Vista/Longhorn and using distributed configuration files with IIS 7, but it was still the #1 subject for customers.
  • IIS and PHP - Is IIS going to have a PHP engine built-in?
    There was a bit of confusion on the information that was presented in the keynote address, because several people got the impression that IIS was going to ship with a PHP script engine. I had the misfortune of communicating that this is not the case, and showed people the annoucement on www.iis.net that discusses the technical preview of FastCGI.

That's all for today. See you tomorrow!

Posted: Nov 14 2006, 18:08 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Day 0 of IIS at TechEd IT Forum in Barcelona

Today is the main registration day for the 2006 Microsoft Tech∙Ed: IT Forum in Barcelona. The show was sold out weeks ago, so there are 4,750 people scheduled to attend, and another 400 people on the waiting list. There were a few pre-conference sessions today, but the main bulk of the show starts tomorrow.

Sergei Anatov and I will be demonstrating IIS 7 and answering questions for any version of IIS at the IIS/IE booth in the "Ask The Experts" lounge, then later in the week I'll be delivering two presentations on IIS:

  • 17 November at 09:00 - Building a Custom Log Analysis Solution with Log Parser 2.2 for Internet Information Services (IIS) 6 (CSI303)
  • 15 November at 17:00 - An Administrator's Guide to Internet Information Services (IIS) 7.0 (CSI201)

If you're at Tech∙Ed, feel free to drop by and say "Hi!"

Posted: Nov 13 2006, 17:12 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Converting W3C log files to NCSA format

Around a year ago I wrote a blog entry titled "Converting NCSA log files to W3C format", which showed how to use the MSWC.IISLog object to convert log files in the NCSA format back to W3C format. I wrote that blog entry to make up for the fact that the CONVLOG.EXE utility only converts log files to NCSA format, which some older log analysis software packages require. So what happens if you have a bunch of log files in W3C format and you don't have a copy of CONVLOG.EXE on your computer?

This blog entry is something of a reverse direction on my previous post, and shows you how to use the MSUtil.LogQuery object to convert W3C log files to NCSA format. The MSUtil.LogQuery object is shipped with LogParser, which you can download from one of the following URLs:

Once you've downloaded and installed the LogParser package, you will need to manually register the LogParser.dll file in order to use the MSUtil.LogQuery object. Having done so, you can use the Windows Script Host (WSH) code in this blog article to convert a folder filled with W3C log files to NCSA format. 

To use this code, just copy the code into notepad, and save it with a ".vbs" file extension on your system. To run it, copy the script to a folder that contains your W3C log files, (named "ex*.log"), then double-click it.

Option Explicit
Dim objFSO
Dim objFolder
Dim objInputFile
Dim objOutputFile
Dim objLogQuery
Dim objLogRecordSet
Dim objLogRecord
Dim strInputPath
Dim strOutputPath
Dim strLogRecord
Dim strLogTemp

Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(".")

For Each objInputFile In objFolder.Files
 strInputPath = LCase(objInputFile.Name)
 If Left(strInputPath,2) = "ex" And Right(strInputPath,4) = ".log" Then
  strOutputPath = objFolder.Path & "\" & "nc" & Mid(strInputPath,3)
  strInputPath = objFolder.Path & "\" & strInputPath
  Set objLogQuery = CreateObject("MSUtil.LogQuery")
  Set objLogRecordSet = objLogQuery.Execute("SELECT * FROM " & strInputPath)
  Set objOutputFile = objFSO.CreateTextFile(strOutputPath)
  Do While Not objLogRecordSet.atEnd
  
   Set objLogRecord = objLogRecordSet.getRecord
   strLogRecord = FormatField(objLogRecord.getValue("c-ip"))
   strLogRecord = strLogRecord & " " & FormatField("")
   strLogRecord = strLogRecord & " " & FormatField(objLogRecord.getValue("cs-username"))
   strLogTemp = BuildDateTime(objLogRecord.getValue("date"),objLogRecord.getValue("time"))
   strLogRecord = strLogRecord & " " & FormatField(strLogTemp)
   strLogRecord = strLogRecord & " """ & FormatField(objLogRecord.getValue("cs-method"))
   strLogRecord = strLogRecord & " " & FormatField(objLogRecord.getValue("cs-uri-stem"))
   strLogTemp = FormatField(objLogRecord.getValue("cs-version"))
   If strLogTemp = "-" Then
    strLogRecord = strLogRecord & " HTTP/1.0"""
   Else
    strLogRecord = strLogRecord & " " & strLogTemp & """"
   End If   
   strLogRecord = strLogRecord & " " & FormatField(objLogRecord.getValue("sc-status"))
   strLogRecord = strLogRecord & " " & FormatField(objLogRecord.getValue("sc-bytes"))
    objOutputFile.WriteLine strLogRecord
   objLogRecordSet.moveNext
  Loop
  
  Set objLogQuery = Nothing
  objOutputFile.Close
 
 End If
Next

Function FormatField(tmpField)
 On Error Resume Next
 FormatField = "-"
 If Len(tmpField) > 0 Then FormatField = Trim(tmpField)
End Function

Function BuildDateTime(tmpDate,tmpTime)
 On Error Resume Next
 BuildDateTime = "[" & _
  Right("0" & Day(tmpDate),2) & "/" & _
  Left(MonthName(Month(tmpDate)),3) & "/" & _
  Year(tmpDate) & ":" & _
  Right("0" & Hour(tmpTime),2) & ":" & _
  Right("0" & Minute(tmpTime),2) & ":" & _
  Right("0" & Second(tmpTime),2) & _
  " +0000]"
End Function

I hope this helps!

Posted: Nov 06 2006, 21:08 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | LogParser
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Testing IIS 7 for Yourself

The momentum for IIS 7 is gradually building, and I keep seeing great things in the press and several blogs about it. You can read a few details below:

IIS 7 contains a number of great features, and there are a couple of ways that you can get your hands on it for testing without installing the Vista or Longhorn Beta:

Have fun!

Posted: Oct 30 2006, 15:39 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

IIS Show #8

Okay, it's somewhat self-promoting, but I was cornered by Brett Hill the other day, who is the IIS 7 Evangelist for Microsoft, and he interviewed me for the IIS Show on MSDN's Channel 9:

http://channel9.msdn.com/Shows/IIS_Show

We discuss several topics like IIS history, HTTP modules in IIS 7, componentization in IIS 7, etc.

Posted: Sep 19 2006, 19:34 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS News Item
Tags: ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

IIS 6: FTP User Isolation with Multiple User Accounts

In IIS 4.0 and IIS 5.0, if you created a virtual directory that had a name that was identical to a user name, when the user logged in to the FTP site they would automatically be changed to their folder. When multiple users will access the same FTP content, you could create another virtual directory that is identical to the other user name and point it to the same content.

This allowed sharing a single FTP site across several users and content sets without advertising user names or content folders. Even though a user could type "CD /" from an FTP prompt, they would not be able to see the virtual directories from other user accounts on that server because virtual directories are not listed when a user types "ls -l" or "dir" from an FTP prompt at the root. That being said, this security feature still doesn't go far enough from a security perspective.

One of the great IIS 6.0 features is User Isolation, which is discussed in the Hosting Multiple FTP Sites with FTP User Isolation (IIS 6.0) topic on MSDN. As a quick review, there are three different isolation modes that you can choose when creating an IIS 6.0 FTP site:

  • "Do Not Isolate Users"
    No user isolation; FTP works like IIS 4.0 or IIS 5.0.
    (Not covered in this post.)
  • "Isolate Users"
    Simple user isolation through folders.
    (Described below.)
  • "Isolate Users Using Active Directory"
    Requires A.D. configuration.
    (Not covered in this post.)

To configure the "Isolate Users" mode, you first need to create your FTP site and choose the "Isolate Users" option when prompted for FTP User Isolation. Once the FTP site has been created, you need to create a physical folder named "LocalUser" for local user accounts or named after your domain under your FTP server's root folder. To isolate users to a specific folder, you use these rules that I copied from the MSDN topic that I listed earlier in this post:

  • For anonymous users, the home directory is LocalUser\Public under the FTP root directory.
  • For local users, the home directory is LocalUser\UserName under the FTP root directory.
  • For users that log on with Domain\UserName, the home directory is Domain\UserName under the FTP root directory.

This is very easy to configure, and when a user logs in to your FTP server they will be restricted to their physical folder under the FTP root. Typing "CD /" from an FTP prompt will always restrict the user within their own site.

That being said, because physical directories are required for this configuration it may seem like a step backward when you consider that you used to be able to create multiple virtual directories that pointed to content in varying locations and for multiple user accounts. Not to worry, however, because Windows provides a way around this limitation using NTFS junctions.

For those of you that are not familiar with NTFS junctions, there are several topics that discuss this. (For example, see Inside Win2K NTFS, Part 1.) A junction is somewhat like a symbolic directory link in the UNIX world, where a junction looks like a folder but points to content that is physically located somewhere else. There are two tools that you can use to create junctions, LINKD from the Windows Resource Kit, and JUNCTION from www.sysinternals.com. Using these tools with IIS 6.0 can allow you the freedom to deploy FTP folder structures much like you did with IIS 4/5 while utilizing the user isolation features in IIS 6.

Here's an example - when configuring an IIS 6.0 FTP site, I used the following steps:

  1. I chose the "Isolate Users" option when creating my FTP site.
  2. I created the "LocalUser" physical folder under my FTP site's root folder.
  3. I created junctions under the "LocalUser" physical folder that were named after user accounts and pointed to various content folders.

When a user logs in to my FTP site using their user account, they are automatically dropped in their content folder via the junction. Since you can create multiple junctions that point to the same content folder, you can create junctions for every user account that will work with a set of content.

I hope this helps!

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: May 08 2006, 19:21 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: FTP | IIS
Tags: , ,
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

IIS 6: Reverting log files back to the default W3C fields

Recently I had to work with a customer that was trying to use a 3rd-party utility that read W3C log files and it was failing to complete processing. I had the customer send me his log files, and upon examination I discovered that the trouble was occuring because the customer had been experimenting with adding and removing the different fields from their log files and this was causing the log parsing utility to crash.

As luck would have it, IIS provides a useful logging utility object that you can read more about at the following URL:

I had used this logging utility object for an earlier project, so I was familiar with how it worked. With that knowledge in mind, I wrote the following script that loops through all of the log files in a folder and creates new log files in a subfolder that contain only the default W3C fields. (BTW - I sent this script to the customer and he was able to parse all of his log files successfully. ;-] )

Option Explicit
Randomize Timer

' Declare variables.

Dim objIISLog
Dim objFSO, objFolder, objFile
Dim objOutputFile, strInputFile
Dim strOutputFile, strOutputPath
Dim strLogRecord
Dim blnExists

' Create file system object.
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
' Retrieve an object For the current folder.
Set objFolder = objFSO.GetFolder(".")

' Create a subfolder with a random name.
blnExists = True
Do While blnExists = True
strOutputPath = objFolder.Path & "\" & CreateRandomName(20)
blnExists = objFSO.FolderExists(strOutputPath)
Loop
objFSO.CreateFolder strOutputPath

' Loop through the log files in the current folder.
For Each objFile In objFolder.Files

' Test for a log file.
If Right(LCase(objFile.Name),4) = ".log" Then

' Format the file names/paths.
strInputFile = objFolder.Path & "\" & objFile.Name
strOutputFile = strOutputPath & "\" & objFile.Name

' Create and open an IIS logging object.
Set objIISLog = CreateObject("MSWC.IISLog")
' Open the input log file.
objIISLog.OpenLogFile strInputFile, 1, "", 0, ""
' Open the output log file.
Set objOutputFile = objFSO.CreateTextFile(strOutputFile)

' Read the initial record from the log file.
objIISLog.ReadLogRecord

' Write the headers to the output log file.
objOutputFile.WriteLine "#Software: Microsoft Internet Information Services 5.0"
objOutputFile.WriteLine "#Version: 1.0"
objOutputFile.WriteLine "#Date: " & BuildDateTime(objIISLog.DateTime)
objOutputFile.WriteLine "#Fields: date time c-ip cs-username s-ip s-port " & _
"cs-method cs-uri-stem cs-uri-query sc-status cs(User-Agent)"

' Loop through the records in the log file.
Do While Not objIISLog.AtEndOfLog

' Format the log file fields.
strLogRecord = BuildDateTime(objIISLog.DateTime)
strLogRecord = strLogRecord & _
" " & FormatField(objIISLog.ClientIP) & _
" " & FormatField(objIISLog.UserName) & _
" " & FormatField(objIISLog.ServerIP) & _
" " & FormatField(objIISLog.ServerPort) & _
" " & FormatField(objIISLog.Method) & _
" " & FormatField(objIISLog.URIStem) & _
" " & FormatField(objIISLog.URIQuery) & _
" " & FormatField(objIISLog.ProtocolStatus) & _
" " & FormatField(objIISLog.UserAgent)

' Write the output log file record.
objOutputFile.WriteLine strLogRecord

' Read the next record from the log file.
objIISLog.ReadLogRecord

Loop

' Close the input log file.
objIISLog.CloseLogFiles 1
objIISLog = Null

End If

Next

' Inform the user that the operation has completed.
MsgBox "Finished!"

' Format a log file field.
Function FormatField(tmpField)
On Error Resume Next
FormatField = "-"
If Len(tmpField) > 0 Then FormatField = Trim(tmpField)
End Function

' Format a log file date.
Function BuildDateTime(tmpDateTime)
On Error Resume Next
tmpDateTime = CDate(tmpDateTime)
BuildDateTime = Year(tmpDateTime) & "-" & _
Right("0" & Month(tmpDateTime),2) & "-" & _
Right("0" & Day(tmpDateTime),2) & " " & _
Right("0" & Hour(tmpDateTime),2) & ":" & _
Right("0" & Minute(tmpDateTime),2) & ":" & _
Right("0" & Second(tmpDateTime),2)
End Function

' Create a random name.
Function CreateRandomName(intNameLength)
Const strValidChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
Dim tmpX, tmpY, tmpZ
For tmpX = 1 To intNameLength
tmpY = Mid(strValidChars,Int(Rnd(1)*Len(strValidChars))+1,1)
tmpZ = tmpZ & tmpY
Next
CreateRandomName = tmpZ
End Function

Happy coding!

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Posted: Mar 27 2006, 12:01 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | Scripting
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

IIS 6: Creating an Itemized List of Server Bindings

One of my servers has a large number of individual web sites on it, and each of these web sites has several server bindings for different IP addresses, Port Assignments, and Host Headers. As I continue to add more web sites on the server, it becomes increasingly difficult to keep track of all the details using the IIS user interface.

With that in mind, I wrote the following ADSI script which creates a text file that contains an itemized list of all server bindings on a server.

Option Explicit
On Error Resume Next

Dim objBaseNode, objChildNode
Dim objBindings, intBindings
Dim objFSO, objFile, strOutput

' get a base object
Set objBaseNode = GetObject("IIS://LOCALHOST/W3SVC")
Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("ServerBindings.txt")

' check if if have an error ...
If (Err.Number <> 0) Then

    ' ... and output the error.
    strOutput = "Error " & Hex(Err.Number) & "("
    strOutput = strOutput & Err.Description & ") occurred."

' ... otherwise, continue processing.
Else
    ' loop through the child nodes
    For Each objChildNode In objBaseNode
        ' is this node for a web site?
        If objChildNode.class = "IIsWebServer" Then
            ' get the name of the node
            strOutput = strOutput & "LM/W3SVC/" & _
                objChildNode.Name
            ' get the server comment
            strOutput = strOutput & " (" & _
                objChildNode.ServerComment & ")" & vbCrLf
            ' get the bindings
            objBindings = objChildNode.ServerBindings
            ' loop through the bindings
            For intBindings = 0 To UBound(objBindings)
                strOutput = strOutput & vbTab & _
                    Chr(34) & objBindings(intBindings) & _
                    Chr(34) & vbCrLf
            Next
        End If
    ' try not to be a CPU hog
    Wscript.Sleep 10
    Next
End If

objFile.Write strOutput
objFile.Close

Set objBaseNode = Nothing
Set objFSO = Nothing

Hope this helps!

Posted: Feb 21 2006, 14:47 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | Scripting
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us

Updating several IP addresses using ADSI

(Note: I had originally posted this information on a blog that I kept on http://weblogs.asp.net, but it makes more sense to post it here. [:)] )

Like many web programmers, I host several hobby web sites for fun. (They make a wonderful test bed for new code. ;-] )

And like many computer enthusiasts, I sometimes change my ISP for one reason or another. If you are hosting web sites in a similar situation, I’m sure that you can identify the pain of trying to manually update each old IP address to your new IP address. This situation can be made even more difficult when any number of your web sites are using several host headers because the user interface for the IIS administration tool only lists the first host header. This means that you have to manually view the properties for every site just to locate the IP addresses that you are required to change.

Well, I'm a big believer in replacing any repetitive task with code when it is possible, and a recent change of ISP provided just the right level of inspiration for me to write a simple Active Directory Service Interfaces (ADSI) script that locates IP addresses that have to be changed and updates them to their new values.

To use the example script, I would first suggest that you make a backup copy of your metabase. (The script works fine, but it is always better to have a backup. ;-] ) As soon as your metabase has been backed up, copy the example script into notepad or some other text editor, update the old and new IP addresses that are defined as constants, and then run the script.

Option Explicit
On Error Resume Next
 
Dim objIIS
Dim objSite
Dim varBindings
Dim intBindings
Dim blnChanged
 
Const strOldIP = "10.0.0.1"
Const strNewIP = "192.168.0.1"
 
Set objIIS = GetObject("IIS://LOCALHOST/W3SVC")
 
If (Err <> 0) Then
  WScript.Echo "Error " & Hex(Err.Number) & "(" & _
    Err.Description & ") occurred."
  WScript.Quit
Else
  For Each objSite In objIIS
    blnChanged = False
    If objSite.class = "IIsWebServer" Then
      varBindings = objSite.ServerBindings
      For intBindings = 0 To UBound(varBindings)
        If InStr(varBindings(intBindings),strOldIP) Then
          blnChanged = True
          varBindings(intBindings) = Replace(varBindings(intBindings),strOldIP,strNewIP)
        End If
      Next
    End If
    If blnChanged = True Then
      objSite.ServerBindings = varBindings      
      objSite.Setinfo
    End If
  Next
End If
MsgBox "Finished!"

That’s all for now. Happy coding!

Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
Posted: Jan 11 2006, 03:38 by Bob | Comments (0)
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: IIS | Scripting
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us