Archive for the Technologies Category

PowerShell to get remote website’s SSL certificate expiration

Posted in Monitoring, PowerShell, Scripting, Windows on 2014/02/04 by CRCerr0r

I recently needed to put together a PowerShell script that would check the expiration of some external and internal certificates for my company and let me know when they are close to expiring. Since some of the hosts were IP addresses, and some certs were not trusted by the machine running the check, I had to have a way to disable certificate chain validation (equivalent to the curl option -k). There are many ways to get web content in PowerShell, and some are more flexible than others… After some poking around, I put together the script below, combining examples from this post and this post.

$minimumCertAgeDays = 60
$timeoutMilliseconds = 10000
$urls = @(
) #disabling the cert validation check. This is what makes this whole thing work with invalid certs...
[Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} foreach ($url in $urls)
Write-Host Checking $url -f Green
$req = [Net.HttpWebRequest]::Create($url)
$req.Timeout = $timeoutMilliseconds try {$req.GetResponse() |Out-Null} catch {Write-Host Exception while checking URL $url`: $_ -f Red} [datetime]$expiration = $req.ServicePoint.Certificate.GetExpirationDateString()
[int]$certExpiresIn = ($expiration - $(get-date)).Days $certName = $req.ServicePoint.Certificate.GetName()
$certPublicKeyString = $req.ServicePoint.Certificate.GetPublicKeyString()
$certSerialNumber = $req.ServicePoint.Certificate.GetSerialNumberString()
$certThumbprint = $req.ServicePoint.Certificate.GetCertHashString()
$certEffectiveDate = $req.ServicePoint.Certificate.GetEffectiveDateString()
$certIssuer = $req.ServicePoint.Certificate.GetIssuerName() if ($certExpiresIn -gt $minimumCertAgeDays)
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] -f Green}
{Write-Host Cert for site $url expires in $certExpiresIn days [on $expiration] Threshold is $minimumCertAgeDays days. Check details:`n`nCert name: $certName`nCert public key: $certPublicKeyString`nCert serial number: $certSerialNumber`nCert thumbprint: $certThumbprint`nCert effective date: $certEffectiveDate`nCert issuer: $certIssuer -f Red} rv req
rv expiration
rv certExpiresIn

Hope it saves someone some time… 🙂

How to change the IP address of the cluster nodes hosting a SQL Server instance

Posted in Microsoft SQL Server with tags , on 2012/03/30 by CRCerr0r

For whatever reason, there doesn’t seem to be a good post on how to change the IP addresses of the physical cluster nodes hosting a clustered SQL instance (or multiple clustered SQL instances). So after piecing together some articles and testing, here are the simple steps:


2-node Microsoft Cluster, each node is running Windows Server 2008 R2. In my case I had two SQL 2008 instances, each normally running on one of the nodes, in an ‘Active-Active’ setup.

SQL Instance A – the applications and services belonging to one of the SQL instances (IPs, names, drives, services, etc.)

