Monthly Archives: May 2011

It’s widely known that Microsoft allows anyone to install and use any version of Windows 7 for 30 days without having to enter a product activation key. By using the slmgr -rearm command, this 30-day trial period can be extended three times for a total of 120 days before the installation must be activated to continue functioning.

It is less known, perhaps, that Microsoft has implemented a similar method for delaying the activation of Office 2010 for up to 180 days. The steps below are from the Deploy volume activation of Office 2010 instructions on TechNet.

To rearm your Office 2010 installation

  1. Make sure all Office 2010 applications are closed.
  2. Open an elevated command prompt.
  3. Go to %installdir%\%Program Files%\Common Files\Microsoft Shared\OfficeSoftwareProtectionPlatform. If you installed the 32-bit edition of Office 2010 on a 64-bit operating system, %Program Files% is the Program Files (x86) folder.
  4. Run ospprearm.exe.

(The italics are mine, as I was tripped up for awhile by looking for ospprearm.exe under C:\Program Files\, rather than the Program Files (x86) folder.)

The Office 2010 rearm delays the activation requirement for 30 days, and it can be used five times, for a total of 180 days of activation-free use.

If you sign up for GameFly using this referral link, we both get a free month: http://gamefly.tellapal.com/a/clk/cxlkm. Even if you are signed up on the One Game Out plan, if someone uses your referral code to join, your reward is a free month at the Two Games Out plan (so you get an extra game, too).

The GameFly Refer-A-Friend Program is completely legit, even though the tellapal.com site is primitive and cheesy. Due mostly to this little blog post, I’ve been coasting along on free months for the last year, so if you can find a way of getting the word out (blog post, facebook, etc.), I would highly recommend it. It’s basically like having a free Gamefly account.

All told, as of June, 2012, I’ve been a Gamefly customer for 17 months and have only paid for five. I originally signed up using the free trial code in March, 2011, which I converted into the One Game Out plan in April. And that was fine for me, as I really only had time to play a few nights a week. But once I put this post up in May, 2011, the free months started pouring in. By July, 2011, they stopped billing my credit card and I was getting two games per month, which frankly was more than I needed.

My only gripe is that it seems to take one day longer than I’d expect to receive the games, as I live in Chicago and they’re usually shipped from Pittsburgh, PA. But they were awesome in that they sent Skyrim as soon as it was available (which I’ve had since last October). They sell older games for basically what you’d pay at Gamestop or whatever, and you earn more discounts by being a customer for a while.

So, be good to each others and get a free month for each friend who joins GameFly! (They get a free month too!)

Back in February, 2010, I posted instructions on how to create a bootable USB drive that can install any version of Windows 7. As of yesterday, ISOs of updated versions of Windows 7 with SP1 have been made available to Microsoft TechNet and MSDN subscribers.

If you want to update your install media with the ‘slipstreamed’ version, grab a torrent and then check it against the official Windows 7 SHA1 and ISO/CRC hashes.

The filenames for the 5/12/2011 versions of Windows 7 Ultimate are below.

