Wednesday, August 19, 2009

Scripted hiding of Windows Updates under Vista

Similar to my last post, here is another UI issue with Windows Vista. Fortunately, this time I have a solution to offer.

Starting with Windows Vista, the "Windows Update" functionality is provided through Control Panel rather than Internet Explorer. In both versions, there is the ability to hide updates. While hidden updates can easily be restored, this feature allows for ignoring unnecessary updates so that they don't continually count towards the number of available updates that are displayed. For me, this includes the 34 "Windows Vista Ultimate Language Packs" that are currently available. Unfortunately, multiple-selection is not enabled in the "View available updates" dialog. There are checkboxes, including a checkbox on the header that can be used to select/unselect all shown updates, but the checkbox selections are used for the "Install" button only. The other options available from the context menu - "View details", "Copy details", and "Hide update" - can currently be applied only one-at-a-time. This means that hiding just the 34 language packs would require no fewer than 68 clicks!

Originally, I assumed that these hidden updates and other preferences would be stored in the Windows registry, or possibly in a file on the file system. They are in a file, but a database-type file that isn't directly editable: %SystemRoot%\SoftwareDistribution\DataStore\DataStore.edb. Fortunately, there is a comprehensive Windows API for viewing and editing this information, and it is even easily available to scripting through the Windows Scripting Host and languages such as JScript. Microsoft's reference is located on MSDN: Windows Update Agent API.

Here is my resulting script that automatically hides all the "Windows Vista Ultimate Language Packs":

var updateSession = WScript.CreateObject("Microsoft.Update.Session");
var updateSearcher = updateSession.CreateUpdateSearcher();
updateSearcher.Online = false;

var searchResult = updateSearcher.Search("CategoryIDs Contains 'a901c1bd-989c-45c6-8da0-8dde8dbb69e0' And IsInstalled=0");

for(var i=0; i<searchResult.Updates.Count; i++){
  var update = searchResult.Updates.Item(i);
  WScript.echo("Hiding update: " + update.Title);
  update.IsHidden = true;
}

If you're not familiar with WSH, this can be simply executed as saving it as a *.js file, then double-clicking. A better option is to execute the file from a command-line with cscript. This will cause the output messages to be written to the standard output, instead of popping up a message box that must be acknowledged for each message. Also, since this script is making administrative changes to the system, it must be executed as an administrator.

"a901c1bd-989c-45c6-8da0-8dde8dbb69e0" is the ICategory.CategoryID for "Windows Vista Ultimate Language Packs". (This ICategory happens to have a .Type of "Product".) A similar script can easily be used to perform operations on other sets of updates by simply modifying the search query.

For the above example, the changes can be reverted by updating the script to executed update.IsHidden = false; (instead of true), then re-executing the script. Alternatively, here the Windows Vista GUI works a little better: By clicking on "Restore hidden updates" from the side panel in Windows Update, the "Restore" button operates on the checkbox selection - allowing all hidden updates to quickly be restored with 2 clicks if desired.

Finally, here is an extended example that doesn't change anything, but displays some of the many details that are available through this API. First, it displays all the updates grouped and nested by category. Note that some updates belong to more than one category. Finally, it displays all available updates in a "flat" view, without using categories.

var updateSession = WScript.CreateObject("Microsoft.Update.Session");
var updateSearcher = updateSession.CreateUpdateSearcher();
updateSearcher.Online = false;

var searchResult = updateSearcher.Search("IsInstalled=1 or IsInstalled=0");

var describeCategory = function(cat, depth){
  var pad = new Array(depth + 1).join("  ");
  WScript.echo(pad + depth + ": " + cat + ", " + cat.CategoryID + ", " + cat.Name + ", " + cat.Type);

  for(var i=0; i<cat.Children.Count; i++){
    var child = cat.Children.Item(i);
    describeCategory(child, depth + 1);
  }
  
  for(var i=0; i<cat.Updates.Count; i++){
    var update = cat.Updates.Item(i);
    WScript.echo(pad + "  " + describeUpdate(update, pad + "  "));
  }
};