Node n – each of the nodes

  1. Take SQL Instance A offline on Node 1 (do not fail over, just take it offline)
  2. Change IP address on Network Adapters (in Windows)
  3. In Cluster Administrator, change the IP address of the all SQL resources (Services and applications) of Instance A to new IPs. You have to do this twice for some reason (click Apply, then OK, then open the properties again and re-set the IP – you will know you need to do it, when the IP under the Resource Name says “”IP Address: Address on Cluster Network x” instead of the actual IP address, and when you open the properties, the mask is set to Confirm a new network has been created under Networks and it is setup as Enabled
  4. Bring Instance A online
  5. Repeat 1-4 for the second instance on Node 2 for Instance B
  6. Failover to test

Simple. 🙂

PowerShell Invoke-SQLcmd cmdlet “Could not find stored procedure”

Posted in PowerShell, Scripting with tags on 2011/07/16 by CRCerr0r

If, in the process of writing a script using Invoke-SQLcmd cmdlet from the SQL 2005/2008 shell you get “Could not find stored procedure” back, but you know what you are executing IS there, or it is not even a stored procedure, check the input. In my case the input T-SQL had quotes around it, which is what choked the command. Remove the quotes from the input string – the issue goes away.

SCOM 2007 Regular Expressions

Posted in Microsoft, Monitoring, SCOM on 2011/06/24 by CRCerr0r

One of the hardest thing to deal with in SCOM over the years (for me) has been understanding how SCOM interprets RegEx. It has been frustrating, to say the least. And for whatever reason, everything else to do with SCOM has been very well documented, expanded by the community and freely available. Not RegEx info. So today, working on a non-related issue, I came across this post that had some really good, concise info on how SCOM handles RegEx. In case the post gets deleted or lost or whatever, here is the excerpt (thanks to Dan Rogers):

Regular expression support in SCOM 2007

Many teams that are authoring management packs may need to include regular expression matching in their discoveries and groups, as well as for pattern matching in expression criteria in monitors and rules.

There are two different types of regular expression support in the SCOM product, and you have to know which element you are working in to choose the correct one.  Specifically, Group membership calculation and expression filters use distinctly different syntaxes for pattern matching.

Group Calculation matching criteria

Group calculation uses PERL regular expression syntax.  By default, the matching is case insensitive, but in the XML you can specify that an expression needs to be case sensitive by way of a special attribute dedicated to specifying that the expression content should be evaluated in a case sensitive way.

Group Calculation is found in your MP whenever you are using the Group Calc module.

The GroupCalc expression has an operator called MatchesRegularExpression that is used to create dynamic group membership based on pattern matching expressions.  The implementation of this operator passes the expression found in the MP XML to the SQL call name dbo.fn_MatchesRegularExpression.  If this call returns 0, the match is false.  If the expression returns 1, the match is true.

GroupCalc also supports two special sub-elements that abstract away a couple of common regex style queries.

GroupCalc sub element

Regex Equivalent

ContainsSubstring ^*{O}.*$                ({O} is replaced by the substring)
MatchesWildcard MP expression Regex Equivalent
? .
* .*
# [0-9]

Table 1:  GroupCalc special functions

Note:  If either of these two special operators are used, the evaluation will always be case sensitive.

Expression Filter matching criteria

Expression filters used in management packs use .NET Regex expression syntax.  A summary of the .NET regular expression syntax elements appears below.  Expression filters are present in your management pack whenever you are using the Expression Eval module.


SCOM Regex

Any Character


Character in Range

[ ]

Character not in range

[^ ]

Beginning of Line


End of Line





( )

0 or 1 matches


0 or more matches


1 or more matches


Exactly N matches


Atleast N matches

{n, }

Atmost N matches

{ , n}

N to M Matches

{n, m}

New line character


Tab character


Regular expressions via SDK

The SCOM SDK has a Matches criteria operator for filtering objects. This operator use the same functionality as MatchesCriteria in the GroupCalc case explained above.

When using the SDK to construct a criteria expression to find objects in the Ops Manager database, the following syntax elements are valid (see below).  This syntax is useful when creating a criteria expression that includes any of the following elements:

  • Comparison operators
  • Wildcard characters
  • DateTime values
  • Integer to XML Enumeration comparisons

Comparison operators

You can use comparison operators when constructing a criteria expression. The valid operators are described in the following table:

Operator Description Example(s)
=, == Evaluates to true if the left and right operand are equal. Name = ‘’
!=, <> Evaluates to true if the left and right operand are unequal. Name != ‘’
> Evaluates to true if the left operand is greater than the right operand. Severity > 0
< Evaluates to true if the left operand is less than the right operand. Severity < 2
>= Evaluates to true if the left operand is greater than or equal to the right operand. Severity >= 1
<= Evaluates to true if the left operand is less than or equal to the right operand. Severity <= 3
LIKE Evaluates to true if the left operand matches the pattern that is defined by the right operand. Use the characters in the wildcard table later in this topic to define the pattern. Name ‘LIKE SQL%’Evaluates to true if the Name value is “SQLEngine.”Name LIKE ‘%SQL%’

Evaluates to true if the Name value is “MySQLEngine.”

MATCHES Evaluates to true if the left operand matches the regular expression defined by the right operand. Name MATCHES ‘SQL*05’Evaluates to true if the Name value is “SQL2005.”
IS NULL Evaluates to true if the value of the left operand is null. ConnectorId IS NULLEvaluates to true if the ConnectorId property does not contain a value.
IS NOT NULL Evaluates to true if the value of the left operand is not null. ConnectorId IS NOT NULLEvaluates to true if the ConnectorId property contains a value.
IN Evaluates to trueif the value of the left operand is in the list of values defined by the right operand.

The IN operator is valid for use only with properties of type Guid.
Id IN (‘080F192C-52D2-423D-8953-B3EC8C3CD001’, ‘080F192C-53B2-403D-8753-B3EC8C3CD002’)Evaluates to true if the value of the Id property is one of the two globally unique identifiers provided in the expression.
AND Evaluates to true if the left and right operands are both true. Name = ‘SQL%’ AND Description LIKE ‘MyData%’
OR Evaluates to true if either the left or right operand is true. Name = ‘SQL%’ OR Description LIKE ‘MyData%’
NOT Evaluates to true if the right operand is not true. NOT (Name = ‘IIS’ OR Name = ‘SQL’)

Table 3: SDK comparison operators


The following table defines the wildcard characters you can use to construct a pattern when using the LIKE operator:

Wildcard Description Example
% A wildcard that matches any number of characters. Name LIKE 'SQL%'Evaluates to true if the Name value is “SQLEngine.”Name LIKE '%SQL%'

Evaluates to true if the Name value is “MySQLEngine.”

_ A wildcard that matches a single character. Name LIKE 'SQL200_'Evaluates to true for the following Namevalues:”SQL2000″


The expression evaluates to false for “SQL200” because the symbol _ must match exactly one character in the Name value.
[] A wildcard that matches any one character that is enclosed in the character set.

Brackets are also used when qualifying references to MonitoringObject properties. For more information, see Defining Queries for Monitoring Objects.
Name LIKE 'SQL200[05]‘Evaluates to true for the following Namevalues:”SQL2000″


The expression evaluates to false for


[^] A wildcard that matches any one character that is not enclosed in the character set. Name LIKE 'SQL200[^05]'Evaluates to truefor”SQL2003.”

The expression evaluates to false for

“SQL2000” and


Table 4:  Wildcard operators used with LIKE operator

DateTime comparisons

When you use a DateTime value in a query expression, use the general DateTime format (“G”) to convert the DateTime value to a string value. For example,


string qStr = “TimeCreated <= ‘” + myInstant.ToString(“G”) + “‘”;

ManagementPackCriteria mpCriteria = new ManagementPackCriteria(qStr);

All date values need to be converted to the G format (GMT) so that valid string comparisons can be made.

Integer value comparison to enumerations

When you use an integer enumeration value in a query expression, cast the enumeration value to an integer. For example,


string qStr = “Severity > ” + (int)ManagementPackAlertSeverity.Warning;

MonitoringAlertCriteria alertCriteria = new MonitoringAlertCriteria(qStr);

Restore TMG 2010 Exported config from one server to another

Posted in ForeFront TMG 2010, Microsoft on 2011/03/04 by CRCerr0r

Imagine this situation:

  • You have a TMG 2010 box (I have tested this with the Enterprise Edition with SP1, Rollup 1 for SP1 and Rollup 2 for SP1)
  • The TMG box is dead or for whatever other reason you have to bring up a brand new TMG server to replace the old one
  • You don’t want to recreate all objects and rules.

This is what you can do:

You need to do a rule export (or if your box is dead, hopefully you did one before) that includes all sensitive information and user permissions. To do this:

  1. Right-click on ‘Forefront TMG (SERVER_NAME)’ and choose Export (Backup)
  2. Click Next
  3. Check BOTH boxes to Export confidential information and user permission settings, put a password in
  4. Give it a path to save to and complete the wizard


After you have the config file (it will be pretty large) copy it to the new server. The new server needs to be identical to the old one, down to the naming of the NICs. If you are putting the new server side-by-side with the old one, and both will be online for a bit, the new server must have different IPs, for obvious reasons. On mine, the old one’s IPs ended with .1 on every subnet (except the External one) so I made the new one end with .2 on every subnet.

The next thing you need to do is install TMG. Make sure it is isntalled the same way, including paths (if you installed the old one on D:\Program Files\… the new one must be the same) and patched with the same patches (TMG ones, not so much OS).

Open the XML export file from the old server in Notepad. Do a ‘find and replace’ for every OLD_SERVER_NAME and OLD_SERVER_IP values and replace them with their NEW_SERVER_NAME, NEW_SERVER_IP counterparts.

Import the config file into the new server choosing the ‘Overwrite’ option in the wizard. Restart the ‘Microsoft Forefront TMG Storage’ service (that will restart all TMG services)

If you had Site-to-Site VPN you may have to re-create it on the new server. If you get an error in the event log “The user SYSTEM dialed a connection named xxxxx which has failed. The error code returned on failure is 789.” check the IPs on each endpoint of the Site-ti-Site VPN. If you get an error “The user SYSTEM dialed a connection named xxxxx which has failed. The error code returned on failure is 812.” check the Dial-In properties of the account used for the Site-ti-Site VPN and make sure it is set to Allow.

How to integrate Remote Desktop Services and SharePoint

Posted in MOSS 2007, Remote Desktop Services (RDS), SharePoint on 2011/02/15 by CRCerr0r

I just finished setting up an RDS farm and, as part of the setup, I needed to setup the RDWeb (Remote Desktop Services Web Access) and integrate it with our SharePoint 2007 intranet portal. I was surprised to find out that the process of integrating RDS with SharePoint was rather tedious and not very well documented. I found a few articles, including one on TechNet that explained the process, however they were either incomplete or geared toward setting up SharePoint and RDWeb on the same server.

My situation (and from the many forum posts I read, it seems this was the case for many others) was different – I needed to setup a separate installation of RDS (and make it redundant see post here) and then integrate it with SharePoint. After piecing together a few different articles, blog posts and forum posts and a healthy amount of educated (and some not so educated… 🙂 ) guesses I finally got it to work. Here is how…

First – the environment. This was setup on a total of 8 servers:

  • 2 front end IIS servers running the Remote Desktop Web Access role only (setup with Windows NLB for load sharing and redundancy)
  • 2 middle tier boxes running Remote Desktop Licensing and Remote Desktop Connection Broker (setup as a Windows Cluster, for redundancy). One important thing to note is that the RemoteApp and Desktop Connection Management service was also clustered as it is an integral part of the application list population function for the front end IIS boxes and the SharePoint web part
  • 2 Session Host servers (load balanced with Windows NLB and setup in an RDS Farm)
  • 1 SharePoint front end server
  • 1 SharePoint DB server (not really related to the setup directly, but a part of the environment nevertheless)

All servers are Windows 2008 R2 Standard 64-bit, except the two middle tier clustered boxes, which were Windows 2008 R2 Enterprise 64-bit, because of the clustering. This is very important as it makes a BIG difference in some of the steps, especially in GAC registration (because of Windows 2008 R2) and certain paths I list (because of the 64-bit edition). If you have different setup, change details accordingly.

Here is the meat. This assumes you have a functional RDS environment, i.e. you can open applications via the standard RDWeb web site and that the RDWeb web site is setup with Windows Authentication, not Forms… If you have not done that, here is how:

Edit the C:\Windows\Web\RDWeb\Pages\web.config file:
– un-comment <authentication mode=”Windows”/> section
– comment out the <authentication mode=”Forms”> section.
– comment out the <modules> and <security> sections in the <system.webServer> section at the end of the file.

Now to the web part setup…

1. Edit the web.config of the SharePoint site you will be adding the RDS web part to, adding the following, in one line, to the SafeControls section. This can be the root site, or a sub site. Find the path to the file system from IIS manager:

<SafeControl Assembly=”TSPortalWebPart, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35″ Namespace=”Microsoft.TerminalServices.Publishing.Portal” TypeName=”*” Safe=”True” AllowRemoteDesigner=”True” />

2. Create images directory structure and secure it properly:

mkdir “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\wpresources\TSPortalWebPart\\images”

mkdir “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\wpresources\TSPortalWebPart\\rdp”

cacls “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\wpresources\TSPortalWebPart\\images” /T /E /P NetworkService:F

cacls “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\wpresources\TSPortalWebPart\\rdp” /T /E /P NetworkService:F

3. Copy TSPortalWebPart and TSPortalWebPart.Resources DLLs from a server running the “Remote Desktop Web Access” role:

xcopy C:\Windows\assembly\GAC_64\TSPortalWebPart c:\temp\TSPortalWebPart /d /e /c /i /y

xcopy C:\Windows\assembly\GAC_64\TSPortalWebPart.Resources c:\temp\TSPortalWebPart.Resources /d /e /c /i /y

4. Copy the two directories to your SharePoint server’s c:\temp

5. Login to the SharePoint server console as administrator

6. Open Task Manager, go to Processes tab and click Show Processes from all users

7. Kill ALL Explorer.exe instances for your session

8. Go to File, New Task (Run…) and open an Explorer.exe instance (this makes it run as admin and no, it does not work if you just right-click on Explorer and choose Run as administrator)

9. Drag and drop the c:\temp\TSPortalWebPart\\tsportalwebpart.dll and c:\temp\TSPortalWebPart\\TSPortalWebPart.resources.dll into the GAC (C:\Windows\assembly)

10. Verify the TSPortalWebPart and TSPortalWebPart.Resources directories are created under c:\Windows\assembly\GAC_MSIL\ (do a dir c:\Windows\assembly\GAC_MSIL\)

11. Copy the remaining files into the GAC directory created by dropping the two DLLs in

xcopy c:\temp\TSPortalWebPart\ c:\Windows\assembly\GAC_MSIL\TSPortalWebPart\ /d /e /c /i /y

xcopy c:\temp\TSPortalWebPart.Resources\

c:\Windows\assembly\GAC_MSIL\TSPortalWebPart.Resources\ /d /e /c /i /y

(the above three lines are actually one command, just concatenate them before executing. For some reason the blog editor is chopping off the end if they are all together…)

12. Recycle the site’s app pool

13. Populate the web part gallery

#In the upper-right corner, on the Site Actions tab, click Site Settings.
#Under Galleries, click Web Parts.
#Under the Web Part Gallery heading, click New.
#Select the check box next to Microsoft.TerminalServices.Publishing.Portal.TSPortalWebPart, and then click Populate Gallery.

14. Create images directory under the website root and copy all images from \TSPortalWebPart\ to it (PNG, GIF, JPEG)

15. Add the user account of the SharePoint web site App Pool into the TS Web Access Computers group on the server where RemoteApp and Desktop Connection Management service is running (it should already have the names of the front end Remote Web IIS servers). In my case it is the clustered middle tier.

16. Add the web part to the SharePoint site

17. In the web part choose RemoteApp and desktop Connection Management for Populate the Web Part from option and enter the name of the server/cluster where the service resides

Your web part should now have icons from the RDS Session Hosts.

Enjoy! 🙂

Migrating Small Business Server 2003 to Small Business Server 2008 (SBS 2008)

Posted in Microsoft Exchange, Small Business Server on 2011/01/11 by CRCerr0r

I recently installed a Small Business Server 2008, migrating content and mailboxes from a Small Business Server 2003 installation. I came across a few issues that I thought would post here in case they are helpful to someone else…

Issue 1:

BlackBerries (through Verizon Wireless) stopped getting mail after the upgrade was complete. iPhones and Android phones did not have issues, just BBs. “Peeling the onion” I realized that BlackBerry uses the Outlook Web Access URL to login to the mailbox and get mail, while the iPhones and Android phones use Microsoft ActiveSync (as ALL normal modern devices should). The problem lies in the fact that the URL changed from https://SERVER-URL/Exchange in Exchange 2000 (on SBS 2003) to https://SERVER-URL/owa in Exchange 2007 (on SBS 2008). The Blackberries apparently keep trying the old URL and fail miserably.

After many calls to Verizon and BlackBerry Technical Support and predatory forcing of data plan upgrades the BBs still did not get connected. In the BlackBerry web site they would get setup, but eventually the little check mark next to the mail profile would turn into a circle with a cross through it. So I gave up that route.

I decided to set them up with an IMAP profile. One of the devices setup without issues after I enabled the IMAP client access on Exchange and created a Client Mail connector for them to be able to send mail. The other device failed with an error “This POP server is not supported as it does not have sufficient capabilities. Please try a different POP server.”. Very helpful. 😦 Afer more calls to Verizon and more changed to the plan and asking me to force a “routing table update” on the phone and blah, blah, blah, still nothing. So I decided to see if the same account would be able to setup the mailbox for the device that worked. It did. So it was not the BlackBerry service, or the account plan or none of that nonsense. It had to be something with that mailbox.

I tried setting it up through Outlook thinking that it would give me a little more sensible error. It didn’t… But I thought I’d share what Outlook gave me in case someone else comes across the same error:

Connection is closed. 15
Protocol: IMAP
Port: 993
Error Code: 0x800CCCDD

So I proceeded… I followed this article to enable IMAP logging (by the way this article has a really nice explanation of Exchange 2007 logs) and then tried again. Here is the result:

2011-01-11T12:45:12.010Z,,0000000000EA8015,1,,,>,* OK The Microsoft Exchange IMAP4 service is ready.,
2011-01-11T12:45:12.135Z,,0000000000EA8015,2,,,<,1 LOGIN FLAST *****,
2011-01-11T12:45:12.135Z,,0000000000EA8015,3,,,*,,”User FIRST LAST Server name SERVER.DOMAIN.local, version 1912701168, legacyId /o=First Organization/ou=first administrative group/cn=Recipients/cn=FLAST
2011-01-11T12:45:12.151Z,,0000000000EA8015,4,,,>,1 OK LOGIN completed.,
2011-01-11T12:45:12.197Z,,0000000000EA8015,5,,,<,2 CAPABILITY,
2011-01-11T12:45:12.197Z,,0000000000EA8015,7,,,>,2 OK CAPABILITY completed.,
2011-01-11T12:45:12.244Z,,0000000000EA8015,8,,,<,3 SELECT INBOX,
2011-01-11T12:45:12.260Z,,0000000000EA8015,9,,,>,”3 BAD Duplicate folders Drafts, Journal, Notes, Tasks were detected in the mailbox. Therefore the user’s connection was disconnected.“,
2011-01-11T12:45:12.260Z,,0000000000EA8015,10,,,>,* BYE Connection is closed. 15,

So that was great! Easy fix! The user did indeed have those duplicate folders and after deleting them in Outlook (it only lets you delete the ones that are not needed) the account setup fine through 🙂

Issue 2:

Outlook keeps popping up an authentication prompt. This one I am almost certain I have solved (if there is more, I will update the post). It seems the users were getting the prompt almost every 5 min. It was saying “Welcome back to” I saw a lot of 401.1 and 401.2 errors in the IIS logs of the SBS Web Applications web site. In addition, the Outlook Autodiscover test was throwing a 0×80040413 erro error… After some digging I came across this post that pointed to Rollup 9 for Service Pack 1 for Exchange 2007. Since SP 2 is already out, I just downloaded that and installed it. If you do have to do that on a SBS 2008 server, you also need to download this tool and use IT to install or otherwise your install will fail.

Also, keep in mind that the SP install tool has a few known issues (see the KB article of the installation tool) like resetting SSL on the default web site and apparently (which was not documented, but I experienced first hand) it resets the logging configuration for IMAP (enabled in the C:\Program Files\Microsoft\Exchange Server\ClientAccess\PopImap\Microsoft.Exchange.Imap4.exe.config) and the X.509 Certificate Name in the Server Configuration – Client Access – POP3 and IMAP4 – IMAP4 – Authentication tab to the default server.domain.local certificate name. Bummer.

Issue 3:

QuickBooks Database Server Manager does not start. Well, apparently it is not meant to run on a Windows 2008 server. After installing it it copied all the files and created/updated a QBDataServiceUSer20 user account, created the QuickBooksDB20 service, but it failed to make sure the NTFS permission on the .\Program Files\Intuit\QuickBooks 2010 are properly setup so the QBDataServiceUSer20 user has access to it. It does not by default… So if you try to start it it fails with “The system cannot find the file specified”. Updating the permissions and opening the appropriate ports (TCP 55338, 8019, 10180) takes care of the issue.

Issue 4:

Installing SQL 2008 Standard on the SBS 2008 Premium server fails with “rule “SQL Server 2005 Express tools” failed. The SQL Server 2005 Express tolls are installed. To continue, remove the SQL Server 2005 Express Tools”. After some digging and looking at some posts on similar issues it turns out renaming the

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\90\Tools\ShellSEM key


HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SQL Server\90\Tools\ShellSEM.old

solves the issue. Oddly enough, the setup log shows this key being the culprit:

2011-01-15 12:35:25 Slp: Sco: Attempting to create base registry key HKEY_LOCAL_MACHINE, machine
2011-01-15 12:35:25 Slp: Sco: Attempting to open registry subkey
2011-01-15 12:35:25 Slp: Sco: Attempting to open registry subkey SOFTWARE\Microsoft\Microsoft SQL Server\90\Tools\ShellSEM
2011-01-15 12:35:25 Slp: Rule ‘Sql2005SsmsExpressFacet’ detection result: SQL 2005 Ssms EE installed=True
2011-01-15 12:35:25 Slp: Evaluating rule        : Sql2005SsmsExpressFacet
2011-01-15 12:35:25 Slp: Rule running on machine: SERVER_NAME
2011-01-15 12:35:25 Slp: Rule evaluation done   : Failed
2011-01-15 12:35:25 Slp: Rule evaluation message: The SQL Server 2005 Express Tools are installed. To continue, remove the SQL Server 2005 Express Tools.

But I think because the box is 64-bit the key is masked.


Hope this helps someone out there and saves them a few hours of hair pulling. 🙂