How to solve 401.2 errors related to Windows Authentication and the BUILTIN\Administrators role in IIS 7

by Peter Tyrrell Tuesday, July 06, 2010 3:28 PM


An ASP.NET web application set to use Windows authentication where the web.config allows/denies authorization based on Windows roles, which references the BUILTIN\Administrators role specifically.

Your account is in the BUILTIN\Administrators group. The web application is running on a Windows OS with User Account Control [UAC] enabled. (hint HINT.)

Here's an example taken straight from official Microsoft Patterns and Practices: How To: use Windows Authentication in ASP.NET 2.0.



Even though your account is in the BUILTIN\Administrators group - you checked three times, pinching yourself in case you were dreaming - you cannot authenticate to get in to the web application. Instead, you get 401.2 errors.


You know your credentials are correct, because if you deliberately screw up your password, you get a 401.1 error. If you allow your specific account (DOMAIN\frustratedguy) in web.config, you can authenticate as normal.

It's as if the app doesn't think you are a member of the BUILTIN\Administrators role at all...


In fact, as far as the app is concerned, you are not a member of BUILTIN\Administrators. UAC has cast you out from that divine realm, and you no longer hold the keys to heaven.

using System.Web.Security

Listing roles might get you a list like:

None,Everyone,HomeUsers,BUILTIN\Users,NT AUTHORITY\NETWORK,NT AUTHORITY\Authenticated Users,NT AUTHORITY\This Organization,NT AUTHORITY\NTLM Authentication

No BUILTIN\Administrators. Allow another of those roles in web.config and your credentials will authenticate.

Myself, I didn't know how UAC actually worked. I knew that it didn't let me operate in the context of Administrator unless explicitly told to do so, but I didn't realize that meant that a role check would fail to find me in the Administrators group. Live and learn.


How to share wired internet wirelessly with a Windows 7 laptop

by Peter Tyrrell Tuesday, March 23, 2010 12:35 PM

I was recently on vacation in Maui, with my laptop and iPhone, and two other people had iPod Touches in the same condo, and we all had the same problem: no wireless. Damned if I was going to data roam in Hawai'i for $300/minute or whatever. In preparation for the trip I had in fact scoped out the nearest places that offered free wireless, and there were even some faint networks in the condo complex we could pick up by wandering around holding our mobile devices up like Spock searching for signs of life with a tricorder. This was inconvenient however, and also humiliating.

Then my father-in-law casually mentioned there *was* an internet connection in the condo, but only a wired one, didn't even think it was worth mentioning - oh, is that important? Why are you squealing and hopping around like a little girl in pigtails?

Within seconds I had the laptop connected by ethernet to the modem, and was setting up an ad hoc wireless network that would share the internet out to our various iPods.

I plan to do this again at various conferences this year where they charge vendors like ourselves horrendous internet connection rates per computer, because they can. Here's a heartfelt haiku on the matter:

at Spring conference
internet lines are costly
stick it to the Man

i. Create ad hoc wireless network

  1. Open Manage wireless networks from the Windows Start menu.
  2. Add a new network.
  3. Choose Create an ad hoc network.
  4. Enter a network name, which will be seen by wireless devices.
  5. Configure security options. Now, I had real trouble getting WPA2-Personal to work. I had to fall back to WEP if I wanted any security (a wide open connection worked fine, too). WEP needs you to enter a 5 or 13 character "seed" which creates a hexadecimal password. That created password is what you'll need to enter when connecting with wireless clients.

ii. Allow internet connection sharing

  1. Open View network connections from the Windows Start menu.
  2. Open Properties on the currently active wired Local Area Connection.
  3. Select the Sharing tab and check Allow other network users to connect etc. Then choose the Wireless Network Connection option from the dropdown.ics

iii. Configure wireless adapter settings

  1. Open View network connections from the Windows Start menu.
  2. Open Properties on the Wireless Network Connection.
  3. Select Internet Protocol Version 4 (TCP/IP) and then click Properties.
  4. Manually set the IP address to
  5. Manually set the Subnet mask to
  6. Manually set the Preferred DNS server to