var describeUpdate = function(update, pad){
  var u = update;
  var np = "\n" + (pad || "") + "  ";
  return u.Title
    + np + "Type: " + u.Type
    //+ np + "Description: " + u.Description
    + np + "IsInstalled: " + u.IsInstalled
    + np + "IsDownloaded: " + u.IsDownloaded
    + np + "IsHidden: " + u.IsHidden
    + np + "AutoSelectOnWebSites: " + u.AutoSelectOnWebSites;
};

for(var i=0; i<searchResult.RootCategories.Count; i++){
  var category = searchResult.RootCategories.Item(i);
  describeCategory(category, 1);
}

WScript.echo("\n");

for(var i=0; i<searchResult.Updates.Count; i++){
  var update = searchResult.Updates.Item(i);
  WScript.echo(describeUpdate(update));
}

According to the IUpdateSearcher.Search documentation, the default search criteria is "IsInstalled = 0 and IsHidden = 0". Unfortunately, there doesn't seem to be a simple option to short-circuit the evaluator to just return all available updates, e.g. "" or "1=1". So far now, "IsInstalled=1 or IsInstalled=0" results in all updates being displayed. The only other note concerning the above example is that the "description" line is commented out in the describeUpdate function only because it can be rather verbose, and make the overall output difficult to read. Feel free to uncomment it to view the details, as well as adding additional lines for all the other properties available from IUpdate.

Sunday, August 9, 2009

IME and other Vista Start Menu Annoyances

Recently I noticed some context menu items under Windows Vista that I didn't previously recall. I first noticed this after right-clicking on the text box on the start menu. However, these items appear on most text-input fields, including Notepad, any of the text fields in the default File Open/Save dialog boxes from almost any application, or even right-clicking on the text while renaming a file from Windows Explorer. The complete context menu displayed is shown below:

Right to left Reading order, Show Unicode control characters, Insert Unicode control characters, Open IME, Reconversion

These extra items - "Right to left Reading order", "Show Unicode control characters", "Insert Unicode control character", "Open IME", and "Reconversion" - practically double both the width and the height of the context menu. To make things even more annoying, there doesn't appear to be any way to disable even the display of these items.

IME stands for Input Method Editor, which should allow for the input of additional characters and symbols that may not be found on the keyboard. However, the "Open IME" option doesn't even appear to function - even though clicking it toggles the option between "Open IME" and "Close IME". I've also never seen the "Reconversion" item enabled, even when text is selected. I don't even know what it is for. While "IME" contains a short 1-sentence definition in the Windows Help, searching for "reconversion" doesn't give any results. (Regardless of the menu functionality, a user should still be able to input any character code through the use of "alt codes".)

At first, I thought I accidentally installed an additional language pack, which is method that would have added these items under previous operating systems such as Windows XP. Another thought was that these options were introduced with Windows Vista Service Pack 2, or that I had accidentally installed a SP2 version designed for multiple languages. However, I found that these options are immediately available in default installations of Vista, including both the English Ultimate and Business editions.

I was a bit surprised at how few results related to this menu and Windows Vista show up on Google. Most of those are several years old (around 2007), the most comprehensive and recent of which I found on this forum thread. None that I've found contain any solutions, and apparently these menu items still exist in Windows 7 as well.

Start Menu size / width

Another issue I just noticed is that Vista's new start menu is not at all resizable, and is sometimes too small / too narrow to display items with longer names. To make matters worse, there are no scroll bars or other apparent functionality for viewing the cut-off text. This is even the case with some of Microsoft's own programs and installed shortcuts. For example, the last 2 characters of "Microsoft Windows Performance Toolkit" do not fit within the fixed width of the "All Programs" menu.

Unfortunately, again, there doesn't appear to be any resolution or reasonable work-around to this issue, short of renaming the longer names to shorter ones. The two most relevant pages I found from searching the web are this forum thread, and this Microsoft Answers forum thread where a Microsoft support engineer's response is only to switch to the classic Start menu instead.

In summary...

"UI blunders"?