Windows 7 Ultimate with Service Pack 1 (x64) – DVD (English): en_windows_7_ultimate_with_sp1_x64_dvd_u_677332.iso
(http://thepiratebay.org/torrent/6391716/Windows_7_x64_SP1_MSDN_Technet_May_2011_Refresh)

Windows 7 Ultimate with Service Pack 1 (x86) – DVD (English): en_windows_7_ultimate_with_sp1_x86_dvd_u_677460.iso

Typically, your ISP provides DNS services. In an ideal world, this would work well, as your ISP’s DNS server ought to be geographically close to your machine and should be able to perform look ups quickly. However, there are a number of reasons why you might want to use a public DNS server instead of your ISP’s server. The two big public DNS servers are OpenDNS and Google Public DNS.

OpenDNS

The OpenDNS nameserver IP addresses are:

  • 208.67.222.222
  • 208.67.220.220

http://www.opendns.com/support/article/197

You can confirm that you are using OpenDNS as your DNS resolution service by visiting http://www.opendns.com/welcome/.

Google Public DNS

The Google Public DNS nameserver IP addresses are:

  • 8.8.8.8
  • 8.8.4.4

http://code.google.com/speed/public-dns/docs/using.html

Speed test

So which DNS servers are faster for you?

Try out namebench. It hunts down the fastest DNS servers available for your computer to use. (For Mac OS X, Windows, and UNIX.)

http://code.google.com/p/namebench/

Using OpenDNS to filter (whitelist/blacklist) content

If you have an account with OpenDNS, you can whitelist and blacklist IP addresses. A free account allows you to whitelist or blacklist 25 addresses; paid accounts allow more.

  1. Create an account at OpenDNS.
  2. Set up a network for your physical location (your current IP address).
  3. Configure your machine to use the OpenDNS servers.
  4. Install the client software for updating a dynamic IP in an OpenDNS network – https://support.opendns.com/entries/23282614-Where-do-I-download-an-OpenDNS-Dynamic-IP-updater-client-.

Technically more sophisticated users may discover that manually setting the DNS servers on a computer allows that computer to circumvent the OpenDNS filtering. To prevent a machine from bypassing the OpenDNS filtering, you could configure the DNS servers directly on the router and then block all outgoing DNS requests to all DNS servers except the OpenDNS servers.

OpenDNS system status

It’s a good idea to be able to check the condition of your DNS server.

The OpenDNS system status page’s IP address is http://208.69.38.170/.

Seriously restricting internet access

What I really want to do is severely restrict internet access on a single machine on my LAN. For this machine, I want to manage a small whitelist of domains and block access to everything else. OpenDNS doesn’t seem to offer this type of functionality.

Just a few notes to myself about monitoring web sites for infections/malware and potential vulnerabilities.

Tools for detecting infections on web sites

Google Webmaster Tools

Your first stop should be here, as I’ve personally witnessed alerts show up in Webmaster Tools, even when all the following tools gave the site a passing grade. If your site is registered here, and Google finds weird pages on your site, an alert will appear. You can also have the messages forwarded to your email account on file, by choosing the Forward option under the All Messages area of the Home page.

Google Webmaster Tools Hack Alert

Google Safe Browsing

The Google Safe Browsing report for ardamis.com: http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=ardamis.com

Norton Safe Web

https://safeweb.norton.com/

The Norton Safe Web report for ardamis.com: https://safeweb.norton.com/report/show?url=ardamis.com

Tools for analyzing a site for vulnerabilities

Sucuri Site Check

http://sitecheck.sucuri.net/scanner/

The Sucuri report for ardamis.com: http://sitecheck.sucuri.net/scanner/?scan=www.ardamis.com.

Nearly a year ago, I wrote a post on how to detect and fix Word add-in problems with a macro and batch file, in a Windows XP and Office 2007 environment.

This was sufficiently effective, but it was also overly complicated, requiring four separate components:

  1. an autoexec Word 2007 macro that runs each time Word is opened
  2. a batch file that runs the registry merge file and writes an entry to a log file
  3. the registry merge file that contains the correct LoadBehavior settings for the add-ins
  4. a text file that acts as a log

This month, I decided to rewrite the macro to handle the registry changes and write to the log file. It was also a good opportunity to dig a bit deeper into VBA, and I also wanted to confirm that it would work in a more modern environment of Windows 7 and Office 2010 (that code is near the bottom of the post). The new system has only two components:

  1. an autoexec Word 2007 macro that runs each time Word is opened
  2. a text file that acts as a log

Background

First, a bit of background.

Many of the problems with Word 2007 are due to Word’s handling of add-ins. When something unexpected happens in Word, and Word attributes the problem to an add-in, Word will react by flagging it and prompting the user for a decision the next time Word opens. Depending on the severity of the problem and the user’s response, the add-in can be either ‘hard-disabled’ or ‘soft-disabled’.

Microsoft explains the differences between Hard Disabled vs Soft Disabled in a MSDN article at: http://msdn.microsoft.com/en-us/library/ms268871(VS.80).aspx.

I’ve explained a bit about the process by which Word disables add-ins at the end of this post, and I’ve written a shorter post about the basics behind the registry keys responsible for disabling add-ins.

Handling disabled add-ins programmatically

A Word macro can access the condition of an add-in via an Application.COMAddIns object, and it can read and write to the registry. This allows us to tell when an add-in has been disabled and re-enabled it.

My macro has some admittedly hackish parts that need to be cleaned up, there is the matter of unsetting variables to be addressed, and it could certainly be made more elegant, but it works. Note that a file named addinslog.txt must exist in the %TEMP% directory in order for the macro to write the log file. This is what the Word 2007 macro looks like, using the COM add-in installed with Adobe Acrobat 8 Standard as the required add-in…

Option Explicit

' Set up a function to search for a key and return true or false
Public Function KeyExists(key)
    Dim objShell
    On Error Resume Next
    Set objShell = CreateObject("WScript.Shell")
        objShell.RegRead (key)
    Set objShell = Nothing
    If Err = 0 Then KeyExists = True
End Function
    

Sub AutoExec()
'
' FixMissingAddins Macro
' Display a message box with any critical but not 'Connected' COM add-ins, then fix them programatically
'
' Oliver Baty
' June, 2010 - April, 2011
'
' Information on the Application.COMAddIns array
' http://msdn.microsoft.com/en-us/library/aa831759(v=office.10).aspx
'
' Running macros automatically
' http://support.microsoft.com/kb/286310
'
' Using Windows Scripting Shell (WshShell) to read from and write to the local registry
' http://technet.microsoft.com/en-us/library/ee156602.aspx

   
' Declare the WshShell variable (this is used to edit the registry)
    Dim WshShell
    
' Declare the fso and logFile variables (these are used to write to a txt file)
    Dim fso
    Dim logFile

' Create an instance of the WScript Shell object
    Set WshShell = CreateObject("WScript.Shell")
   
' Declare some other variables
   Dim MyAddin As COMAddIn
   Dim stringOfAddins As String
   Dim listOfDisconnectedAddins As String
   Dim requiredAddIn As Variant
   Dim msg As String

   
' Notes on deleting registry keys and values in VB
' http://www.vbforums.com/showthread.php?t=425483
' http://www.tek-tips.com/viewthread.cfm?qid=674375
' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

' Create a string containing the names of all 'Connected' COM add-ins named "stringOfAddins"
   For Each MyAddin In Application.COMAddIns
      If MyAddin.Connect = True Then
          stringOfAddins = stringOfAddins & MyAddin.ProgID & " - "
      End If
   Next
   
' Create an array to hold the names of the critical (required) add-ins named "requiredAddIns"
' Example: change to "Dim requiredAddIns(0 To 4)" if the macro is checking 5 total add-ins)
   Dim requiredAddIns(0 To 0) As String
   
' Add each required AddIn to the array
   requiredAddIns(0) = "PDFMaker.OfficeAddin"
'   requiredAddIns(1) = ""
'   requiredAddIns(2) = ""
'   requiredAddIns(3) = ""
'   requiredAddIns(4) = ""
   
' Cycle through the array of required add-ins, and see if they exist in the connected add-ins list
   For Each requiredAddIn In requiredAddIns
      If InStr(stringOfAddins, requiredAddIn) Then
        ' The required add-in is in the string of connected add-ins
         msg = msg
      Else
        ' The required add-in is not in the string of connected add-ins, so add the add-in name to a string named "listOfDisconnectedAddins"
         msg = msg & requiredAddIn & vbCrLf
         listOfDisconnectedAddins = requiredAddIn & " " & listOfDisconnectedAddins
         listOfDisconnectedAddins = Trim(listOfDisconnectedAddins)
      End If
   Next
   
' If the msg variable is not blank (it contains at least one add-in's name) handle it, otherwise, do nothing
   If msg = "" Then
        ' There are no critical, unconnected add-ins (yay!)
        ' The script can now exit
   Else
        ' There are critical add-ins that are not connected, so handle this
        MsgBox "The following critical Word Add-In(s) are disabled: " & vbCrLf & vbCrLf & msg & vbCrLf & vbCrLf & "To correct this problem, please save any documents you are working on, then close Word and reopen Word."

            ' I find it extremely hackish to check for each possible key and delete it if found... need to research how to delete the tree
            ' One potential obstacle to this method is that I've seen a DocumentRecovery subkey under Resiliency (only once, while editing this macro), that I haven't researched yet
            
            
            ' Note: Since the WSH Shell has no Enumeration functionality, you cannot
            '       use the WSH Shell object to delete an entire "tree" unless you
            '       know the exact name of every subkey.
            '       If you don't, use the WMI StdRegProv instead.
            ' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

            ' More info on WMI StdRegProv at:
            ' http://msdn.microsoft.com/en-us/library/aa393664(v=vs.85).aspx
            
        ' This is hackish, but it effectively deletes a registry key, if it exists
        If KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\DisabledItems\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\DisabledItems\"
        ElseIf KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems\"
        ElseIf KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\"
        End If
        
        ' To be completely thorough, we can also set the desired LoadBehavior for certain add-ins
        ' This can be done selectively, and only if the LoadBehavior was incorrect, but the quick and dirty way would be to just force the values
        
        WshShell.RegWrite "HKLM\SOFTWARE\Microsoft\Office\Word\Addins\PDFMaker.OfficeAddin\LoadBehavior", 3, "REG_DWORD"

        ' Release the WshShell object
        Set WshShell = Nothing
        
        ' Declare a few variables for the log file
        Dim user, machine, datetime, output
        
        Set WshShell = CreateObject("WScript.Shell")
        user = WshShell.ExpandEnvironmentStrings("%USERNAME%")
        machine = WshShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
        temp = WshShell.ExpandEnvironmentStrings("%TEMP%")
        ' Convert the slashes in Now to hyphens to prevent a fatal error
        datetime = Replace(Now, "/", "-")
        ' Create the string that will be written to the log file
        output = datetime + ", " + user + ", " + machine + ", " + listOfDisconnectedAddins

        ' Write the event to a log file
        logfile = temp + "\addinslog.txt"
        ' http://msdn.microsoft.com/en-us/library/2z9ffy99(v=vs.85).aspx
        ' http://www.devguru.com/technologies/vbscript/quickref/filesystemobject_opentextfile.html
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set logFile = fso.OpenTextFile(logfile, 8, True)
        logFile.WriteLine (output)
        logFile.Close
        Set logFile = Nothing
        Set fso = Nothing
        
        ' Should we clear the variables?
        
        ' Release the WshShell object
        Set WshShell = Nothing
   End If
   
   ' Ardamis.com - We're in your macros, fixing your COM add-ins.