iv. Turn on the ad hoc wireless network

  1. Open View network connections from the Windows Start menu.
  2. Right click on Wireless Network Connection and select Connect/Disconnect.
  3. Connect to the ad hoc network you created. Once connected, the connection will say Waiting for users in the Connect/Disconnect dialog.adhco_waiting

v. Connect with wifi-enabled mobile device

On a mobile device, look for the name of your ad hoc wireless network and connect to it the usual way. You will not need to set anything manually as the laptop will hand out IP addresses.

If you are using security, you will need to give users the password. (A WEP password will be particularly unmemorable.):

  1. Open Manage wireless networks from the Windows Start menu.
  2. Open Properties on the ad hoc network you created.
  3. Select the Security tab.
  4. Check Show characters to see the password.adhoc_password

Tags: tips

Replace MS Word special characters in javascript and C#

by Peter Tyrrell Wednesday, February 24, 2010 3:18 PM

MS Word uses characters from the Windows-1252 character encoding set which are not represented in ASCII or ISO-8859-1. This is often a pain in the butt. Special characters include:

  • the… ellipsis
  • ‘smart’ “quotes”
  • en – dash and em — dash
  • dagger † and double dagger ‡
  • and more, but these are most common.

If you want to replace them with ASCII cognates, here's a function to do that. (Daggers don't have cognates as far as I know.)


