Category Archives: IT

Posts arising from problems or situations encountered while working in the IT field.

I’m in the middle of troubleshooting a printing problem that has arisen with our in-development Windows 7 image. We’re running 64-bit Windows 7 Enterprise with Office 2010 and using the HP Universal Print Driver for Windows PCL6 version 5.4.0 dated 1 Dec 2011 (the current version). The printer driver is installed on a Windows server using default settings and the printer connections on the workstations are created either as per-machine connections by running printui.exe /ga or as per-user connections by running the Find Printers wizard in an Office application. The printers themselves are HP 4250n and HP P4015 models with relatively up-to-date firmware.

The problem is that certain print jobs produce many pages of apparent gibberish instead of the intended file or email message. The gibberish pages begin like this:

"
 @PJL SET JOBATTR="JobAcct8=USERNAME"
                                     @PJL SET JOBATTR="JobAcct9="
                                                                 @PJL SET RET=OFF

I’ve done some research into the lines beginning @PJL, and my understanding is that PJL (Printer Job Language) commands are part of the standard job header output from the Universal Printer Driver, and that when everything is working normally, they are processed by the printer as instructions instead of printed as text.

For more reading about PJL commands, I can recommend the page at: http://www.sxlist.com/techref/language/pcl/lj1686.htm

Almost immediately, I was able to rule out the per-machine connections as being the cause, as the problem also occurred on per-user connections. The same files that printed problematically to the networked HP printers printed normally to locally-installed printers using non-UPD PCL 6 drivers. It seemed logical to pursue this as a driver-related problem.

What is PCL 6

It’s probably worth pausing here for a bit of explanation of PCL 6.

The Enhanced PCL XL or PCL6 driver that is included with the HP LaserJet printers provides enhanced WYSIWYG and enhanced performance with application support over the Standard (PCL5e) driver. PCL XL is a new page description language by HP that is part of PCL6 and is closer to GDI, which many applications use. Less translation takes place by the driver, which means increased WYSIWYG capabilities and better performance with applications that support escapes implemented by the Enhanced driver. The output from the Enhanced (PCL XL) driver may not be the same as the output from the Standard driver. If the output is not as expected, choose the Standard (PCL5e) driver instead.
What is the Enhanced PCL XL or PCL6 Driver?

The part that catches my eye is “better performance with applications that support escapes implemented by the Enhanced driver”. Are we encountering applications that do not support escapes?

Eliminating possible causes