End Sub

While working on this, I found that there were some gaps in my understanding of the sequence of events that occur when Word 2007 disables a COM add-in. Please comment if you find that any of this is inaccurate or incomplete.

What happens when Word launches

A critical key to the whole business of Word add-ins is HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency

When Word launches, it looks for data under the Resiliency key and a subkey: HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems

If the StartupItems subkey contains a REG_BINARY value that corresponds to an add-in, Word throws the familiar warning:

Microsoft Office Word
Word experienced a serious problem with the ‘[addin name]’ add-in. If you have seen this message multiple times, you should disable this add-in and check to see if an update is available. Do you want to disable this add-in?
[Yes] [No]

Choosing No at the prompt removes the Resiliency key and allows Word to continue to launch, leaving the LoadBehavior for that add-in unchanged.

Choosing No also writes an Error event to the Application Event Viewer log:

Event Type:	Error
Event Source:	Microsoft Office 12
Event Category:	None
Event ID:	2000
Date:		5/23/2011
Time:		3:15:29 PM
User:		N/A
Computer:	[WORKSTATION_NAME]
Description:
Accepted Safe Mode action : Microsoft Office Word.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

Choosing Yes at the prompt removes the StartupItems subkey and creates a new DisabledItems subkey. This DisabledItems subkey will contain a different REG_BINARY value, the data of which contains information about the disabled add-in.