/// Replaces commonly-used Windows 1252 encoded chars that do not exist in ASCII or ISO-8859-1 with ISO-8859-1 cognates.
var replaceWordChars = function(text) {
    var s = text;
    // smart single quotes and apostrophe
    s = s.replace(/[\u2018\u2019\u201A]/g, "\'");
    // smart double quotes
    s = s.replace(/[\u201C\u201D\u201E]/g, "\"");
    // ellipsis
    s = s.replace(/\u2026/g, "...");
    // dashes
    s = s.replace(/[\u2013\u2014]/g, "-");
    // circumflex
    s = s.replace(/\u02C6/g, "^");
    // open angle bracket
    s = s.replace(/\u2039/g, "<");
    // close angle bracket
    s = s.replace(/\u203A/g, ">");
    // spaces
    s = s.replace(/[\u02DC\u00A0]/g, " ");
    return s;

C# extension method

public static string ReplaceWordChars(this string text)
            var s = text;
            // smart single quotes and apostrophe
            s = Regex.Replace(s, "[\u2018\u2019\u201A]", "'");
            // smart double quotes
            s = Regex.Replace(s, "[\u201C\u201D\u201E]", "\"");
            // ellipsis
            s = Regex.Replace(s, "\u2026", "...");
            // dashes
            s = Regex.Replace(s, "[\u2013\u2014]", "-");
            // circumflex
            s = Regex.Replace(s, "\u02C6", "^");
            // open angle bracket
            s = Regex.Replace(s, "\u2039", "<");
            // close angle bracket
            s = Regex.Replace(s, "\u203A", ">");
            // spaces
            s = Regex.Replace(s, "[\u02DC\u00A0]", " ");
            return s;

ClamAV on Windows 2008 x64 update

by Peter Tyrrell Friday, February 19, 2010 10:19 AM

Further to my previous post which describes how to install and run ClamAV as a service on Windows, here is extra info on what is required for Windows Server 2008 x64, discovered the hard way, through trial and error, by the persistent IT brains at SET-BC (Special Education Technology British Columbia). Particular thanks to IT Manager Gordon Eddy.

Configuring ClamD and FreshClam services

No special configuration is needed for the services. Clam and FreshClam both run fine under Local System, with automatic start and defaults for other service settings. The service account needs read/write access to C:\ClamAV, which it would have by default if Local System is used.

Starting the services

If the ClamD service is started from the services UI and there is no database, or the database is no good, it will fail silently. This could lead one off on a long goose chase looking at service accounts, permissions, service settings, etc. trying to figure out why the service won’t run, when in fact all you need is to run FreshClam once to get a good database, and then ClamD will run fine.

Run FreshClam immediately after installing ClamAV, before trying to run the ClamD service the first time. If FreshClam reports corruption or other problems with the existing database files, delete everything in ..\data and run FreshClam again.

There is no useful error info returned when trying to start ClamD from the services UI. On the other hand, starting it from a command prompt using "NET START CLAMD" does return a bit of useful info. Executing it directly as "clamd.exe --daemon" also returns some (different) info.

Registry setting required

There is a registry file in the ..\docs folder called clamav.reg that contains some path information. The docs seem to be saying that this is not necessary unless you are running Clam from somewhere other than the default location. We found this is not true. Even if installed to C:\ClamAV, Clam will not run without this info in the registry.

TCPAddr setting required

In clamd.config, the comments suggest that the TCPAddr setting is optional. It is not. Set it to the address at which ClamD should respond. If this is missing, the Clamd service will run, but will not respond to requests.

Charting Change Atlas: the technical details

by Peter Tyrrell Wednesday, February 17, 2010 11:14 AM

The City of Burnaby just launched their Charting Change Atlas, a series of interactive maps showing historical points of interest for the past 100 years. See the news post here. Since I was responsible for its development, I thought I’d talk about some of the technical aspects.

Over 350 points of interest, held as records in an Inmagic database, are associated with four map images. Making those images look and act like current web-based map applications was a bit of a challenge, and it was critical to keep page size down and performance snappy.

Map images

Each map image originated as a 2700 x 3500 TIFF, and each point of interest was located as an X/Y coordinate in pixels relative to the image. These images were not maps, but pictures that looked like maps. That meant we couldn't place points of interest on them via address or latitude/longitude.

The large images were then sliced into PNG tiles by excitable chefs wielding ginsu knives. The tiles are loaded dynamically when they are pulled into the visible viewport to cut down on initial load time. A modified version of the jQuery plugin Lazy Load is used to determine when an unloaded tile has appeared within the viewport.

A map framework

The viewport resizes to fit the browser resolution, whatever it is, regardless of the size of the map within, and reveals only a portion of the map at a time. It contains a very large outer div tag that marks the boundaries of the drag area, and an inner div that contains the map tiles.

The map can be dragged or scrolled in any direction, but the majority of it is hidden outside the viewport bounds. jQuery UI Draggable powers the drag mechanism. The snap-back feature, which pops the map back to the viewport boundary when the edges are pulled in too far, was inspired by my iPhone.

The rest of the map UI is a nod to current web-based map applications - i.e. Google Maps and Bing Maps - in an effort to create an intuitive and comfortable experience for a visitor. We found the more the application looked and acted like these map applications, the less we had to explain to a first-time user. On the other hand, it perhaps worked too well, because users keep expecting the map to zoom! It doesn't zoom because it consists of just the one layer, while Google, Bing and Co. boast multiple vertical layers. Something to work on in future...

Points of interest

The point data are recursively loaded sector by sector upon page load via jQuery AJAX to a .NET web service, which performs the database query and returns the results as a JSON object. This load sequence considerably improves the perception of performance: large amounts of data are pushed over the wire, but they are spread over the first few seconds following page load.

Pins are cloned from a pin template, stuffed with point of interest data and positioned relative to the map container. The dialog that appears when a pin is hovered over or clicked is built from a dialog template bound to pin data on demand. A modified version of John Resig's Micro-Templating function is used for client-side templating and databinding.

All points of interest are held inside a Heritage Landmarks Inmagic CS/Textworks database, already in use at, which was extended to hold information specific to the Charting Change Atlas project: query URLs out to other databases, a blurb and primary image, coordinates, and a Google Street View URL.


It was a blast designing and building the Charting Change Atlas, and a privilege to work together with the far-seeing heritage team at the City of Burnaby. Kudos to them for leveraging their existing toolset and informational treasure trove to make history so alive and accessible.


Month List