Possible causes of the PJL commands being output as text include the driver not prefixing the PJL statements (at the beginning of each job) with a Universal Exit Language (UEL) escape sequence. (http://www.tek-tips.com/viewthread.cfm?qid=1618494)

To rule this out, one can use the “print to file” option in the print dialog box to produce a file that contains the instructions that would be sent to the printer.

Choose File | Print in your application, then check the “Print to file” box in the print dialog box. (In Office 2010, the Print Options button under the available printers menu displays the print dialog box.) Choose a name for the .prn file and save it somewhere, then open the resultant *.prn file in something that displays escape characters, such as Notepad++ (or even Notepad). The first character should be an escape character, and the first line of text will begin something like this:

{ESC}%-12345X

If the PJL initialization command looks correct, it’s possible that the printer is not properly configured to accept PJL commands. Older printers may not be PJL-aware, but I knew our printers to work fine with older 32-bit HP UPDs installed on our Windows XP machines. The ‘Personality’ attribute on HP printers can be checked by going to the printer’s web admin panel and browsing to Settings | Configure Device | System Setup. Setting the Personality to PS is probably going to cause problems, but either Auto or PCL should work. I confirmed that our printers were set to Auto, further ruling out the printers themselves as the cause of the problem.

I next looked at disabling the advanced features of the driver (a little skeptically, I’ll admit). This can be done by going into the printer’s properties and unchecking the “Enable advanced printing features” box on the Advanced tab. (http://h30499.www3.hp.com/t5/Print-Servers-Network-Storage/12345X-PJL-Printing-on-Dot-Matrix-Printers/td-p/1132391) I was curious about how this affected the job sent to the printer – would the entire series of JPL commands be removed?

To test, I unchecked the “Enable advanced printing features” and printed an email message to a *.prn file, then checked the box and printed the same email to a second *.prn file, then compared the two files. The only difference in the PJL commands was that “@PJL SET SEPARATORPAGE=OFF” was present with advanced printing features enabled, and absent with advanced printing features disabled.

I found the separator page line to be an interesting difference, as banner pages/separator pages had been suggested as a possible cause, but our drivers were not configured to print separator pages. (http://www.oasq.com/PJL-SET-JOBATTR-thread-252568-1-1.html)

So, that’s where the issue currently stands. I’m waiting to see if turning off advanced printing features has any effect. To be thorough, I need to test whether the UPD PS driver prints without error and whether the problem continues with a printer connected via TCP/IP and with a manually installed driver. I can also bring the printers up to the latest version of the firmware, although this would be a less satisfactory resolution, as we have a variety of printer models and not all of them have firmware updates available.

Update 17 Feb. 2012

The Application event log on the print server contains a number of errors, though we’re unsure of whether there is a direct correlation between the errors and attempts by Windows 7 users to print, or jobs in the spooler being processed, or any other activity.

Description:
Faulting application name: PrintIsolationHost.exe, version: 6.1.7600.16385, time stamp: 0x4a5bd3b1
Faulting module name: hpzuiwn7.dll, version: 0.3.7071.0, time stamp: 0x4a5bdfcb
Exception code: 0xc0000005
Fault offset: 0x00000000000d6971
Faulting process id: 0x900
Faulting application start time: 0x01ccea9860e17377
Faulting application path: C:\Windows\system32\PrintIsolationHost.exe
Faulting module path: C:\Windows\system32\spool\DRIVERS\x64\3\hpzuiwn7.dll
Report Id: 3eaa21e6-568c-11e1-b7a4-005056a50027

It certainly does look like the 64-bit HP driver is at fault here. More searching has turned up a number of reports of this error with HP’s UPD PCL6 driver, going back to 2010.

Because we have a small number of Windows 7 users, we’re removing the network printers from the Windows 7 machines temporarily, to see if the server stabilizes.

Update 21 Feb. 2012

We were able to take a closer look at the print server today. We searched the registry for hpzuiwn7.dll and noted the printers that had this DLL listed among the supporting files. Many, but not all, of the printers included this DLL. We also reviewed the printers in Print Management and made an odd discovery. There seemed to be two varieties of the model-specific PCL 6 driver in use: one is named “HP LaserJet 4250 PCL 6” and the other is “HP LaserJet 4250 PCL6“. The difference in the naming is that the later driver has a space between PCL 6. While most of the printers used the UPD, a handful were using one of the model-specific drivers. When we looked at the Additional Drivers, we found that one of them had only the 64-bit version available. I expect that only 32-bit workstations are printing to those printers, so I’m not sure how they even functioned, but it would seem that the next step would be to either add the matching 32-bit drivers for that model printer or change the assigned driver to UPD PCL 6. I suspect that we were not diligent enough about exactly matching the printer driver names (let alone the version numbers) when we were installing drivers on the server.

Update 1 Mar. 2012

After installing the missing 32-bit driver that complemented the stray 64-bit driver, all of the printing problems, including the error messages in the Application log on the server, have subsided.

In the VBScript example below, I’m using the Icacls.exe utility to assign modify permissions to the D:\Test folder for the user Oliver on the LOOMER domain (or local machine). The script includes as comments some good resources on the subject.

' http://support.microsoft.com/kb/919240
' http://technet.microsoft.com/en-us/magazine/2009.07.geekofalltrades.aspx
' http://timbolton.net/2010/06/23/icacls-changing-permissions-on-files-and-folders/

Dim strFolder, strUser, strDomain

strFolder = "D:\Test"
strUser = "Oliver"
strDomain = "LOOMER"

SetPermissions
	
Function SetPermissions()
	Dim intRunError, objShell, objFSO

	Set objShell = CreateObject("Wscript.Shell")
	Set objFSO = CreateObject("Scripting.FileSystemObject")
	If objFSO.FolderExists(strFolder) Then
		intRunError = objShell.Run("icacls " & strFolder & " /inheritance:r /grant:r " & strDomain &"\" & strUser & ":(OI)(CI)M ", 2, True)
		
		If intRunError <> 0 Then
			Wscript.Echo "Error assigning permissions for user " & strUser & " to folder " & strFolder
		End If
	Else
		Wscript.Echo "Error: folder " & strFolder & " does not exist"
	End If
End Function

This script is a work-in-progress. To be considered complete, I want it to be able to create multiple directories and assign them permissions. For extra credit, I want it to be able to accept as input a list of usernames from a text file and iterate through them, creating folders where necessary and assigning them permissions.

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

Because the page at http://www.nullsoft.com/free/netmon/ has been down every time I’ve tried to visit it lately, I’ve decided to reproduce it here, along with the download of the NetMon application. Below is the content of the page, with the link updated to the file hosted at ardamis.com.

introduction

This is a slightly useful network monitor graphing thing for Win32.
It just sits in its own window, pinging a host, and giving you a
graph of how long it takes each time.

Because all great (err) things should be free, this should be too.
Not only that, we’re pretty much giving away all rights to it, giving
you the source, and letting you do what you want with it (see the
license below).

features

  • Host configuration
  • Hops configuration
  • Refresh rate configuration
  • Graph scale configuration
  • Configurable text for window
  • Automatic start-on-system-start
  • Static window size (120×40)
  • Small memory footprint

license

Copyright (C) 1999-2000 Nullsoft, Inc.

This software is provided ‘as-is’, without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

Note that this license is borrowed from zlib.

download

Current version: 0.4 (8/1/00)
Download: netmon04.exe

version history

v0.4 (8/1/00)

  • first public release