Choosing Yes also writes an Error event to the Application Event Viewer log:

Event Type:	Error
Event Source:	Microsoft Office 12
Event Category:	None
Event ID:	2001
Date:		5/23/2011
Time:		3:12:36 PM
User:		N/A
Computer:	[WORKSTATION_NAME]
Description:
Rejected Safe Mode action : Microsoft Office Word.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.

At this point, the add-in is ‘hard-disabled’, but not ‘soft-disabled’.

Word then continues to launch, but without loading the add-in.

To see which add-ins have been hard-disabled, click on the Office Button | Word Options | Add-Ins, and scroll down to “Disabled Application Add-ins”.

To see which add-ins have been soft-disabled, click on the Office Button | Word Options | Add-Ins. Select “COM Add-Ins” in the Manage menu and click Go.

Word is somewhat tricky in this regard, as the add-in will not have a checkmark, but the LoadBehavior registry value will be unchanged. At any other time, the presence of a checkmark is an indication of the LoadBehavior, but when an add-in has been hard-disabled, the box will always be unchecked.

What users can do at this point

Going through Word Options and enabling the hard-disabled COM add-in will remove the Resiliency key. This may not make the add-in immediately available in Word, however.

To immediately load the add-in and gain its functionality, you can check the box. Otherwise, close and reopen Word, which will cause Word to launch with the add-in’s specified LoadBehavior.

In case you were curious about the keyboard shortcuts used to enable the first disabled add-in in the list of disabled add-ins (maybe you wanted to do something with SendKeys, for example), they are:
Alt+F, I, A, A, Tab, Tab, Tab, D, Enter, G, Space, Alt+E, C, Alt+F4.

In summary, deleting the Resiliency key after the “serious problem” prompt, then closing and reopening Word, returns Word to a normal operating state.

What I intend to accomplish with the macro is to re-enable the hard-disabled add-in, return any LoadBehavior values back to the desired settings, then prompt the user to save their work and close and reopen Word.

This should return Word to a working state.

Word 2010 on 64-bit Windows 7

As a bonus, here’s the same macro, with some minor adjustments to run in Word 2010 on Windows 7 64-bit, with Adobe Acrobat 9 Pro’s COM add-in acting as one of the required add-ins. The OneNote add-in is not enabled in Word by default, and the macro below does not attempt to enable it, but does consider it a required add-in. This is done to demonstrate the pop-up window. Note that a file named addinslog.txt must exist in the %TEMP% directory in order for the macro to write the log file.

Option Explicit

' Set up a function to search for a key and return true or false
Public Function KeyExists(key)
    Dim objShell
    On Error Resume Next
    Set objShell = CreateObject("WScript.Shell")
        objShell.RegRead (key)
    Set objShell = Nothing
    If Err = 0 Then KeyExists = True
End Function

Sub AutoExec()
'
' FixMissingAddins Macro
' Display a message box with any critical but not 'Connected' COM add-ins, then fix them programatically
'
' Oliver Baty
' June, 2010 - April, 2011
'
' Information on the Application.COMAddIns array
' http://msdn.microsoft.com/en-us/library/aa831759(v=office.10).aspx
'
' Running macros automatically
' http://support.microsoft.com/kb/286310
'
' Using Windows Scripting Shell (WshShell) to read from and write to the local registry
' http://technet.microsoft.com/en-us/library/ee156602.aspx

' Declare the WshShell variable (this is used to edit the registry)
    Dim WshShell

' Declare the fso and logFile variables (these are used to write to a txt file)
    Dim fso
    Dim logfile

' Create an instance of the WScript Shell object
    Set WshShell = CreateObject("WScript.Shell")

' Declare some other variables
   Dim MyAddin As COMAddIn
   Dim stringOfAddins As String
   Dim listOfDisconnectedAddins As String
   Dim requiredAddIn As Variant
   Dim msg As String

' Notes on deleting registry keys and values in VB
' http://www.vbforums.com/showthread.php?t=425483
' http://www.tek-tips.com/viewthread.cfm?qid=674375
' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

' Create a string containing the names of all 'Connected' COM add-ins named "stringOfAddins"
   For Each MyAddin In Application.COMAddIns
      If MyAddin.Connect = True Then
          stringOfAddins = stringOfAddins & MyAddin.ProgID & " - "
      End If
   Next

' Create an array to hold the names of the critical (required) add-ins named "requiredAddIns"
' Example: change to "Dim requiredAddIns(0 To 4)" if the macro is checking 5 total add-ins)
   Dim requiredAddIns(0 To 1) As String

' Add each required AddIn to the array
   requiredAddIns(0) = "PDFMaker.OfficeAddin"
   requiredAddIns(1) = "OneNote.WordAddinTakeNotesService"
'   requiredAddIns(2) = ""
'   requiredAddIns(3) = ""
'   requiredAddIns(4) = ""

' Cycle through the array of required add-ins, and see if they exist in the connected add-ins list
   For Each requiredAddIn In requiredAddIns
      If InStr(stringOfAddins, requiredAddIn) Then
        ' The required add-in is in the string of connected add-ins
         msg = msg
      Else
        ' The required add-in is not in the string of connected add-ins, so add the add-in name to a string named "listOfDisconnectedAddins"
         msg = msg & requiredAddIn & vbCrLf
         listOfDisconnectedAddins = requiredAddIn & " " & listOfDisconnectedAddins
         listOfDisconnectedAddins = Trim(listOfDisconnectedAddins)
      End If
   Next

' If the msg variable is not blank (it contains at least one add-in's name) handle it, otherwise, do nothing
   If msg = "" Then
        ' There are no critical, unconnected add-ins (yay!)
        ' The script can now exit
   Else
        ' There are critical add-ins that are not connected, so handle this
        MsgBox "The following critical Word Add-In(s) are disabled: " & vbCrLf & vbCrLf & msg & vbCrLf & vbCrLf & "To correct this problem, please save any documents you are working on, then close Word and reopen Word."

            ' I find it extremely hackish to check for each possible key and delete it if found... need to research how to delete the tree
            ' One potential obstacle to this method is that I've seen a DocumentRecovery subkey under Resiliency (only once, while editing this macro), that I haven't researched yet

            ' Note: Since the WSH Shell has no Enumeration functionality, you cannot
            '       use the WSH Shell object to delete an entire "tree" unless you
            '       know the exact name of every subkey.
            '       If you don't, use the WMI StdRegProv instead.
            ' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

            ' More info on WMI StdRegProv at:
            ' http://msdn.microsoft.com/en-us/library/aa393664(v=vs.85).aspx

        ' This is hackish, but it effectively deletes a registry key, if it exists
        If KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\DisabledItems\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\DisabledItems\"
        ElseIf KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\StartupItems\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\StartupItems\"
        ElseIf KeyExists("HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\") Then
            WshShell.RegDelete "HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\"
        End If

        ' To be completely thorough, we can also set the desired LoadBehavior for certain add-ins
        ' This can be done selectively, and only if the LoadBehavior was incorrect, but the quick and dirty way would be to just force the values

        WshShell.RegWrite "HKCU\Software\Microsoft\Office\Word\Addins\PDFMaker.OfficeAddin\LoadBehavior", 3, "REG_DWORD"

        ' Release the WshShell object
        Set WshShell = Nothing

        ' Declare a few variables for the log file
        Dim user, machine, temp, datetime, output

        Set WshShell = CreateObject("WScript.Shell")
        user = WshShell.ExpandEnvironmentStrings("%USERNAME%")
        machine = WshShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
        temp = WshShell.ExpandEnvironmentStrings("%TEMP%")
        ' Convert the slashes in Now to hyphens to prevent a fatal error
        datetime = Replace(Now, "/", "-")
        ' Create the string that will be written to the log file
        output = datetime + ", " + user + ", " + machine + ", " + listOfDisconnectedAddins

        ' Write the event to a log file
        logfile = temp + "\addinslog.txt"
        ' http://msdn.microsoft.com/en-us/library/2z9ffy99(v=vs.85).aspx
        ' http://www.devguru.com/technologies/vbscript/quickref/filesystemobject_opentextfile.html
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set logfile = fso.OpenTextFile(logfile, 8, True)
        logfile.WriteLine (output)
        logfile.Close
        Set logfile = Nothing
        Set fso = Nothing
        
        ' Should we clear the variables?

        ' Release the WshShell object
        Set WshShell = Nothing
   End If

   ' Ardamis.com - We're in your macros, fixing your COM add-ins.
End Sub