Windows 7 Troubleshooting Guide

[This documentation is preliminary and is subject to change.]

Abstract

Windows Troubleshooting Platform allows script writers and developers to write Windows Troubleshooting Platform programs, which empower the home user and information worker to troubleshoot and resolve their PC problems. These programs are invoked by the user or an application when a problem is suspected and guide the user through the troubleshooting experience.

Windows Troubleshooting Platform brings a uniform way of troubleshooting PC problems to Windows 7, based on a standard three-step approach: detecting the problem, resolving the problem, and verifying the resolution.  Furthermore, Windows Troubleshooting Platform provides a standard user experience that is automatically generated.  This reduces development costs and ensures the user experience is the same regardless of who developed the troubleshooting program bringing an unprecedented uniformity to troubleshooting.

Contents

  • Microsoft Software License Terms
  • Introduction
  • Design Concepts
  • Technical Design
  • Developing Windows Troubleshooting Packs
  • Adding Multiple Root Causes
  • Adding an Interaction
  • Customizing the Interaction
  • Controlling Flow Between Root Causes
  • Preserving Context
  • Command-Line Administration
  • Packaging and Security
  • Localization
  • Deployment
  • Additional Resources
  • Sample Code Listings

MICROSOFT SOFTWARE LICENSE TERMS

MICROSOFT WINDOWS 7 TROUBLESHOOTING GUIDE

These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft

  • updates,
  • supplements,
  • Internet-based services, and
  • support services

for this software, unless other terms accompany those items. If so, those terms apply.
By using the software, you accept these terms. If you do not accept them, do not use the software.

If you comply with these license terms, you have the rights below.

INSTALLATION AND USE RIGHTS . You may install and use any number of copies of the software on your devices.

ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS

Distributable Code. The software contains code that you are permitted to distribute in programs you develop if you comply with the terms below.

Right to Use and Distribute. The code and text files listed below are “Distributable Code.”

  • Sample Code. You may modify, copy, and distribute the source and object code form of code marked as “sample.”
  • Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.

Distribution Requirements. For any Distributable Code you distribute, you must

  • add significant primary functionality to it in your programs;
  • require distributors and external end users to agree to terms that protect it at least as much as this agreement;
  • display your valid copyright notice on your programs; and
  • indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your programs.

Distribution Restrictions. You may not

  • alter any copyright, trademark or patent notice in the Distributable Code;
  • use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft;
  • distribute Distributable Code to run on a platform other than the Windows platform;
  • include Distributable Code in malicious, deceptive or unlawful programs; or
  • modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that 1) the code be disclosed or distributed in source code form; or 2) others have the right to modify it.

SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not

  • work around any technical limitations in the software;
  • reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;
  • make more copies of the software than specified in this agreement or allowed by applicable law, despite this limitation;
  • publish the software for others to copy;
  • rent, lease or lend the software; or
  • use the software for commercial software hosting services.

BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the software.

DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.

TRANSFER TO ANOTHER DEVICE. You may uninstall the software and install it on another device for your use. You may not do so to share this license between devices.

TRANSFER TO A THIRD PARTY. The first user of the software may transfer it and this agreement directly to a third party. Before the transfer, that party must agree that this agreement applies to the transfer and use of the software. The first user must uninstall the software before transferring it separately from the device. The first user may not retain any copies.

EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see www.microsoft.com/exporting.

SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it.

ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.

APPLICABLE LAW.

  • United States. If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.
  • Outside the United States. If you acquired the software in any other country, the laws of that country apply.

LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.

DISCLAIMER OF WARRANTY. The software is licensed “as-is.” You bear the risk of using it. Microsoft gives no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this agreement cannot change. To the extent permitted under your local laws, Microsoft excludes the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any other damages, including consequential, lost profits, special, indirect or incidental damages.

This limitation applies to

  • anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and
  • claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.

It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.

Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.

Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français.

EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues.

LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.

Cette limitation concerne :

  • tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et
  • les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur.

Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard.

EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas.

WINDOWS TROUBLESHOOTING PLATFORM

Introduction

When people use a computer, they are looking to enhance their productivity, connect with friends and family, and accomplish other tasks. If the computer fails the user in any way, it leads to frustration, time loss, and possibly not being able to accomplish the task at hand.

Help from documentation, friends, communities, and support professionals have all played a part in allowing people to get past the problems they face with a computer.  Not enough investment has gone into making it easy to automate fixing computer problems.  Windows Troubleshooting Platform was developed to address this specific area and to make it easy to automate fixes to computer problems in an easy, consistent, secure, and user-friendly way.

A good troubleshooting experience will increase customer satisfaction and decrease support calls, because it allows users to fix problems directly.

Windows Troubleshooting Platform can be used by software developers, OEMs, or Information Technology (IT) administrators to write troubleshooting programs that detect and resolve software problems and detect hardware problems.

This guide is organized into two sections:

  1. The first section explains the conceptual design behind the platform and addresses the technical details and how the conceptual design is implemented.
  2. The second section guides the reader through creating a troubleshooting pack.
Design Concepts

Windows Troubleshooting Platform is based on the following five concepts:

  • User-initiated or application-initiated
  • Configuration comparison
  • Easy to author
  • Secure
  • Discoverable

User-initiated or application-initiated

One of the core concepts of Windows Troubleshooting Platform is that it is user-initiated or application-initiated troubleshooting.  While much has been said and done about auto-fixing, self-healing, and a computer just working, these approaches fail to take into consideration the user intent.  For example, if the sound is turned off, it is not clear if it is a malfunction or the user has intentionally turned the sound off.  Windows Troubleshooting Platform takes the user or application intent into consideration by allowing the user or application to initiate troubleshooting.

Similarly, an application can initiate troubleshooting when it cannot accomplish a task.  For example, an application might try to access a remote share or Web site and fail to access it.  It can at that point initiate troubleshooting to determine whether the network is running instead of generating an error message and leaving it up to the user to do manual troubleshooting.

Configuration comparison

Traditionally, troubleshooting has targeted specific problems.  For example, if the disk is fragmented, then run defragmentation. If the disk is full, delete temporary files.  Windows Troubleshooting Platform covers these scenarios, but it also allows and recommends a holistic approach to troubleshooting.  For example, a troubleshooting program that detects and fixes sound problems should check for all conditions that could cause those problems.  For example, it should check if the volume is set to zero, if the sound has been muted, if a sound driver is present, and if the right hardware is present, etc.

To generalize this concept, Windows Troubleshooting Platform is able to compare a well-known configuration with the current conditions on the computer.  Based on the results of this comparison, a set of actions can be taken if conflicts are found.  For example, if the sound is muted, troubleshooting can un-mute the sound.

Easy to author

Troubleshooting has not become an integrated part of product development such as security or performance.  In many cases, people who deploy the product develop ways to troubleshoot and fix the problems.  Windows Troubleshooting Platform meets the needs of both product-level developers as well as IT administrators who deploy the product by making authoring of troubleshooting simple.  This is done by using scripting to detect and resolve problems and providing a complete user experience out of the box.

  • Script based. To allow administrators and developers to quickly write and test troubleshooting programs, all problem detection and resolution logic can be written in PowerShell.This allows script developers to try the troubleshooting logic through a shell, formulate a script, and after the script successfully detects and fixes the problem to harden and generalize the script by adding error detection and edge cases. In addition, developers do not have to worry about the user experience, which is automatically provided by Windows Troubleshooting Platform as explained in the next section.
  • Declarative graphical user interface. To provide a consistent user experience, and to free the script writer from having to worry about designing and coding the graphical user interface, Windows Troubleshooting Platform provides a rich user experience out of the box. An author simply defines the troubleshooting logic structure and the desired user input requirement, and Windows Troubleshooting Platform will automatically handle all graphical rendering. This is done through providing standard wizard pages so users get the same experience regardless of which troubleshooting is performed. The declarative nature of defining the logic structure and input requirement is the key to freeing authors from having to provide any UI; it separates the presentation from the logic.

Secure

Windows Troubleshooting Platform helps to ensure a secure troubleshooting experience.  Windows Troubleshooting Platform will not run any troubleshooting program unless it is signed by a certificate that chains up to a trusted root authority on a computer.  It will also show the user the publisher of the troubleshooting program.  The publisher is derived from the certificate.

Windows Troubleshooting Platform security is Group Policy enabled so enterprises have increased control and flexibility for the IT administrator.

Discoverable

With a compiled program in the form of an executable file, it is hard to tell what the program will do.  Generally, the IT administrator has to read the documentation, look for the help switch, or run the program and to try it out and hope that the documentation or help is up to date.

Given that IT administrators need to know what problems a troubleshooting program will look for and fix what responses are required from the user, what platform it will run on, if it needs to run in an elevated security mode etc., Windows Troubleshooting Platform makes the metadata associated with a troubleshooting program easily discoverable.

In summary, Windows Troubleshooting Platform approaches troubleshooting from a user perspective as compared to an error or event driven condition.  It leaves the initiation of the troubleshooting to the user or the application. The way the problems are fixed is through examining the current configuration against a well-known working configuration, and making adjustments on discrepancies.

It is easy to author troubleshooting because the logic can be written in PowerShell scripts and no coding is required for the UI.

An administrator can discover what a troubleshooting program does before running it.  The administrator or user can feel safe running Windows Troubleshooting Platform because troubleshooting programs are secure, signed by certificates, and will run only when the certificate chains up to a trusted root authority on a computer.

Technical Design

The Windows Troubleshooting Platform technical design embeds the five key concepts discussed in the previous section.  The following diagram illustrates the components that make up Windows Troubleshooting Platform.

WTPDiagram.jpg

As the diagram shows, Windows Troubleshooting Platform consists of three major components:

  1. The Windows Troubleshooting Framework, represented by the gray block.
  2. A user interface application, represented by the green blocks.
  3. A Windows Troubleshooting Pack, represented by the blue block.A troubleshooting package is a combination for XML declarations and PowerShell scripts that implement detection, resolution, and verification logic.

These three components are discussed in detail in the next sections.

The diagram also shows the process boundaries, where PowerShell is run in a separate process than Windows Troubleshooting Platform.  This is done for reliability to ensure that the Windows Troubleshooting Platform isolates script run-time effects from the command and GUI interface.

Windows Troubleshooting Pack

A troubleshooting package consists of metadata including identification, the problem the package addresses, a security signature, and logic for detecting and resolving problems in the form of scripts and resources for localization. 

For a general problem, it is likely that the troubleshooting package will contain a long list of conditions, referred to as root causes that can go wrong.  For a problem with sound, this list could include hardware, drivers, services, volume level, mute condition, etc.

A troubleshooting package should contain a full list of root causes that it addresses.  In addition, it should contain metadata that an IT administrator may want to discover about a troubleshooting pack, such as security level required, platform or OS, etc, as well as metadata needed for control flow. The discussion of metadata will be covered throughout this document starting with building a troubleshooting package in later section.

A troubleshooting package also contains PowerShell scripts that detect each of the root causes described, PowerShell scripts that fix the root causes and optionally PowerShell scripts that verify that the root cause has been fixed. PowerShell scripting and details particular to troubleshooting scripts and cmdlets are covered in authoring sections starting at section Developing Windows Troubleshooting packs. Note that no UI coding is required, making it easy to author a troubleshooting pack.

Localization of troubleshooting packs is fully supported using standard Multiple-Language UI (MUI) resource files.  For each supported language, a corresponding DLL that contains localized resources must be created. Through this mechanism, Windows OS will locate and load the appropriate DLL during runtime based on locale setting. This gives the package author flexibility to release additional language support after the troubleshooting package has been shipped by simply making available the new MUI DLLs.

To help ensure security, the troubleshooting package must be signed.  In order for the package to run, the certificate for the package must chain up to a trusted root authority on the computer running the package.

Below is a diagram that illustrates these components that make up the troubleshooting pack.

WTPSteps.jpg

Windows Troubleshooting Platform

As the diagram in the design section shows, Windows Troubleshooting Platform (WTP) consists of a Windows troubleshooting run-time engine, results and reports, four troubleshooting cmdlets, and a hosted Windows PowerShell runtime.

When a user or an application invokes a troubleshooting package to run, the troubleshooting run-time engine reads the metadata section, checks that the package is allowed to run on the computer and, if so, it proceeds to display some of the metadata to the user, such as the name of the package and the publisher.  If the security check fails, the package run is terminated immediately.

The run-time engine then gets the detection script from the troubleshooting package and runs it in the hosted PowerShell runtime.  If the script needs to get information from the user, it does that by calling troubleshooting cmdlets.

Again, in order to simplify the authoring experience, troubleshooting provides a PowerShell experience for all troubleshooting specific semantics.  Troubleshooting cmdlets provide a PowerShell way for the script writer to communicate to the User Interface through the run-time engine or to communicate to the run-time engine itself.

Graphical and command-line interface

Troubleshooting packs can be invoked through the graphical or the command-line user interfaces.  The graphical user interface was developed for the end user to troubleshoot his or her own problems. The command-line user interface was developed for the IT administrators who may have to troubleshoot computers for other users.

The graphical user interface was developed to allow an easy and simple way to run a troubleshooting package with the minimum amount of clicks.  In many cases where no input is required from the user, the package can be run with just one click. There are times when a user may want to see what the package is about to do before running it.  To support the principal of discoverability, there is an advanced mode that lists the root causes that were detected, and the user has the ability to select which resolutions to apply.

The command-line user interface is primarily for IT administrator who needs more control of what is run and how it is run. Supporting the discoverability principle, the IT administrator can discover all the root causes and many of the properties of a troubleshooting pack.  It is helpful for the administrator to be able to see what changes the package will make based on the root causes it is looking for.  In addition, the administrator can see what types of input the package requires and whether there are any user interactions outside the declarative Windows Troubleshooting user interface. Likewise, there are times when an administrator may want to run a package on a remote computer. Because the command-line interface is implemented as a PowerShell cmdlet, PowerShell remoting can execute this cmdlet and enable troubleshooting packs to run on remote computers. If the troubleshooting package runs on a remote computer, the IT administrator does not want it to require input from the user.  WTP supports running packs both silently and by providing an answer file.  The answer file can be easily created by querying the package in answer file creation mode.  The package asks the user for input to each of the questions and creates an answer file.  This answer file can then be supplied as input when running the pack.

In summary, Windows Troubleshooting Platform is designed with reliability, security, and ease-of-use. From an authoring perspective, the declarative model affords clear definition and ease of development. Through the use of PowerShell scripts, logic to detect and resolve root causes can be implemented. The run-time model provides reliability through process isolation, and gives flexibility and capability to users initiating troubleshooting from graphical and command-line interfaces. And security is enhanced because every troubleshooting package must be signed with a trusted certificate.

Developing Windows Troubleshooting Packs

This section introduces the mechanics in a troubleshooting pack.  It starts with the workings of the core concepts in a troubleshooting package and then expands on those by progressively introducing more concepts that add functionality to the basic scenario.  At each step, the reader is able to run a fully working pack.

While the accompanying troubleshooting package samples are limited to one or two implementations of the concept, the explanations cover most implementations to get the user familiar with the full functionality of Windows Troubleshooting Platform.

Building a troubleshooting package

As illustrated in the design concepts section, one of the key design concepts for Windows Troubleshooting is easy to author. This section will show the elements needed to build a troubleshooting packs covering three concepts: troubleshooting pack, root cause, and elevation of privileges.

A troubleshooting package is described through metadata. Providing the identification metadata is the first step to defining a troubleshooting pack. The critical elements in this metadata are the package identifier, the display name, description, and a list of root causes. Root causes contain three troubleshooting steps: detection, resolution, and verification.  Each of these steps has metadata and can have a PowerShell script associated with it.

Other related information such as localization resources and the security signature are part of the metadata, too. However, for now, the discussion will be limited to what is required to develop a simple troubleshooting pack. In this section, a sample troubleshooting package will be built to illustrate the crafting and usage of these elements. The focus of this section is to start with a single root cause, a single resolver, and the steps needed for the troubleshooting package to materialize. Later sections will gradually introduce more root causes and other troubleshooting constructs.

Starting with the metadata, one should first understand the following properties:

  • Unique troubleshooting package identifier – Every troubleshooting package should be uniquely identified to distinguish itself from other packages.
  • The package name and description – The name and description of the troubleshooting package as it is shown to the user who initiated troubleshooting.
  • The package version – The author should specify a version number for a troubleshooting package for better versioning control.
  • The root causes, each capturing the detection, resolution, and verification – Aside from the various definition elements, there are or could have associated PowerShell scripts that package author implement which contains logic to troubleshoot a set of problems.

Here, a troubleshooting package will be built to diagnose Windows Aero. The ‘Glass’ transparency and theme-based selection allows users to personalize the appearance of the desktop. In this example, a user’s personalized desktop does not appear correctly. The troubleshooting program will help users resolve the issue of not being able to see the Aero effects on their computer.

For the scoping purpose of this section, a single root cause will serve as an example to build the detection and resolution logics. The Desktop Window Manager Service, or DWM service, is a critical service that must be running for Aero to function properly. This is a perfect illustration to show that if this service is not running properly and hence the detection, the resolution is to restart this service to restore Aero effects. For simplicity too, this sample troubleshooting package will be developed by assuming the only language supported is English. Therefore, the package should be marked as not-localized through the following metadata element. Localization is covered in detail in sections Localized resources and Localization.

<dcmPS:AdvDiagnosticPackage Localized="false" />

Planning the troubleshooting pack

With the Aero diagnostic in mind, the metadata definition of a name, description, identifier, and the version should be determined for the troubleshooting pack. The name and description describe what the troubleshooting package does. They can be viewed by the end user in the graphical user interface and can be discovered by the administrator in the command-line user interface.

The identifier and the version are used to identify the troubleshooting package for the author and WTP. The identifier needs to be unique across troubleshooting packs. The version field identifies the current version of the troubleshooting package and can be used for future updates. Here are the definition properties for the Aero diagnostic:

  • ID: AeroDiagnostic
  • Version: 1.0
  • Name: Aero
  • Description: Display Aero effects such as transparency.

Next, the Aero troubleshooting package will have one root cause, so the definition of this root cause also needs to be stated. The single root cause here is the DWM service. Like the troubleshooting pack, an identifier is also needed for a root cause to primarily distinguish root causes defined within a pack. Although not applicable for a single root cause, this is nevertheless a good practice. As with the viewable elements for a troubleshooting pack, the root cause name and description will need to be defined. The author should keep in mind that any text that could be displayed to the user should be carefully considered. Poorly worded text not only leads to confusion but brings about a poor experience for the user. Here are the definition properties for the DWM service root cause:

  • ID: RC_DwmService- The RC prefix here is a good practice to denote identifier for a root cause. The ‘DwmService’ is an abbreviation for Desktop Window Manager Service.
  • Name: Desktop Window Manager Session Manager service isn't running
  • Description: The Desktop Window Manager Session Manager service is used to display Aero desktop effects such as transparency.The service or process is currently stopped.

Following this, the detection, resolution, and verification definitions will also need to be thought through. There are two parts to this step: the definition in the metadata and the actual PowerShell scripts that implements the logic. Both of these are discussed here.

Two PowerShell scripts will be needed for detection and resolution for this root cause. A third PowerShell script that verifies the resolution is optional. The detection script checks if the condition specified in the root cause is true. In this case, the detection script checks if the DWM service (that is, uxsms service) is running. The resolution script carries out changes to configurations and fixes the condition that was detected by the detection script. In this case, the resolution will simply restart the DWM service. The verification script checks to see if the resolution has done its job in fixing the condition that the detection script has detected. It will check if the DWM service is indeed running after the resolution. For troubleshooting packs in general, the verification script is optional because not all resolutions can be verified automatically by scripts. If the resolution can be verified by scripts, in most cases, the detection script that was used to detect the condition in the first place can be reused to check if it’s been fixed. For this troubleshooting pack, the detection script can be reused to see if the DWM service is running.

Now, moving on to privilege elevation discussion, the Windows troubleshooting graphical and command-line user interfaces optimize the user experience for the cases when the scripts contained in the root causes of a troubleshooting package require system privileges (elevation). Instead of prompting users for every script that needs elevation, the user prompts will be grouped and reduced to the minimum needed. For this to work, each of the detection, resolution, and verification scripts needs to declare whether it will need elevation in the troubleshooting pack. Hence a decision needs to be made about whether they will require elevation up front.

In the sample Aero troubleshooting pack, the detection script just needs to query the status of a service and therefore does not require elevation. The resolution script needs to restart a service, so it will require elevation. For this troubleshooting pack, the WTP wizard interface will automatically ask for elevation for the entire experience. Hence this troubleshooting package can be run only by an administrator. Depending on the sensitivity of the user’s user account control setting in Windows, it may or may not prompt for permissions.

Here is a summary of elevation for the three scripts:

  • Detection: Checks if the desktop window manager service is running.
    • Requires elevation: No.
  • Resolution: Restart the desktop window manager service.
    • Requires elevation: Yes.
  • Verification: Same as detection script.

At this point, the metadata, the root cause, and the associated scripts are all determined for the Aero troubleshooting package and the planning phase is complete. One can now proceed to implement the Aero troubleshooting pack. 

Implementing the troubleshooting pack

The following PowerShell detection script will check to see if the DWM Service is running.

$RootCauseId = "RC_DwmService"
$service = get-service uxsms
$RootCauseDetected = ($service.status -ne "Running")
update-diagrootcause -id $RootCauseId -detected $RootCauseDetected

After retrieving the UxSms service and saving it to a variable, the running status of this service can be interrogated, saved to a variable, and passed onto the Update-DiagRootCause cmdlet. Update-DiagRootCause is a WTP PowerShell cmdlet that is used to inform whether the root cause as identified by the –ID switch is indeed found to be the source of the problem. This is also known as a root cause being detected. The following resolution script restarts the UxSms service.

start-service uxsms

Up to this point, the metadata definition has been discussed at a high level. There are more definitions that need to be stated for a troubleshooting package to adhere to the WTP framework. These metadata are all specified in a XML file called the troubleshooting package manifest. Every troubleshooting package requires a manifest; it defines the troubleshooting package and informs WTP how to orchestrate the execution. This topic will be covered throughout this document. Here though, the manifest that captures the definition described so far is listed below. Again, following the practice of prefixing root causes, the resolver and corresponding script file names are also prefixed for context clarity. Refer to the WTP Package Schema for full definition.

<?xml version="1.0" encoding="utf-8"?>
<dcmPS:AdvDiagnosticPackage SchemaVersion="1.0" Localized="false"
        xmlns:dcmPS=https://www.microsoft.com/schemas/dcm/package/2007
        xmlns:dcmRS="https://www.microsoft.com/schemas/dcm/resource/2007">
    <DiagnosticIdentification>
        <ID>AeroDiagnostic</ID>
        <Version>1.0</Version>
    </DiagnosticIdentification>
    <DisplayInformation>
        <Parameters/>
        <Name>Aero</Name>
        <Description>Display Aero effects such as transparency.</Description>
    </DisplayInformation>
    <PrivacyLink>https://go.microsoft.com/fwlink/?LinkId=104288</PrivacyLink>
    <PowerShellVersion>2.0</PowerShellVersion>
    <SupportedOSVersion clientSupported="true" serverSupported="true">6.1</SupportedOSVersion>
    <Rootcauses>
        <Rootcause>
            <ID>RC_DwmService</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>Desktop Window Manager Session Manager service isn't running</Name>
                <Description>The Desktop Window Manager Session Manager service is used to display Aero desktop effects such as transparency.  The service or process is currently stopped.
                </Description>
            </DisplayInformation>
            <Troubleshooter>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>false</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>TS_DwmService.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Troubleshooter>
            <Resolvers>
                <Resolver>
                    <ID>RS_DwmService</ID>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>
                        Restart the Desktop Window Manager Session Manager service
                        </Name>
                        <Description>Restarting the Desktop Window Manager Session Manager service will enable Aero desktop effects such as transparency.
                        </Description>
                    </DisplayInformation>
                    <RequiresConsent>false</RequiresConsent>
                    <Script>
                        <Parameters/>
                        <ProcessArchitecture>Any</ProcessArchitecture>
                        <RequiresElevation>true</RequiresElevation>
                        <RequiresInteractivity>false</RequiresInteractivity>
                        <FileName>RS_DwmService.ps1</FileName>
                        <ExtensionPoint/>
                    </Script>
                    <ExtensionPoint/>
                </Resolver>
            </Resolvers>
            <Verifier/>
            <ContextParameters/>
            <ExtensionPoint/>
        </Rootcause>
    </Rootcauses>
    <Interactions>
        <SingleResponseInteractions/>
        <MultipleResponseInteractions/>
        <TextInteractions/>
        <PauseInteractions/>
        <LaunchUIInteractions/>
    </Interactions>
    <ExtensionPoint></ExtensionPoint>
</dcmPS:AdvDiagnosticPackage>

After the troubleshooting package manifest is created and the script files are implemented, the package is almost ready for execution. WTP requires every troubleshooting package to contain a security catalog that is signed by a certificate that is trusted on the computer the package will execute on. These steps are discussed in detail in section Packaging and Security. For now, simply create a Catalog Definition File as shown below and use Makecat.exe to create the security catalog. Then, using Signtool.exe, sign the security catalog with a certificate that chains up to a trusted root authority.

[CatalogHeader]
Name=DiagPackage.cat
PublicVersion=0x0000001
EncodingType=0x00010001
CATATTR1=0x10010001:OSAttr:2:6.1
[CatalogFiles]
<hash>AeroDiagnostic.diagpkg=AeroDiagnostic.diagpkg
<hash>AeroDiagnostic.diagpkgATTR1=0x10010001:Filename:AeroDiagnostic.diagpkg
<hash>RS_DwmService.ps1=RS_DwmService.ps1
<hash>RS_DwmService.ps1ATTR1=0x10010001:Filename:RS_DwmService.ps1
<hash>TS_DwmService.ps1=TS_DwmService.ps1
<hash>TS_DwmService.ps1ATTR1=0x10010001:Filename:TS_DwmService.ps1

Note that we have not created any UI.  This is intentional.  To make the development of the troubleshooting package easy and the user experience consistent, all UI is automatically generated by the platform.  Specific interactions are discussed later and can also be declared through the manifest. In essence, WTP interprets the manifest and automatically generate the UI.

Section Running the troubleshooting pack shows the effect when running the Aero diagnostic package from both graphical and command-line interfaces. To run the graphical interface, use Cabarc.exe from Windows SDK to bundle up all package files and set the file extension to .diagcab. (for example, AeroDiagnostic.diagcab). This particular extension is file associated with the WTP graphical interface application. An example usage is shown below.

Cabarc N c:\AeroDiagnostic.diagcab c:\AeroDiagnostic\*.*

Running the troubleshooting pack

In the earlier design section, “Graphical and command-line user interface”, troubleshooting packs can be invoked through both a graphical and a command-line user interface. In this section, the Aero troubleshooting package will be exercised in both the graphical and the command-line interfaces, thus illustrating the user experience. The user interface shown in this section is a standard part of WTP, and the sample crafted in the previous section can run as-is; no additional user interface development is needed. This graphical application is also known as the Microsoft Diagnostic Tool or MSDT.

To run the package, launch the AeroDiagnostic.diagcab file.

Screen1.jpg

The following table describes the elements in this first screen.

Text/Field

Description

Manifest XML

Aero

Troubleshooting package window title.

<dcmPS:AdvDiagnosticPackage>

<DisplayInformation>

<Name>Aero</Name>

</DisplayInformation>

</dcmPS:AdvDiagnosticPackage>

Troubleshoot and help prevent computer problems

Standard title for the first page of the WTP wizard user interface.

   

N/A

Aero

Troubleshooting package title.

<dcmPS:AdvDiagnosticPackage>

<DisplayInformation>

<Name>Aero</Name>

</DisplayInformation>

</dcmPS:AdvDiagnosticPackage>

Display Aero effect such as transparency.

Troubleshooting package description.

<dcmPS:AdvDiagnosticPackage>

<DisplayInformation>

<Description>Display Aero effects such as transparency.</Description>

</DisplayInformation>

</dcmPS:AdvDiagnosticPackage>

Advanced

A link to the “advanced option,” which allows the user to choose not to automatically run the resolution.

N/A

Publisher: TestCertforWindowsTroubleShooting

This is the publisher of the troubleshooting package derived from the certificate used to sign the troubleshooting pack. The troubleshooting package must be signed by a certificate that chains up to a trusted root authority on the computer that the package is running on. WTP wizard interface will display the publisher of the troubleshooting pack.

N/A

Read the privacy statement online

A link to the optional privacy statement for the troubleshooting pack.

N/A

Express problem resolution by default

To enhance the fix-and-go experience, the user simply launches the desired troubleshooting andclicks on the Next button. MSDT will then go through the list of root causes and execute the detection scripts. When the detection script of a root cause detects a problem, this root cause is flagged as “detected”. After having executed the detection scripts for all root causes, MSDT will then enumerate through the “detected” root causes and execute the corresponding resolution scripts. When the resolution script  for a root cause finishes successfully, the verification script will be executed to make sure the root cause is indeed resolved. Hence if no user input is needed, the whole troubleshooting package will be run with just one click (the click of the Next button on the first wizard page).

For the Aero troubleshooting pack, when the user clicks on the Next button, the troubleshooting package executes the detection script for the “RC_DwmService” root cause. If it happens to be the issue, it will run the resolution script to restart the desktop window manager session service and then run the verification script to verify the resolution. After that, the troubleshooting package execution is completed and the wizard page shown below will be displayed.

Screen2.jpg

The following table describes the elements in the completed screen.

Text/Field

Description

Manifest XML

Aero

Troubleshooting package window title.

<dcmPS:AdvDiagnosticPackage>

<DisplayInformation>

<Name>Aero</Name>

</DisplayInformation>

</dcmPS:AdvDiagnosticPackage>

Troubleshooting has completed

Standard last page title for when troubleshooting was successful.

N/A

The troubleshooter made some changes to your system…

Message indicating at least one resolution was applied.

N/A

Problems found

Shows a list of all root causes that were found and the status of each root cause.

<Rootcause>

<ID>RC_DwmService</ID>

<DisplayInformation>

<Name>Desktop Window Manager Session Manager service isn't running</Name>

</DisplayInformation>

</Rootcause>

Close the troubleshooter

Closes the WTP wizard troubleshooter.

N/A

Explore additional options

Link that leads the user to more advanced troubleshooting options.

N/A

View detailed information

Shows the report of running this troubleshooting pack.

N/A

Note that this screen shot was captured on a computer that has low sensitive elevation setting, which is why there is no elevation prompt for the user. As discussed in earlier sections, the resolution for the desktop window manager service root cause will need to start a service, hence requires elevation, hence will prompt the user for it on computers with high sensitivity for elevation set.

To the end user, after one click on the Next button, the troubleshooting package completes and the problem she has with Aero due to DWM service not running is resolved.

There’s actually more that goes on underneath to ensure thoroughness with troubleshooting. Upon the first pass of detecting root causes and applying resolutions, MSDT will actually replay the sequence again but this time only on the root causes that were previously detected. The replay stops when no new detections were found. To the end user, this replay mechanism is not apparent but MSDT performs this to ensure thoroughness and provides the user a better experience with troubleshooting.

Advanced option allows discoverability

For a user who wishes to discover more advanced control with troubleshooting, the initial screen shows an Advance link. Selecting this link brings the user a check box that, when cleared, provides the user the control to choose which resolutions to apply. The screen is shown below.

Screen3.jpg

The elements in the screen are largely the same as the default starting screen, with the exception of the “Apply repairs automatically” checkbox.

Text/Field

Description

Manifest XML

Apply repairs automatically

If  this check box is cleared, the windows troubleshooting platform will not automatically apply the resolutions to any root causes it detects

N/A

If the user clicks the Next button and root causes are found to be problematic, the user will see the following wizard screen that lists the root causes detected by WTP.

Screen4.jpg

The following table describes the elements in the above screen.

Text/Field

Description

Manifest XML

Aero

Troubleshooting package window title.

<dcmPS:AdvDiagnosticPackage>

<DisplayInformation>

<Name>Aero</Name>

</DisplayInformation>

</dcmPS:AdvDiagnosticPackage>

Select the repairs you want to apply

WTP wizard page title asking the user to choose resolutions for root causes found.

N/A

Desktop Window Manager … isn’t running

Root cause title.

<Rootcause>

<ID>RC_DwmService</ID>

<DisplayInformation>

<Name>Desktop Window Manager Session Manager service isn't running</Name>

</DisplayInformation>

</Rootcause>

The Desktop Window Manager … is used to display Aero desktop effects …

Root cause description.

<Rootcause>

<ID>RC_DwmService</ID>

<DisplayInformation>

<Description>The Desktop Window Manager Session Manager service is used to display Aero desktop effects such as transparency.  The service or process is currently stopped.

</Description>

</DisplayInformation>

</Rootcause>

Restart the Desktop Windows Manager …

Resolution title.

<Resolver>

<ID>RS_DwmService</ID>

<DisplayInformation>

<Name>Restart the Desktop Window Manager Session Manager service</Name>

</DisplayInformation>

</Resolver>

View detailed information

Shows the report of running this troubleshooting pack.

N/A

At this point, the users can choose which resolution scripts they want to apply. When users click on the Next button, the resolutions of the root causes selected by the user will be executed. 

Command-line user interface

As covered in the WTP command-line design section, IT administrators can use the command-line to discover the root causes and the properties of a troubleshooting package and execute a troubleshooting package from the command-line. More on administrator use will be discussed in later section Command-line administration including execution on remote computers.

To run a troubleshooting package in the PowerShell command-line user interface, one needs to specify the path to a package folder. The path can be local or UNC. The cabinet file package is supported by the graphical interface MSDT.exe only. To prepare for this cmdlet to work, one must first ensure the cmdlet is available within a PowerShell session. This can be done by open a PowerShell session and by entering the following.

Import-Module TroubleshootingPack

This command will bring the WTP management cmdlets into the active session. Refer to the PowerShell documentation for details on what this import cmdlet does and likewise how to make this import process automatic for every new session. Upon executing the import command, two WTP management cmdlets are available: Get-TroubleshootingPack and Invoke-TroubleshootingPack.

Using the Get-TroubleshootingPack cmdlet, administrators can gather detailed information of a troubleshooting pack. As shown below, the package high level metadata is listed as the default properties of a troubleshooting pack. Upon retrieving the troubleshooting pack, one can also examine the root causes and the resolutions.

Screen5.jpg

By using the Invoke-TroubleshootingPack cmdlet, the user is able to execute the Aero troubleshooting package from the command line. Shown in the example below, the DWM service is manually stopped first so that the root cause of this service will be detected and hence the resolution is presented. By default, Invoke-TroubleshootingPack cmdlet is interactive, meaning it will prompt the user before applying the resolution and providing help and additional options at the end of troubleshooting package execution. A ‘silent’ mode is also available, enabling IT administrators to setup and launch troubleshooting package silently. More on this capability will be discussed in the Command-line administration section below.

Screen6.jpg

Adding multiple root causes

The exercise illustrated in the previous section highlights the mechanics of building a troubleshooting package and how they stem from the concepts and design of WTP. Performing a diagnostic can simply be summarized as detecting a series of root causes, fixing those root causes that were found to be problematic, and then verifying the fixes. This simplicity allows diagnostic authors to build solutions addressing a variety of scenarios. In this section, the sample built in the previous section will be enhanced with an additional root cause Desktop Composition, as well as introducing user interaction for resolution, and then leading to customizing the interaction with variation of user interface presentation. The buildup of this Aero diagnostic package will also include discussion on progress and results reporting, along with guides on debugging.

Windows Aero represents the latest presentation technology offered in the Windows operating system. From a diagnostic perspective, the right question to ask is what are the root causes that could prevent Aero from working correctly? In the previous section, the illustrating DWM service (uxsms) is one root cause that could prevent Aero from functioning. Other root causes include color bit-depth, power settings, desktop composition, and themes. The important point to note is that when authoring a diagnostic pack, a comprehensive analysis of all root causes should be performed to ensure diagnostic coverage is thorough and effective. While the sample in this section will not to cover all Aero root causes, the best practice is always to perform analysis before authoring diagnostic packs.

The purpose of this exercise is to build upon the previous sample by adding a desktop composition root cause to the troubleshooting logic and thereby further illustrating the usage of the WTP concepts of multiple root causes and multiple resolvers. Just as the steps that were carried out to specify the DWM service root cause, a new root cause definition will need to be entered into the manifest file. Reference to the package schema shows that the Rootcauses node accommodates multiple Rootcause. Therefore, the desktop composition root cause can simply be appended after the DWM service root cause. The structure of this definition simply instructs WTP to execute detection logic based on the order of root cause definition listed in the manifest. While this execution flow is simple and suitable for a variety of diagnostics, section Controlling flow between root causes will discuss how the package author can control the detection logic flow. The introduction of this desktop composition root cause must also be accompanied by resolution and verification. This sample will begin by specifying a resolution that automatically fixes the desktop composition, and then using the same detection logic for verification. The sample will then be expanded in section Adding an interaction to diagnose the Theme setting and presenting to the end user available themes to choose from. This is an illustration of incorporating the gathering of user input, also known as interaction, as offered by WTP. Finally, the sample will be further enhanced by changing the looks of theme choices in the user interaction screen. This last item looks at the user interface extension capability and how one can customize the presentation and flow behavior using the ExtensionPoint facility. During each stage of planning and implementation, the concepts and workings of diagnostic report will also be introduced and incorporated to demonstrate how manageability of a diagnostic package can be realized.

Adding another root cause to a diagnostic package is not a difficult task. However, care must be exercised when root causes are being considered. One should consider what constitutes a root cause, and the root causes that need to be investigated for a diagnosable problem. There’s nothing that prevents one from defining a single root cause definition and then writing a single troubleshooting script that covers all root cause logics. This is not a good practice however. Root causes should be distinct and should not be aggregated together for the sake of convenience. Take the root causes for Aero as an example. Combining desktop composition and power setting root causes doesn’t make sense because each should be identified and executed independently. Doing so offers the advantage of quantifying distinct problem areas and leads to better focused detection logic, well-isolated fixes, structuring of package content, and analysis of reporting results. The last item is worth mentioning because it is through the report data that one can ascertain the thoroughness and effectiveness of the troubleshoot pack. More on the reporting topic will be discussed throughout the construction of the desktop composition root cause.

Planning for multiple root causes

As mentioned, the root cause that will be added in this section is the detection of desktop composition setting. There are two primary checks that need to be performed: the Desktop Manager (dwm.exe) process must be running, and the desktop composition setting must equal 1. As in the single root cause case, this detection logic will be implemented in its own troubleshooting script, and the manifest definition for this root cause will reference this script as well. If the troubleshooting for this detection reveals a problem, the resolution is to set the desktop composition to the correct value and restart the DWM service (uxsms). This will also require a new resolution script and will need to be specified in the manifest. Finally, the verification can use the same detection script but will also need to be specified in the manifest.

With the addition of this root cause to the Aero diagnostic package, it is also important to be mindful with regards to what the processing of two root causes has on the experience for the end user. Obviously, it doesn’t take two root causes to begin this consideration. Having more than one root cause simply amplifies this need with considerations like progress and user interaction during the diagnostic phases. User interaction will be introduced and discussed in section Adding an interaction. Here, two root causes will be processed by WTP in the manner in which they are specified in the manifest. This has an effect on what gets reflected to the end user with the notion of conveying progress of diagnostic execution. The package author can use the Write-DiagProgress cmdlet in each phase of diagnostic to indicate this progress. As with root cause name and description, the progress message should be meaningful for the end user. For this desktop composition root cause detection progress, a message like “Determining whether Desktop Window Manager is running and checking theme composition setting” is appropriate. A similar message should be included in the resolving script.

At this point, the primary logic and scripts are well known, but it is worth mentioning and reiterating the important attributes that specifies and governs this diagnostic pack’s runtime behavior. In particular, unique identifications should be specified for desktop composition root cause and resolution. The name and description also need to be meaningful. The specification for each script should point to the correct file with good practice for naming convention like ‘TS_[root cause].ps1’ for detection script, and ‘RS_[root cause].ps1 for resolver script. Other properties in the script specification can largely be the same as in the DWM service root cause. Another callout here is the manifest setting for the RequiresElevation element. The logic for the detection script simply reads the composition value so administrator privilege is not required. However, the resolver script requires elevation because it has to restart the DWM service. Other properties in the script specification like Parameters, RequiresInteractivity, and ExtensionPoint will be covered in later sections. For now, set the RequiresInteractivity to false and leave the remaining two properties blank.

Implementing multiple root causes

The planning stage lays out all the critical elements that are needed in the manifest as well as the preparation for writing the processing logic in the script files. With the addition of the desktop composition root cause, the manifest for the root causes will largely look like the single root cause. The XML fragment for the new root cause is shown below.

<Rootcauses>
    <Rootcause>
        <ID>RC_DwmService</ID>
        <DisplayInformation>
            <Parameters/>
            <Name>Desktop Window Manager Session Manager service isn't running</Name>
            <Description>The Desktop Window Manager Session Manager service is used to display Aero desktop effects such as transparency.  The service or process is currently stopped.</Description>
        </DisplayInformation>
        <Troubleshooter>
            <Script>
                <Parameters/>
                <ProcessArchitecture>Any</ProcessArchitecture>
                <RequiresElevation>false</RequiresElevation>
                <RequiresInteractivity>false</RequiresInteractivity>
                <FileName>TS_DwmService.ps1</FileName>
                <ExtensionPoint/>
            </Script>
            <ExtensionPoint/>
        </Troubleshooter>
        <Resolvers>
            <Resolver>
                <ID>RS_DwmService</ID>
                <DisplayInformation>
                    <Parameters/>
                    <Name>Restart the Desktop Window Manager Session Manager service</Name>
                    <Description>Restarting the Desktop Window Manager Session Manager service will enable Aero desktop effects such as transparency.</Description>
                </DisplayInformation>
                <RequiresConsent>false</RequiresConsent>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>true</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>RS_DwmService.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Resolver>
        </Resolvers>
        <Verifier>
            <Script>
                <Parameters/>
                <ProcessArchitecture>Any</ProcessArchitecture>
                <RequiresElevation>false</RequiresElevation>
                <RequiresInteractivity>false</RequiresInteractivity>
                <FileName>TS_DwmService.ps1</FileName>
                <ExtensionPoint/>
            </Script>
            <ExtensionPoint/>
        </Verifier>
        <ContextParameters/>
        <ExtensionPoint/>
    </Rootcause>
    <Rootcause>
        <ID>RC_DesktopComposition</ID>
        <DisplayInformation>
            <Parameters/>
            <Name>Desktop composition is not set</Name>
            <Description>Desktop composition must be set to display Aero desktop effects such as transparency. </Description>
        </DisplayInformation>
        <Troubleshooter>
            <Script>
                <Parameters/>
                <ProcessArchitecture>Any</ProcessArchitecture>
                <RequiresElevation>false</RequiresElevation>
                <RequiresInteractivity>false</RequiresInteractivity>
                <FileName>TS_DesktopComposition.ps1</FileName>
                <ExtensionPoint/>
            </Script>
            <ExtensionPoint/>
        </Troubleshooter>
        <Resolvers>
            <Resolver>
                <ID>RS_DesktopComposition</ID>
                <DisplayInformation>
                    <Parameters/>
                    <Name>Enable desktop composition</Name>
                    <Description>Restarting the Desktop Window Manager Session Manager service will enable Aero desktop effects such as transparency.</Description>
                </DisplayInformation>
                <RequiresConsent>true</RequiresConsent>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>true</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>RS_DesktopComposition.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Resolver>
        </Resolvers>
        <Verifier>
            <Script>
                <Parameters/>
                <ProcessArchitecture>Any</ProcessArchitecture>
                <RequiresElevation>false</RequiresElevation>
                <RequiresInteractivity>false</RequiresInteractivity>
                <FileName>TS_DesktopComposition.ps1</FileName>
                <ExtensionPoint/>
            </Script>
            <ExtensionPoint/>
        </Verifier>
        <ContextParameters/>
        <ExtensionPoint/>
    </Rootcause>
</Rootcauses>

The RequiresConsent element determines whether a resolver action requires the end user to give permission to execute. Essentially, when this property is set to true, WTP will enforce and ask for user consent before applying the resolution fix.

Multiple resolvers

In looking at the manifest structure, the resolver section indicates the accommodation for multiple resolvers per root cause. For most diagnostic situations, the guideline is to analyze and scope out the root cause and resolver, and for most cases this is likely a one-to-one pairing. However, there are scenarios where a single root cause can have multiple ways of addressing the resolution. For example, when a print job appears to be stuck, there are a number of resolutions that can be performed, such as resetting the job and restarting the spooler service. Following the best practices for distinct root causes, the principle of individual accountability applies to resolutions as well. In fact, separating distinct resolutions may be a necessity as well. For instance, canceling all print jobs is a last resort resolution and the end user should have the choice whether to terminate all print jobs. This decision is the consent setting.

If all resolutions listed here were aggregated into a single resolution, the consent setting would then always present a choice screen even though resetting a print job is all that’s needed in the majority of cases. This is cumbersome for the end user and provides a bad experience as well. There are other important reasons for isolating distinct resolvers too. Risk impact is also critical to consider. The point of every resolver is to fix a problem, but the very act of fixing can have varying degree of impact to the system. Separation of resolver should be the result of impact assessment. Through a well planned and assessed process, a much more robust and manageable diagnostic package will be the result.

Detection and resolving logic

As mentioned in the planning section for adding the desktop composition root cause, the detection logic script will need to look for the Desktop Manager process (dwm.exe) and the composition setting. It is easy to detect a process by using the Get-WmiObject Win32_Process and matching the ProcessName to dwm.exe. An additional qualifier should be given to ensure the detection is applicable for the end user invoking the Aero diagnostic. This can be done through matching the current user name and domain to the process’ equivalent properties. Capturing this logic into a single function makes good practice for later reuse and better code organization. The code for function GetProcessForCurrentUser is shown here.

function GetProcessForCurrentUser($processName=$(throw "No process name is specified."))
{
     return Get-WmiObject Win32_Process | Where {($_.ProcessName -ieq $processName)  `
                                         -and ($_.GetOwner().User -ieq $Env:UserName) `
                                         -and ($_.GetOwner().Domain -ieq $Env:UserDomain)}
}

 

The next logic to write is to look for the desktop composition setting located in the registry. When Aero theme is enabled, the composition setting value is 1. Use the Get-ItemProperty to retrieve this value from the registry and conveniently save it in a variable for easy comparison. Putting it all together, the final detection logic is calling the GetProcessForCurrentUser with ‘dwm.exe’ as the process to look for, and seeing whether the composition value is indeed equal to 1. If either the dwm.exe process is absent or the composition value is set to other than 1, then this root cause has been identified and the resolution should be applied. This is simply done by informing WTP, via cmdlet Update-DiagRootCause, with the desktop composition root cause identifier so that the RS_DesktopComposition.ps1 script will be executed. This code is shown below.

# This root cause is detected if DWM process is not present and composition not set to 1
$compositionRegValue = (Get-ItemProperty("HKCU:\software\Microsoft\Windows\DWM")).Composition
$RootCauseDetected = ((GetProcessForCurrentUser "dwm.exe") -eq $null -or $compositionRegValue -ne 1)
# Inform WTP of the status of this root cause
Update-DiagRootcause -id $RootCauseId -detected $RootCauseDetected

The resolver logic is likewise simple; ensure that the composition value is set to 1 and restart the uxsms service. Basic validation should be practiced when setting a registry value. One should look for the path existence as well as the property existence prior to setting a value. Here, the path check for HKCU:\Software\Microsoft\Windows\DWM is performed first, and then the existence of the Composition property is tested. If neither is true, then they should be created using the New-Item and New-ItemProperty respectively. Otherwise, it’s a simple Set-ItemProperty on the Composition property with the value 1. A restart on the uxsms service will pick up this value and enable Aero to work properly again. The code is shown here.

$desktopCompositionKey = "HKCU:\software\Microsoft\Windows\DWM"
if(-not(Test-Path $desktopCompositionKey )) {
    New-Item -Path $desktopCompositionKey
}
if((Get-ItemProperty $desktopCompositionKey "Composition") -eq $null) {
    New-ItemProperty -Path $desktopCompositionKey -Name "Composition" -PropertyType DWORD -Value 1
} else {
    Set-ItemProperty $desktopCompositionKey "Composition" 1
}
Restart-Service UxSms

Also mentioned in the planning section, emitting progress messages at each phase should be considered. Whether to emit the message and the verbiage of the message should be carefully considered to promote good user experience. As a good rule of thumb, one should consider showing progress for a task that takes more than one second to process. For the desktop composition detection and resolver, progress message will be displayed via invoking the Write-DiagProgress at the beginning of each corresponding script. Here’s an example for the resolver.

Write-DiagProgress -Activity "Enabling desktop composition..."

Reporting

Integral to WTP is the reporting capability. Each running instance of a diagnostic package will result in a report file being created. Report data captures steps that WTP carried out when executing a diagnostic package. This information can assist support personnel in determining common problems and the effectiveness of a diagnostic pack. Each report contains standard information such as the package header, which includes properties like the version and publisher, and details of every root cause examined and addressed. This report can be found by going to Control Panel\All Control Panel Items\Troubleshooting and selecting the View History link. A list of all diagnostic execution is listed. Select a target troubleshooting diagnostic, and right-click and select ‘Open file location…’ from the context menu. Administrator privilege is required to perform this. Upon opening the folder, locate the file ResultReport.xml.

Looking through this report reveals the detailed information of a diagnostic execution. However, because the context of each diagnostic package is unique and could involve complex logic through many root causes, it would be beneficial for diagnostic package authors to capture specific context information in series with the standard report result file. WTP offers such a facility through the cmdlet Update-DiagReport.

Reference usage for this cmdlet shows that one can either embed XML fragment or supply a path to another file. There may be occasions where intermediate data are written to a file and one wishes to include such information in the overall report. In the case of the Aero diagnostic, a thorough troubleshooting could involve running the System Assessment Tool, which pipes results to a file. The XML in this file can then be used to determine a number of criteria such as DirectX version.

Although only some portion of the data in this intermediate file is needed for detection, the tracking report should contain the entire information. So in this case, it is appropriate to use Update-DiagReport –file [path to System Assessment Tool result file]. In most cases, however, the usage will likely be composed of gathering some raw data, pipe to ConvertTo-Xml, and then pipe to Update-DiagReport. The net effect is embedding the gathered data into the result report. One can invoke Update-DiagReport as many times as needed, but authors should consider the size of each report message and the cumulative size because WTP will buffer in memory and flush to file upon completion.

In the desktop composition detection logic, one useful reporting data is the events generated by dwm.exe. As shown above, the process detection for dwm.exe is trivial. However, if the process cannot be detected, one would like to know why and possibly even find out additional causes for the absence of this process. To get a better assessment from the event log, one should consider pulling several days worth of data and write this data to the result report. The code is shown here.

# Get DWM-related events from the past week for troubleshooting report
$dwmEvents = Get-WinEvent -FilterHashTable @{`
ProviderName="Microsoft-Windows-WindowsSystemAssessmentTool"; `
                            StartTime=[DateTime]::Today.AddDays(-7)} `
                            | Where {$_.Message.contains("DWM")}
$dwmEvents | ConvertTo-Xml | Update-DiagReport -id DesktopWindowManagerEvents `
                                -name "Desktop Window Manager Events" `
                                -description "Recent events generated by the System Assessment"

With the implementation complete, the net result to the Aero diagnostic package is the ability to detect two root causes and to resolve them independently. In addition, dwm.exe events are captured and included in the result report for further analysis and potentially leading to the discovery of new root causes. In section Adding an interaction, user interaction will be introduced, extending the Aero diagnostic to have the end user select a theme.

In the above example, the two root causes are executed in the sequence specified.  This is generally the default.  However, the platform does optimize in some cases.  For example, if elevation is required, the engine will execute all root causes that do not require elevation first before executing any root causes that require elevation.  If the problem is detected and resolved by root causes that do not require elevation, then the user is not bothered with the elevation screen.

Debugging

While developing the above detection and resolution logic, the author will likely face the situation where the troubleshooting package is not functioning as expected. When this happens, the author will need to debug and find out where and why the issue is occurring. As with the reporting facility, WTP offers a corresponding debug file that captures the vital runtime information such as function calls, time spent in each script and exception details. This file can be found in the same location as the report file and has the suffix debugreport.xml. Authors can examine this file to look for script errors which will indicate the errors encountered along with line numbers.

Adding an Interaction

Up to this point, the resolvers for the two root causes are applied silently, meaning without the need for the end user to interact. Depending on circumstances, however, it could be beneficial or even necessary to ask the end user for an input choice before proceeding. The previously discussed user consent is one such case of input choice. In this section, the Aero diagnostic sample will be extended to include user interaction for choosing from a set of Aero themes. This practical example will provide an illustration to the capabilities of user interaction offered by WTP.

The declarative style of defining user interaction makes the specification easy to author. WTP offers the following ways of defining user interaction:

  • Single-response allows selection of one choice from a list of choices
  • Multiple-response allows selection of multiple choices from a list of choices
  • Text input allows the end user to enter text
  • Pause interaction waits for the user to acknowledge before proceeding
  • Launch UI interaction allows another application to be launched

The best troubleshooters automatically find and fix the user’s issue without manual intervention. However, sometimes the user must guide the troubleshooter to what needs to be fixed. For example, if there are multiple audio playback devices detected, the user can be asked which one is causing trouble. For this type of situation, interaction helps guide the user to fix the specific problem at hand. In general, however, interaction should be used sparingly.

For the sample here, fixing the Aero theme means selecting from one of the default Aero themes. A safe bet is to select the Aero theme and apply this in the resolver. Although this is an acceptable resolution, the user might prefer another theme. So here’s an opportunity to improve user experience and offer theme choices for selection. Note the example only requires a single selection.

The SingleResponseInteraction template is a natural fit here. In other circumstances, other response types may be more appropriate. For instance, the text interaction is suitable for gathering the network location the user is trying to reach. The pause interaction is good for instructing the user to perform an action, like plug in the network cable, and waiting until the user acknowledges by clicking the Next button. Multiple response interaction can be used to gather detection criteria for search such as files or emails. One should also consider using the LaunchUIInteractions carefully, because moving the user context away from the troubleshooting wizard screen can lead to a poor experience.

Note that user interaction can also occur during the detection stage. For instance, when troubleshooting an audio playback issue, the user could be asked whether she wants to troubleshoot speakers or headphones. To use interaction from any script logic, the corresponding script block definition in the manifest must have RequiresInteractivity set to true. WTP will enforce this setting with interaction and display an error if this setting is false and interaction is invoked.

Planning for the interaction

Incorporating user interaction into a diagnostic package is straightforward. Upon determining the type of interaction that is needed, the first order is to declare the interaction specification in the package manifest. Just as in the root cause definition, the manifest schema defines the user interaction structure. Notice that the interaction identifier is not referenced from anywhere in the troubleshooter or resolver definition sections. This is intentional to allow for the independence of interactions and the flexibility to invoke interaction from any phase of diagnostic. Through the use of Get-DiagInput cmdlet with the interaction identifier, WTP will read the interaction specification and depending on how diagnostic was initiated, either present a screen for the user to choose or read selected choices from an answer file. More about answer file will be covered in section Command-line administration.

Implementing the interaction

To incorporate the use of interaction in this sample pack, a third root cause, Aero Theme, will be added, and the resolver logic will call Get-DiagInput for the user to pick a theme and the resolution to set to that theme. Following the manifest definition completed for the first two root causes, and setting up the appropriate script files, the housekeeping definition is largely a copy-paste operation. The new task here is adding the interaction definition. A simplified theme choice will be defined offering Windows 7, Nature, and Landscapes. The XML for the interaction looks like this.

<Interactions>
    <SingleResponseInteractions>
        <SingleResponseInteraction>
            <AllowDynamicResponses>false</AllowDynamicResponses>
            <Choices>
                <Choice>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>Windows 7</Name>
                        <Description>Windows 7 Theme</Description>
                    </DisplayInformation>
                    <Value>aero</Value>
                    <ExtensionPoint/>
                </Choice>
                <Choice>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>Nature</Name>
                        <Description>Nature Theme</Description>
                    </DisplayInformation>
                    <Value>nature</Value>
                    <ExtensionPoint/>
                </Choice>
                <Choice>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>Landscape</Name>
                        <Description>Landscape Theme</Description>
                    </DisplayInformation>
                    <Value>landscape</Value>
                    <ExtensionPoint/>
                </Choice>
            </Choices>
            <ID>IT_Theme</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>Select a theme</Name>
                <Description>Select a theme to enable Aero effects such as transparency.</Description>
            </DisplayInformation>
            <ContextParameters/>
            <ExtensionPoint />
        </SingleResponseInteraction>
    </SingleResponseInteractions>
    <MultipleResponseInteractions/>
    <TextInteractions/>
    <PauseInteractions/>
    <LaunchUIInteractions/>
</Interactions>

The detection logic for Aero Theme could just check for the Theme service running. If the service is not running, then inform WTP that a root cause has been found so the defined resolver will be invoked. The detection code is shown here.

# Detect whether the Theme service is running
if ((Get-Service Themes).Status -ne "Running") {
    Update-DiagRootCause -id "RC_Theme"
}

When calling Get-DiagInput in the resolver script, the selection choice can be preserved in a variable and subsequently used to set to the selected theme. But first, the Theme service should be started as part of the resolution. Then Control.exe will then be invoked to set the theme. The resolver code is shown here.

# Have user pick a theme and start the Theme service
$theme = Get-DiagInput -id IT_AeroTheme
Start-Service Themes
# Set the desktop theme to one selected by user
$control_exe_args = `
    "/name Microsoft.Personalization " `
    + "/page ?Theme=" + $Env:SystemDrive[0]
    + "%3A%5CWindows%5CResources%5CThemes%5C" + $theme + ".theme"
& control.exe $control_exe_args.split(" ")

After completing the manifest and these two scripts, build the Aero diagnostic pack, and it’s ready for action. Testing this package is simple. Simply stop uxsms service to exercise the first root cause. Stop the dwm.exe process or set the desktop composition value to 0 to test the second root cause. Finally, stop the Theme service to exercise the theme selection interaction. After exercising through the various combinations, look at the result report as well. This can be viewed from the WTP wizard or from a text editor. It should be clear which root cause was detected and what was resolved.

If choices cannot be determined during design time, then static choices are not very useful. This is where one can use the –Choice parameter in Get-DiagInput and supply a list of choices that can be constructed during runtime. Specifying the –Choice parameter also means the defined choices in the manifest will be ignored when WTP processes the interaction. More important, however, is that the AllowDynamicResponses must be set to true in the manifest for the –Choice to be applicable. An example on how to use the –Choice parameter is shown here.

$choices = New-Object System.Collections.ArrayList
Foreach ( $item in $myCollection ) {
    $choices += @{"Name"="$item.name"; "Description"="$item.desc"; `
                  "Value"="$item.val"; "ExtensionPoint"="";}
}

The sample code above shows how choices can be composed during execution. If this Aero diagnostic is geared for production use, the interaction should look for all available Aero themes installed on the user computer and build a list of choices to allow the user to select.

To summarize, the concepts and workings of multiple root causes, multiple resolvers, reporting, and interaction were shown in this section. A diagnostic package can cover more than one root cause and potentially have more than one resolver per root cause. Package authors can inject custom data, both static and file reference, to be included in the standard result report for post execution analysis. When necessary, package authors can request input from the user through interactions. WTP offers these capabilities through a powerful and flexible combination of manifest declaratives and cmdlet interfaces.

Customizing the Interaction

During the design phase of a diagnostic pack, the author should consider all aspects of processing logic and user experience. If the diagnostic package is designed for the end user to self-navigate, the user experience is even more critical. As a platform, WTP offers a standard user interface to bring about a consistent user experience. The wizard navigation, processing steps, and result report, among others, minimize the need for the user to relearn new diagnostics. However, the context of each diagnostic package is different and, depending on the problem domain, some may require added interaction with the user. The End User License Agreement (EULA) is one example. For a diagnostic resolution to begin, the package author may require the end user to accept a EULA. In other cases, the package author may want to decorate interaction choices with icons, or want links over radio buttons as choice selectors. These and others are offered through the use of the ExtensionPoint definition.

ExtensionPoint is applicable within the WTP wizard only (MSDT.EXE). The ExtensionPoint definition is ignored when executing a diagnostic package via command-line. ExtensionPoint can be defined in most situations according to the package schema but some of these are reserved for future use and not supported by the WTP wizard. Primarily though, ExtensionPoint is for interactions because they have the most potential to vary across troubleshooting packs. This section will cover the available extension elements, indicate where they are applicable, and conclude with a simple demonstration of changing the Aero interaction choice selection to appear as a list instead.

Extension

Description

Applicable

<RTFDescription>

Use instead of default <Description>. The rich text can be in a file located within a resource dll.

Example usage:

<RTFDescription>

  @DiagPackage.dll,-123

</RTFDescription>

<RTFDescription>

  @DiagPackage.dll,MyFile.RTF

</RTFDescription>

All Interactions

<Browse

  FilterText=""    FilterExtension=””>

</Browse>

Open dialog to browse File, Folder, or Computer with optional filtering criteria. FilterText is the description and FilterExtension is the actual filter criteria.

Example usage:

<Browse>

  Folder

</Browse>

<Browse

  FilterText="Text File"

  FilterExtension=”*.txt;*.docx”>

      File

</Browse>

<TextInteraction> - valid only for single line text.

<EditMode>

Allows multiple lines of text to be entered in an edit text field.

Example usage:

<EditMode>

  Multi

</EditMode>

<TextInteraction>

<NoUI>

Suppresses the interaction which contains this extension. An answer file is used instead.

Example usage:

<NoUI />

All interactions

<NoCache>

For efficiency, WTP cache interaction response if the interaction is presented again. This extension suppresses caching and allows the interaction to flow like its first encounter.

Example usage:

<NoCache />

All interactions

<Eula>

Signifies the interaction is an End User Licensing Agreement.

Example usage:

<Eula />

<TextInteraction>

<CommandLinks />

Renders choices as a list instead.

Example usage:

<CommandLinks />

<SingleResponseInteraction> - applicable for two or three choices.

<Link>

Display a hyperlink on an interaction page.

Example usage:

<Link>https://www.microsoft.com</Link>

All interaction

<Resolver>- applies to resolver which does not have an associated script

<LinkText>

Used with <Link> to specify alternative text for the hyperlink.

Example usage:

<LinkText>Microsoft</LinkText>

All interaction

<Resolver>- applies to resolver which does not have an associated script

<Default>

Specifies the default text for a text interaction.

Example usage:

<Default>@DiagPackage.dll,-123</Default>

<TextInteraction>

<Default>

Specifies the default choice of the interaction.

Example usage:

<Default />

<SingleResponseInteraction>

<MultipleResponseInteraction>

<Icon>

Icon in resource file can be used to place an icon next to each choice item.

Example usage:

<Icon>@DiagPackage.dll,-456</Icon>

<SingleResponseInteraction>

<MultipleResponseInteraction>

- Applies to the extension point within the <Choice> element

<Icon>

Icon can also be specified for the troubleshooting package to appear in the first wizard page.

Example usage:

<Icon>@DiagPackage.dll,-456</Icon>

<LocalDiagnosticPackage>

<GlobalDiagnosticPackage>

<LinkFlushWithText>

Align link flush with text instead of being at default link position at bottom of wizard page.

Example usage:

<LinkFlushWithText />

<TextInteraction>

<Resolver>- applies to resolver which does not have an associated script

<ButtonText>

Change the default button text on the LaunchUIInteraction

Example usage:

<ButtonText>@DiagPackage,-123</ButtonText>

<LaunchUIInteraction>

Continuing from the previous section, the interaction choices here will be rendered as a list instead of the radio buttons. In practice, this is as simple as adding <CommandLinks /> within the ExtensionPoint element at the level of SingleResponseInteraction. The result is shown here.

    <Interactions>
        <SingleResponseInteractions>
            <SingleResponseInteraction>
                <AllowDynamicResponses>false</AllowDynamicResponses>
                <Choices>
              Choices as shown in previous section
                </Choices>
                <ID>IT_Theme</ID>
                <DisplayInformation>
                    <Parameters/>
                    <Name>Select a theme</Name>
                    <Description>Select a theme to enable Aero effects such as transparency.</Description>
                </DisplayInformation>
                <ContextParameters/>
                <ExtensionPoint>
                    <CommandLinks/>
                </ExtensionPoint>
            </SingleResponseInteraction>
        </SingleResponseInteractions>
        <MultipleResponseInteractions/>
        <TextInteractions/>
        <PauseInteractions/>
        <LaunchUIInteractions/>
    </Interactions>
Controlling Flow Between Root Causes

The previous section discussed multiple root causes and the sequence in which these root causes are evaluated (detected, resolved, and verified.)  Although the sequence may differ depending on the conditions, all the root causes are always evaluated.  After detecting a root cause, there are times when the execution should stop, or skip some root causes.  This functionality is implemented using a term known as “global troubleshooter”.

Generally it is best to specify all the root causes and let WTP use the internal methods for the execution order.  However, there are specific scenarios where this does not make sense, especially when user interaction is required for a root cause that cannot be fixed under the specified conditions.  For example, if sound is not working because a sound card is not present, it does not make sense to ask the user which sound device to troubleshoot, earphones or speakers.

In these cases, it is best to control the flow between root causes and to determine which root causes to execute next or to terminate execution after the results of executing a root cause.

For example, in the case of Aero, if a WDDM video driver is not present to support Aero, it does not make sense to check whether the DWM service, desktop composition service, or theme service is running because none of these will fix the missing driver problem.

So it would be good to check for the right driver and only continue if the driver exists.  To do this, global troubleshooters allow the detection logic to live outside any single root cause.  This is done by first constructing the troubleshooting package manifest to reflect a global troubleshooter.

<Troubleshooter>
  <Script>
    <Parameters/>
    <ProcessArchitecture>Any</ProcessArchitecture>
    <RequiresElevation>true</RequiresElevation>
    <RequiresInteractivity>true</RequiresInteractivity>
    <FileName>MF_AeroDiagnostic.ps1</FileName>
    <ExtensionPoint/>
  </Script>
  <ExtensionPoint/>
</Troubleshooter>
<Rootcauses>
      <Rootcause>
          <ID>RC_WddmDriver</ID>
          <DisplayInformation>
              <Parameters/>
              <Name>@AeroDiagnostic.dll,-23</Name>
              <Description>@AeroDiagnostic.dll,-24</Description>
          </DisplayInformation>
          <Resolvers>
              <Resolver>
                  <ID>RS_WddmDriver</ID>
                  <DisplayInformation>
                      <Parameters/>
                      <Name>@AeroDiagnostic.dll,-25</Name>
                      <Description>@AeroDiagnostic.dll,-26</Description>
                  </DisplayInformation>
                  <RequiresConsent>false</RequiresConsent>
                  <Script/>
                <ExtensionPoint>
                  <Link>mshelp://Windows/?id=b3c6477e-1111-4b9f-a52a-fffdc51e9c90</Link>
                </ExtensionPoint>
              </Resolver>
          </Resolvers>
          <Verifier>
              <Script>
                  <Parameters/>
                  <ProcessArchitecture>Any</ProcessArchitecture>
                  <RequiresElevation>false</RequiresElevation>
                  <RequiresInteractivity>false</RequiresInteractivity>
                  <FileName>TS_WddmDriver.ps1</FileName>
                  <ExtensionPoint/>
              </Script>
              <ExtensionPoint/>
          </Verifier>
          <ContextParameters/>
          <ExtensionPoint/>
      </Rootcause>
  Other root causes as listed in the previous sections
</Rootcauses>

Note that the troubleshooting section has been placed outside any single root cause, hence the name “global troubleshooter.”  The second part is to write a script that tests root causes and controls flow based on the detection result of each root cause.  Following is an example of a script that detects the presence of the right driver and if this driver is missing stops any further checks, but if this driver is present it proceeds to check for other root causes. The function RunDiagnosticScript is for convenience and makes the script code easier to read. Likewise, what’s also important to spell out here is how WTP is notified of when a root cause is detected. Recall from previous sections that a root cause state is set when the cmdlet Update-DiagRootCause is called within a detection script. This cmdlet should always be called for each root cause, whether the root cause is detected or not. Not doing so puts the root cause in a ‘Not Checked’ state indicating an incomplete path for troubleshooting. Here as a global troubleshooter, the author should keep in mind that there is flexibility as to where and when Update-DiagRootCause can be called. From the code below, one can actually call Update-DiagRootCause immediately after executing each detection script. Or, keep the call localized within each detection script. Regardless of which method is used, the cmdlet must be called.

# Utility function
function RunDiagnosticScript([string]$scriptPath `
                             = $(throw "No diagnostic script is specified")) {
    if(-not (Test-Path $scriptPath)) {
        throw "Can't find diagnostic script"
    }
    $result = &($scriptPath)
    if($result -is [bool]) {
        return [bool]$result
    } else {
        return $false
    }
}
# Main diagnostic flow
if((RunDiagnosticScript .\TS_HardwareSupport.ps1) -eq $false) {
    return
}
RunDiagnosticScript .\TS_DwmService.ps1
RunDiagnosticScript .\TS_DesktopComposition.ps1
RunDiagnosticScript .\TS_ Themes.ps1

In summary, a global troubleshooter can be used to control work flow, specifically what root cause logic to execute next based on a return code of a specific detection logic.  There are two places where a global troubleshooter differs from the local troubleshooter.  The troubleshooting package manifest needs to be modified so that the troubleshooting section is “global” outside any one specific root cause. The detection logic has to be moved into one script that can control work flow.

Preserving Context

There are instances when context/variables need to be passed between scripts, from script to the engine, or from script to the client.  All three of these are supported in WTP.  This section will discuss the ability to pass variables around, give examples of applicable scenarios, and show how to implement this functionality.

The ability to pass variables around is needed in all types of programming.  WTP has the ability to preserve the variables of a script so they can be used after the script has finished running.  This is done by declaring these variables as parameters in the manifest.

For example, if you have a troubleshooting package for Aero and one of the root causes detects the state of the “themes” service. If the script detects that the service is stopped, then you can call the resolution script with the name of the service to start (in this case, the “themes” service).

In WTP this is implemented by declaring a parameter under the script node, under the resolver node of the package manifest, and by populating the declared variable in the detection script.  WTP will then automatically provide the variable when calling the resolution script. Below are the examples for the manifest declaration, setting the variable in the detection script, and the format of the resolution script.

The following scripts describe the execution parameter, which executes another script at a later time by passing this parameter to the script. There are two other types of parameters supported by WTP that are covered in the Parameter details section.

<Rootcause>
    <ID>RC_Theme</ID>
    <DisplayInformation>
        <Parameters/>
        <Name>Themes service isn't running</Name>
        <Description>Starting the Themes service will enable Aero desktop effects such as transparency.</Description>
    </DisplayInformation>
    <Troubleshooter>
        <Script>
            <Parameters/>
            <ProcessArchitecture>Any</ProcessArchitecture>
            <RequiresElevation>false</RequiresElevation>
            <RequiresInteractivity>false</RequiresInteractivity>
            <FileName>TS_Theme.ps1</FileName>
            <ExtensionPoint/>
        </Script>
        <ExtensionPoint/>
    </Troubleshooter>
    <Resolvers>
        <Resolver>
            <ID>RS_Theme</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>Start the Themes service</Name>
                <Description>Aero desktop effects require the Themes service to be running.  Starting Themes will enable Aero desktop effects to be displayed.</Description>
            </DisplayInformation>
            <RequiresConsent>true</RequiresConsent>
            <Script>
       <Parameters>
         <Parameter>
           <Name>ServiceName</Name>
           <DefaultValue/>
         </Parameter>
       </Parameters>
                <ProcessArchitecture>Any</ProcessArchitecture>
                <RequiresElevation>true</RequiresElevation>
                <RequiresInteractivity>true</RequiresInteractivity>
                <FileName>RS_Theme.ps1</FileName>
                <ExtensionPoint/>
            </Script>
            <ExtensionPoint>
            </ExtensionPoint>
        </Resolver>
    </Resolvers>
    <Verifier>
        <Script>
            <Parameters/>
            <ProcessArchitecture>Any</ProcessArchitecture>
            <RequiresElevation>false</RequiresElevation>
            <RequiresInteractivity>false</RequiresInteractivity>
            <FileName>TS_Theme.ps1</FileName>
            <ExtensionPoint/>
        </Script>
        <ExtensionPoint/>
    </Verifier>
    <ContextParameters/>
    <ExtensionPoint/>
</Rootcause>
$RootCauseID = "RC_Theme"
[string]$ServiceName= get-service "themes"
# Detect whether the Theme service is running
$RootCauseDetected = ($ServiceName.Status -ne "Running")
# Inform WTP of the status of this root cause
Update-DiagRootCause -id $RootCauseID -detected $RootCauseDetected -parameter @{"ServiceName"="$ServiceName"}

PARAM ($Name)
If ("Running" -ne (Get-Service $Name).Status) {
    Start-Service $Name
}

Parameter details

As mentioned above, there are three types of parameters that can be used in WT:  1) execution parameters, 2) display parameters and 3) context parameters.

Execution parameters are variables captured by one script and stored by the engine to be passed later to another script carrying the context forward.

Display parameters are also declared like execution parameters.  Display parameters are used to pass display information from WTP engine to WTP client such as MSDT.  As an example, if a root cause detects that a printer is out of paper, MSDT may want to tell the user the name of the printer that is out of paper.  The name of the printer can be declared as a parameter under the DisplayInformation tag.

Note:  This is similar to an extension.  The key difference is that a regular extension is understood only by MSDT.  This particular extension is actually understood and formally supported by the WTP engine.

The last type of parameter is the context parameter.  This parameter is a special case for the time being and does not add any critical functionality.

Command-Line Administration

In medium and large IT organizations, managing workstations by administrators is a common activity. Whether that management involves helping users diagnose issues, to installing applications, to ensuring the latest antivirus software is up-to-date, these activities all have some things in common: They usually involve looking at the state of the workstations and applying some actions to them. For an administrator, this usually involves the following two scenarios. First, an end user is having some issues with her workstation and the administrator begins troubleshooting. In the second, the administrator targets some computers and sets actions to perform without end-user intervention and without needing to watch over the actions. From the perspective of troubleshooting, this section will cover the workings of these two scenarios and the WTP facilities aimed for the administrators.

Command-line execution of troubleshooting packages was covered at the conceptual level with a brief usage illustration in previous section. Here, the discussion will cover more in-depth on command-line facility and how the design of troubleshooting packs can affect administering them. As a command-line interface, the strength of WTP is that it is built with PowerShell. As such, administrators can take full advantage of the power and flexibility of PowerShell while exercising troubleshooting activities on a set of workstations. Although the discussion of PowerShell capabilities is beyond the scope of this paper, features pertaining to WTP will be covered here.

Package discovery

In the context of troubleshooting via WTP, an important administrator’s task is to know what the nature of the troubleshooting package is before administering it. This is very important from the standpoint of risk assessment, and administrators must scrutinize every possible change that could lead to an undesirable effect. When a user calls with an issue, running a diagnostic should lead to resolving the issue and not cause further harm. Through the use of the cmdlet Get-TroubleshootingPack, administrators can find out what the troubleshooting package will detect, what resolvers may be applied, and what consequences may result.

Discovering what the troubleshooting package will do also leads to understanding how the package is designed. The usage of Get-TroubleshootingPack is simple. Within a PowerShell session, provided the troubleshooting module is already loaded, run this cmdlet by supplying the path to the package files. Note that the package files here is not the cabinet file (.diagcab extension) representation but the expanded result of the cabinet file. The details of packaging will be discussed in section Packaging and security. From here, the discovery process is merely using the constructs of PowerShell properties and one can find out the details of the troubleshooting pack. Refer back to previous sections to see screen captures of discovering the Aero diagnostic pack.

Perhaps the most interesting package detail discovery is the use of interactions. As covered in the Aero Theme design section, interactions are meant to capture user responses and process further actions based on the response values. From an administrator’s perspective, though, having user interaction within a diagnostic package poses some challenges. Although answer files can be provided to automate the interactions during execution, what’s highlighted here is again the mentioning of troubleshooting package design. With the administrator’s perspective in mind, the package author realizes how critical it is to understand not only the logic correctness, but also how the package will be used, and adhere to the principle of tiered design. Separating logic from UI has been a long standing design practice, and a well structured package following this practice can become more useful and effective. The usage of answer file is available but package authors should be mindful with design as the troubleshooting package can be used by either the WTP wizard or WTP cmdlets.

As discussed previously, Get-TroubleshootingPack can be invoked with the –AnswerFile along with an output file name. This command allows the generation of answers to interactions defined for the specified pack. But what if some of the interactions have choices that are actually defined during runtime? Recall that within the manifest, an author can specify whether single or multiple response interaction have static or dynamic choices. The latter case is through the AllowDynamicResponses node value set to true. In the case of static definition, Get-TroubleshootingPack with –AnswerFile will generate answers based on choices defined. However, in the dynamic case, because the package is not yet executed, there’s no way to know what the available choices are so it’s not possible to even ask and select what the answers are. In this case, the answer file will be produced but the content of the file will not contain the answers. Can the answer be manually added to the answer file? Certainly, but one must be mindful that the nature of dynamic choices means the certainty of the answer is not absolute.

With the Aero troubleshooting package that has been built up to this point, the answer file can be generated for this package. Because the Aero Theme resolver activates a single-response interaction that offers three themes declared in the manifest, Get-TroubleshootingPack with –AnswerFile on this package can produce an answer file that looks like this.

<Answers>

  <Interaction ID="IT_Theme">

    <Value>Nature</Value>

  </Interaction>

</Answers>

Upon the generation of this answer file, the Aero troubleshooting package can be executed on any reachable computer without requiring the user to interact during the process. How is this any different as compared with the Aero package prior to adding interaction, where the resolver simply sets a default? The difference is the administrator gets to specify the default as opposed to the resolver script hard-coding the default.

Package execution

In previous section, the Aero troubleshooting pack was shown running using the Invoke-TroubleshootingPack cmdlet. As seen in that example, the cmdlet was issued without the –Unattended switch and therefore the administrator will need to select the resolver to apply. Taking this a step further with the helpdesk scenario outlined at the beginning of this section, one can begin to see how an administrator can use this cmdlet to troubleshoot in a variety of situations.

The helpdesk scenario naturally lends itself as an interactive session. The user contacts the administrator with an issue and the administrator starts to look at the problem. And through step-by-step detection, one or more remedies may be applied. This is exactly the default behavior of Invoke-TroubleshootingPack. The administrator should run this from his own computer and remotely run the troubleshooting pack. PowerShell remoting allows one to execute commands on one or more remote computers. The following command demonstrates this action.

Enter-PSSession [–computername] <string>

Readers should note that this is a shortened example definition for Enter-PSSession, simplified to illustrate the initiation of interactive session on a single remote computer. PowerShell remoting is rich with features and has provisions for one to fine tune all aspects of executing commands on remote computers. Readers are highly encouraged to consult the PowerShell reference before proceeding.

To troubleshoot Alice’s computer for the Aero issue as an example, assuming the computer is named Workstation01, the administrator could perform the following.

C:\PS>Enter-PSSession –ComputerName Workstation01

Workstation01\PS> $aero = Get-TroubleshootingPack -Path c:\aero

Workstation01\PS> Invoke-TroubleshootingPack –Pack $aero

… shows the resolution selection and allows admin to select

Workstation01\PS> Exit-PSSession

C:\PS>

Assuming PowerShell Remoting is properly configured, the Invoke-TroubleshootPack command will be executed on Workstation01, and the results will then be piped back to the administrator’s computer. What the administrator sees is as though the command was executed locally.

Suppose now that the administrator received calls from more users with the same problem. Going through the command above one computer at a time and selecting the same resolution each time is impractical. The answer file discussed here is part of the solution because it eliminates the interaction. But the Invoke-TroubleshootingPack runs interactively by default, and with a large number of computers to diagnose, this too is impractical. The –Unattended switch mentioned earlier is the solution here. By specifying this switch, the resolvers will be applied automatically in the order declared in the manifest and without any administrator’s input, on those root causes that are either with the status of detected or not-fixed. Elevated privilege criteria apply here as well; meaning only those resolvers that do not require elevated privileges will run automatically. The security provision here goes hand-in-hand with credential and privilege defined in an organization that governs the workstations, and how PowerShell remoting commands are issued. For non-interactive command issuance, PowerShell offers the Invoke-Command with the following usage pattern.

Invoke-Command <ExecutionContext> {<script block to run in the context>}

Putting the above switches together, the administrator can use Invoke-Command to issue it once or even setup a schedule to run it routinely. Note here that the file machine.txt is simply a way to specify multiple computers and allows for reuse with other remote commands.

Invoke-Command -computername (Get-Content machines.txt)  `
               {Invoke-TroubleshootingPack -Pack $aero  `
                                           -AnswerFile AeroAnswerFile.xml  `
                                           -Unattended}

Lastly, the final Invoke-TroubleshootingPack switch to discuss is the –Result switch. This switch simply takes a path to a folder and instructs the cmdlet to write troubleshooting pack’s result to this folder. A diagnostic report, along with a WTP debug file and any external files linked to the report, will all be written to the specified output folder. This allows the administrator to look in one place and perhaps even craft scripts to read reports and take actions based on result data. In the remote execution case, the files from the target computer will be sent to the specified folder upon completion of the troubleshooting pack. If the troubleshooting package encounters an error, the result files will still be sent but the content will contain information up to the point of failure. PowerShell will automatically differentiate results from each computer by creating subfolders using the computer name within the specified path. So, extending the Invoke-TroubleshootingPack above to include the –Result switch, the command looks like this.

Invoke-Command -computername (Get-Content Machines.txt)  `
 {Invoke-TroubleshootingPack -Pack $aero  `
                             -AnswerFile AeroAnswerFile.xml  `
                             -Unattended  `
                             -Result \\Server01\TroubleshootResult\}

Assuming Machines.txt contains computer names, the output folder and files look like this.

\\Server01\TroubleshootingResult\

       Workstation01\

           ResultsReport.xml

           DebugReport.xml

           Result.xsl

           <any linked report files>

       Workstation02\

           ResultsReport.xml

           DebugReport.xml

           Result.xsl

           <any linked report files>

Packaging and Security

This section will cover the folder and file structure of a troubleshooting pack, what it takes to secure the package, and what localized language supports means with regards to security.

All files associated with a troubleshooting package should be placed in a folder. The folder structure can be as detailed as one decides. By default, though, all files are placed in the same folder and all references such as the manifest simply list the file names without having qualifying the relative path. However, localized language resources should be placed in their own folder, in the fashion of locale name, such as en-us. So, if a troubleshooting package supports English and French, one would have subfolders en-us and fr-fr within the root folder. A sample is shown below.

c:\Aero\

    en-us\

    fr-fr\

    DiagPackage.diagpkg

    TS_AeroTheme.ps1

    RS_AeroTheme.ps1      

To move the troubleshooting pack, one would generally collect all files into a compressed file like a zip, or build an installer which includes the package files. When the package makes it to the destination computer, though, a folder structure will need to be created and the package files expanded. From the command-line execution interface as seen in the section above, a folder path is required to execute a specific troubleshooting pack.

However, the user shouldn’t have to expand files or do any other installation. In fact, the scenario should be as simple as the following. The user obtains a troubleshooting package as one file and opens this file that launches the WTP wizard. This is possible because the troubleshooting package was collected into a cabinet file and an extension .diagcab was specified. The custom extension is WTP exclusive and enables the binding of troubleshooting package in cabinet format to the WTP wizard (Msdt.exe).

For an intranet situation, administrators can collect package files and distribute in any fashion that’s convenient and secure. Zipped files in a share folder is a common practice. But for commercial distribution, a signed cabinet file made available for download is a common method for deployment.

Securing a troubleshooting package to prevent tampering is not just a good idea but one that instills the notion of trustworthy computing. After all, the package author and publisher both want to ensure users that their troubleshooting packs are secure and trustworthy. So how does an author go about achieving this? Before getting into the detailed steps on how one secures a package, however, the understanding of how WTP enforces security should be discussed first.

First, it should be clear that WTP cannot ensure the security level of the code logic in a troubleshooting pack. The content of each script is the responsibility of each author. What WTP does enforce and can provide a level of confidence is that when a package is applied with security measures, the files will be tamper proof and likewise the package folder will be protected with no file changes allowed. This is done through the provision of a security catalog signed with a certificate that chains up to a trusted root authority on the executing computer. The catalog contains a list of known files and each is tagged with a hash code that is computed from the content of the file. When a package executes, WTP will look for the security catalog and run through its content verifying what is defined to the actual files in the execution folder. If any discrepancy is found, the package execution is halted. So even if an extra file was added to the execution folder, the package will not run. This mechanism ensures the troubleshooting package built by the author and publisher cannot be tampered with.

In large organizations where Windows Group Policy is used to control access, WTP is capable of supporting security through this means as well. An administrator can apply two settings that affect the execution of troubleshooting packs. First, a policy can be set to restrict WTP from running at all. This essentially blocks all packs from being executed on computers governed by Group Policy. Second, an administrator can indicate a specific set of certificate authority in the trusted publisher store. Because each troubleshooting package must contain a security catalog that is signed by a certificate issued by a known authority, the package will execute only if the signing authority matches what the administrator specified in the trusted publisher store. For instance, an administrator can collect a set of troubleshooting packs, sign each with a known certificate, and set that certificate publisher in the trusted publisher store. Then use a Group Policy to distribute certificates to an organizational unit on a network.

The security measure mentioned above is simple to apply. The mechanics of each step is straightforward however one should understand the fundamentals of certificates, how cryptography works, and how PKI works to gain a well-rounded perspective with security in computing. One should also obtain the Windows SDK, which contains tools used to generate and sign the security catalog.

Taking a package that has been completed by the author; the first step is to generate the security catalog. To do this, create a text file and change the extension to .cdf, which stands for Catalog Definition File, for example AeroCatalog.cdf. The content structure of this file is similar to an INI file. There are two sections, [CatalogHeader] and [CatalogFiles], that separate the individual files from the overall catalog definition. In the [CatalogHeader] section, add a name-value pair to indicate the security catalog name. For a WTP troubleshooting pack, the name must be DiagPackage.cat. Public version and encoding type are also recommended to be specified. Then in the [CatalogFiles] section, one should look through all the files within the package root folder and specify an entry for each file. When this is complete, run the Makecat.exe with AeroCatalog.cdf as the argument. This will produce the security catalog file with name as indicated in the [CatalogHeader] section. The end result is the new DiagPackage.cat security catalog and the original AeroCatalog.cdf. The latter is not altered; it’s just the input to produce the security catalog. The final step is to sign the security catalog. As mentioned previously, the certificate used to sign the catalog must be one that chains up to the trusted root authority. Use the Signtool.exe to specify the certificate and the target security catalog. After this is done, the catalog is now ready to be included in the troubleshooting pack. Opening the security catalog file reveals two sections as well. The General section shows certificate information such as thumbprint, subject algorithm, etc. The Security Catalog shows a list of hash values corresponding to the files defined in the AeroCatalog.cdf. This is the catalog file that WTP will look for and enforce when a package is executed. A sample is shown below.

AeroDiagnosticCDF.jpg

AeroDiagnosticCDF1.jpg

Packaging and localized resources

With an overall understanding on how troubleshooting package can be made secure, the one area that hasn’t been discussed is language support and how security measure need to be applied to support periodic language pack releases. This scenario is common as software is typically shipped with a selective set of language support and publishers eventually release additional language packs as they are developed. In the case of troubleshooting package, this is likely the case for authors and publishers, as well. The how-to localize a troubleshooting package is covered in the next section. This section explains how to setup the troubleshooting package security, release the pack, and subsequently release additional language packs.

Recall that WTP will enforce security by verifying the troubleshooting package files against the security catalog. Even the number of files appearing in the catalog must match what’s listed in the security catalog. So how can a troubleshooting package work if additional language packs are added in the future? The way this works is through three key elements that one must apply in the troubleshooting package and each individual language pack.

Starting with the troubleshooting pack, the author must create a language-neutral resource file and specify that as the resource entry in the package security catalog. This entry should be entered in the .cdf file under the [CatalogFiles] section prior to running Makecat.exe. The language-neutral resource can optionally contain the base default text. With the MUI language support model, at least one locale resource must be present. Upon troubleshooting package execution, Windows will load the appropriate MUI resource. Depending on the current locale setting and the available MUI resources, Windows will employ a standard selection process and load the most appropriate resource. The language-neutral resource will not be used unless Windows determines there’s no appropriate MUI resource to load.

Authors will typically want to ship several key supported languages when releasing the troubleshooting pack. Assuming, for example, that English and French are the two key languages, the author would create the necessary resource files in the respective folders. When this is done, security measures will need to be applied in both the en-us and fr-fr folders. To do this, the author would follow the same steps and create a security catalog for each language. The key addition is that the author must include the troubleshooting package identifier as an entry in the [CatalogHeader] section before running the Makecat.exe and Signtool.exe. The package identifier is the unique value specified in the manifest file when the package was created. By indicating in each language security catalog, a bond is formed between the troubleshooting package and its associated language packs. WTP will verify when loading the language package that it is indeed a part of the troubleshooting package. And because the language security catalog need to be signed with the same certificate as the troubleshooting package security catalog, tampering will not be possible. This stringent security check eliminates rogue language packs from being accidentally loaded during execution and potentially causing harm.

Localization

Because troubleshooting packs involve two types of data, PowerShell scripts and manifest, there are two areas to consider for localization. The first are the strings presented to the user via the WTP Wizard. Examples include the troubleshooting package title and root cause descriptions. The second type of localized data is anything dynamically generated by the associated PowerShell scripts. This would include dynamic interactions, strings added to the diagnostic report, and any other strings found in the PowerShell script itself. For a localized troubleshooting pack, there will always be a localized manifest file, but localized strings in PowerShell scripts are optional.

Manifest localization

Assuming an English-only and non-localized language troubleshooting pack, strings declared in the manifest that are displayed to the user look something like the following.

<description>This is my single-language string</description>

For multilingual troubleshooting packs, the actual string above would be replaced with a string lookup instead. This lookup tells WTP which localized resource to look into and which specific string to retrieve. During execution, the process would pull the actual string from the correct language version of the dll.mui file at run time. For instance, if the above string was in the resource file AeroDiagnostic.dll with an identifier 100, the localized manifest will look like this.

<description>@AeroDiagnostic.dll,-100</description>

The minus sign before the resource index is intentional. This is a typical way to indicate the identifier in a resource file for the consuming parser to retrieve. The AeroDiagnostic.dll indicated here is the language-neutral resource file. The manifest specification for string lookup is always stated with reference to the language-neutral resource. The localized strings must reside in a dll.mui file, one for every supported language. During execution, the appropriate MUI file will be loaded and the text associated with the string identifier will be retrieved and displayed.

Script localization

Windows PowerShell version 2 uses .psd1 files to support localization. For each locale that the troubleshooting package supports, create a .psd1 file that contains language-specific strings and place each file in itslanguage-specific subfolder of the troubleshooting pack. To load localized strings from a .psd1 file to be used in a script, use the Import-LocalizedData cmdlet as shown in the following example.

Import-LocalizedData -bindingvariable localizationString -filename CL_LocalizationData

The localizationString variable could then be used to access the strings as shown in the following example, assuming that detection_progress is the identifier for a localized string in CL_LocalizationData.psd1 file.

Write-DiagProgress -Activity $localizationString.detection_progress

Files and folder structure

With the troubleshooting package content localized, the manifest and directory structure need to be set, as well. To specify that the package is localized, set the Localized attribute to “true”. This attribute can be found within the GlobalDiagnosticPackage or LocalDiagnosticPackage node in the manifest file. When this attribute is set to true, all UI string elements must be of the form "@resource.dll,-resourceID" (that is, they cannot be literal strings). WTP will load the strings from the language-specific resource DLL. If the package is a non-localized package, WTP reads the string directly from the manifest.

As mentioned in the packaging section, above, the troubleshooting pack's root folder must contain a language-neutral resource DLL and a language-specific subfolder for each locale that the package supports. The name of the subfolder must be the locale string (for example, en-us for English - United States). Each subfolder must contain the language-specific resource file (*.dll.mui). If the scripts in the package use localized strings, the subfolders must also include the PowerShell data file (*.psd1).

Each language-specific subfolder must contain a catalog file that describes all files in the folder. The language packs must be signed by the same publisher that signed the troubleshooting pack. WTP validates that all localized resources are trusted.

The name of the catalog file must use the same name as the subfolder that contains it. For example, if the subfolder is en-us, the catalog file must be named en-us.cat. Likewise, the catalog header must contain a PackageId attribute that is set to the value of the manifest's ID node. The following is an example of a .cdf file for a language pack. If there is localized script data, the .cdf file must also include an entry for the .psd1 file. When properly prepared as prescribed here, language packs can be distributed and installed separately from the troubleshooting pack.

[CatalogHeader]
Name=en-us.cat
PublicVersion=0x0000001
EncodingType=0x00010001
CATATTR1=0x10010001:OSAttr:2:6.1
CATATTR2=0x10010001:PackageId:AeroDiagnostic
[CatalogFiles]
<hash>resource.dll.mui=resource.dll.mui
<hash>resource.dll.muiATTR1=0x10010001:Filename:resource.dll.mui
<hash>en-us.cdf=en-us.cdf
<hash>en-us.cdfATTR1=0x10010001:Filename:en-us.cdf
Deployment

As mentioned in the packaging section, above, there are multiple ways to package and describe the contents of a troubleshooting pack, the cabinet format (that is, the diagcab extension), and the troubleshoot package folder structure. This section describes the various ways to get each of these to the end user’s computer. The goal is to allow the end user to run the troubleshooting package from their computer.

Folder structure represents one of the least complicated methods of deploying a troubleshooting package because the deployment involves only making sure the user can access the directory. This can be over a network share or copied via a USB drive. One can take this even further by compressing and bundling into a single file (for example, zip) and have the user download and expand to a directory of their choosing. Regardless of method, after the user has access to the directory, she can issue the following command to launch the WTP Wizard.

msdt.exe /path <path to the directory>

Likewise, the WTP cmdlets can also be used to invoke the package as explained in section Command-line administration.

Cabinet files (.diagcab files) represent a more flexible way to deploy troubleshooting packs. As mentioned in the packaging section, these files are self-contained representations of the diagnostic directory structure that are recognized by Windows as a troubleshooting pack. As such they can be double-clicked or run directly from a Web page or SharePoint site, without the user having to invoke msdt.exe.

This makes them easier to run but limits them to graphical execution because .diagcab files cannot be passed to Get-TroubleshootingPack or Invoke-TroubleshootingPack. Cabinet files can be hosted on a SharePoint site, Web page, network share, or directly on the user’s computer. They will all run in the same way when the user opens the file.

Windows SDK tools such as expand.exe can be used to unpack a .diagcab file, which essentially turns into a folder structure and allows one to then use the WTP cmdlet to execute.

Additional Resources

See Also

Windows Troubleshooting Platform

Windows SDK

Windows PowerShell Programmer’s Guide

Sample Code Listing
<?xml version="1.0" encoding="utf-8"?><dcmPS:DiagnosticPackage xmlns:dcmPS="https://www.microsoft.com/schemas/dcm/package/2007" xmlns:dcmRS="https://www.microsoft.com/schemas/dcm/resource/2007" SchemaVersion="1.0" Localized="true">
    <DiagnosticIdentification>
        <ID>AeroDiagnostic</ID>
        <Version>1.0</Version>
    </DiagnosticIdentification>
    <DisplayInformation>
        <Parameters/>
        <Name>@AeroDiagnostic.dll,-1</Name>
        <Description>@AeroDiagnostic.dll,-2</Description>
    </DisplayInformation>
    <PrivacyLink>https://go.microsoft.com/fwlink/?LinkId=104288</PrivacyLink>
    <PowerShellVersion>2.0</PowerShellVersion>
    <SupportedOSVersion clientSupported="true" serverSupported="true">6.1</SupportedOSVersion>
  <Troubleshooter>
    <Script>
      <Parameters/>
      <ProcessArchitecture>Any</ProcessArchitecture>
      <RequiresElevation>true</RequiresElevation>
      <RequiresInteractivity>false</RequiresInteractivity>
      <FileName>MF_AeroDiagnostic.ps1</FileName>
      <ExtensionPoint/>
    </Script>
    <ExtensionPoint/>
  </Troubleshooter>
  <Rootcauses>
        <Rootcause>
            <ID>RC_WddmDriver</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>@AeroDiagnostic.dll,-23</Name>
                <Description>@AeroDiagnostic.dll,-24</Description>
            </DisplayInformation>
            <Resolvers>
                <Resolver>
                    <ID>RS_WddmDriver</ID>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>@AeroDiagnostic.dll,-25</Name>
                        <Description>@AeroDiagnostic.dll,-26</Description>
                    </DisplayInformation>
                    <RequiresConsent>false</RequiresConsent>
                    <Script/>
                  <ExtensionPoint>
                    <Link>mshelp://Windows/?id=b3c6477e-1111-4b9f-a52a-fffdc51e9c90</Link>
                  </ExtensionPoint>
                </Resolver>
            </Resolvers>
            <Verifier>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>false</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>TS_WddmDriver.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Verifier>
            <ContextParameters/>
            <ExtensionPoint/>
        </Rootcause>
        <Rootcause>
            <ID>RC_DwmService</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>@AeroDiagnostic.dll,-3</Name>
                <Description>@AeroDiagnostic.dll,-4</Description>
            </DisplayInformation>
            <Resolvers>
                <Resolver>
                    <ID>RS_DwmService</ID>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>@AeroDiagnostic.dll,-5</Name>
                        <Description>@AeroDiagnostic.dll,-6</Description>
                    </DisplayInformation>
                    <RequiresConsent>false</RequiresConsent>
                    <Script>
                        <Parameters/>
                        <ProcessArchitecture>Any</ProcessArchitecture>
                        <RequiresElevation>true</RequiresElevation>
                        <RequiresInteractivity>false</RequiresInteractivity>
                        <FileName>RS_DwmService.ps1</FileName>
                        <ExtensionPoint/>
                    </Script>
                    <ExtensionPoint/>
                </Resolver>
            </Resolvers>
            <Verifier>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>false</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>TS_DwmService.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Verifier>
            <ContextParameters/>
            <ExtensionPoint/>
        </Rootcause>
        <Rootcause>
            <ID>RC_DesktopComposition</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>@AeroDiagnostic.dll,-7</Name>
                <Description>@AeroDiagnostic.dll,-10</Description>
            </DisplayInformation>
            <Resolvers>
                <Resolver>
                    <ID>RS_DesktopComposition</ID>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>@AeroDiagnostic.dll,-8</Name>
                        <Description>@AeroDiagnostic.dll,-9</Description>
                    </DisplayInformation>
                    <RequiresConsent>true</RequiresConsent>
                    <Script>
                        <Parameters/>
                        <ProcessArchitecture>Any</ProcessArchitecture>
                        <RequiresElevation>true</RequiresElevation>
                        <RequiresInteractivity>false</RequiresInteractivity>
                        <FileName>RS_DesktopComposition.ps1</FileName>
                        <ExtensionPoint/>
                    </Script>
                    <ExtensionPoint/>
                </Resolver>
            </Resolvers>
            <Verifier>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>false</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>TS_DesktopComposition.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Verifier>
            <ContextParameters/>
            <ExtensionPoint/>
        </Rootcause>
        <Rootcause>
            <ID>RC_Theme</ID>
            <DisplayInformation>
                <Parameters/>
                <Name>@AeroDiagnostic.dll,-11</Name>
                <Description>@AeroDiagnostic.dll,-12</Description>
            </DisplayInformation>
            <Resolvers>
                <Resolver>
                    <ID>RS_Theme</ID>
                    <DisplayInformation>
                        <Parameters/>
                        <Name>@AeroDiagnostic.dll,-13</Name>
                        <Description>@AeroDiagnostic.dll,-22</Description>
                    </DisplayInformation>
                    <RequiresConsent>true</RequiresConsent>
                    <Script>
                      <Parameters>
                        <Parameter>
                          <Name>ServiceName</Name>
                          <DefaultValue/>
                        </Parameter>
                      </Parameters>
                        <ProcessArchitecture>Any</ProcessArchitecture>
                        <RequiresElevation>true</RequiresElevation>
                        <RequiresInteractivity>true</RequiresInteractivity>
                        <FileName>RS_Theme.ps1</FileName>
                        <ExtensionPoint/>
                    </Script>
                    <ExtensionPoint>
                    </ExtensionPoint>
                </Resolver>
            </Resolvers>
            <Verifier>
                <Script>
                    <Parameters/>
                    <ProcessArchitecture>Any</ProcessArchitecture>
                    <RequiresElevation>false</RequiresElevation>
                    <RequiresInteractivity>false</RequiresInteractivity>
                    <FileName>TS_Theme.ps1</FileName>
                    <ExtensionPoint/>
                </Script>
                <ExtensionPoint/>
            </Verifier>
            <ContextParameters/>
            <ExtensionPoint/>
        </Rootcause>
    </Rootcauses>
    <Interactions>
        <SingleResponseInteractions>
            <SingleResponseInteraction>
                <AllowDynamicResponses>false</AllowDynamicResponses>
                <Choices>
                    <Choice>
                        <DisplayInformation>
                            <Parameters/>
                            <Name>@AeroDiagnostic.dll,-15</Name>
                            <Description>@AeroDiagnostic.dll,-18</Description>
                        </DisplayInformation>
                        <Value>aero</Value>
                        <ExtensionPoint/>
                    </Choice>
                    <Choice>
                        <DisplayInformation>
                            <Parameters/>
                            <Name>@AeroDiagnostic.dll,-16</Name>
                            <Description>@AeroDiagnostic.dll,-19</Description>
                        </DisplayInformation>
                        <Value>nature</Value>
                        <ExtensionPoint/>
                    </Choice>
                    <Choice>
                        <DisplayInformation>
                            <Parameters/>
                            <Name>@AeroDiagnostic.dll,-17</Name>
                            <Description>@AeroDiagnostic.dll,-20</Description>
                        </DisplayInformation>
                        <Value>landscape</Value>
                        <ExtensionPoint/>
                    </Choice>
                </Choices>
                <ID>IT_Theme</ID>
                <DisplayInformation>
                    <Parameters/>
                    <Name>@AeroDiagnostic.dll,-14</Name>
                    <Description>@AeroDiagnostic.dll,-21</Description>
                </DisplayInformation>
                <ContextParameters/>
                <ExtensionPoint>
                    <CommandLinks/>
                </ExtensionPoint>
            </SingleResponseInteraction>
        </SingleResponseInteractions>
        <MultipleResponseInteractions/>
        <TextInteractions/>
        <PauseInteractions/>
        <LaunchUIInteractions/>
    </Interactions>
    <ExtensionPoint></ExtensionPoint>
</dcmPS:DiagnosticPackage>
# This script represents the controller for detection logics runtime flow in the Aero
# diagnostic Windows Troubleshooting package. This script is referenced in the Aero
# diagnostic manifest in the Troubleshooter node outside of the Rootcauses node.
# The primary function of global troubleshooter is to control the sequence execution
# of root cause detections. Here, the illustration is to test for WDDM driver first.
# If it turns out there's no WDDM driver, then there's no point continuing other detections.
# Utility function to run a script
function RunDiagnosticScript([string]$scriptPath = $(throw "No diagnostic script is specified")) {
    if(-not (Test-Path $scriptPath)) {
        throw "Can't find diagnostic script"
    }
    $result = &($scriptPath)
    if($result -is [bool]) {
        return [bool]$result
    } else {
        return $false
    }
}
if((RunDiagnosticScript .\TS_WddmDriver.ps1) -eq $false) {
    return
}
RunDiagnosticScript .\TS_DwmService.ps1
RunDiagnosticScript .\TS_DesktopComposition.ps1
RunDiagnosticScript .\TS_Theme.ps1

# This script represents the detection logic for the WDDM driver root cause
# in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_WddmDriver'.
# The primary logic here is to run the Windows System Assessment Tool (WinSat.exe)
# and look into the output file for LDDM setting equals 1. Root cause detected means
# LDDM is not set and therefore indicates the absence of WDDM driver. Call
# Update-DiagRootCause cmdlet to indicate whether this root cause has been detected.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# The identifier for this root cause
[string]$RootCauseID = "RC_WddmDriver"
# Inform user the current troubleshooting progress
Write-DiagProgress -activity $localizationString.wddm_progress
# Function to execute Windows System Assessment Tool
function GetAssessmentFile()
{
       [string]$featureFileName = "features.xml"
       [string]$systemPath = [System.Environment]::SystemDirectory
    [string]$winSatCmd = Join-Path $systemPath "WinSat.exe"
    & $winSatCmd features -xml $featureFileName | Out-Null
    return (Resolve-Path ".\$featureFileName").Path
}
# Run WinSAT and retrieve the output file content
[string]$fileName = GetAssessmentFile
if($fileName -eq $null)
{
    throw "Can't find assessment file"
}
[XML]$winsatData = Get-Content $fileName
# Look into file content and check the graphics card has WDDM driver
[bool]$RootCauseDetected = ([int]$winsatData.WinSAT.SystemConfig.Graphics.LDDM -ne 1)
# Inform WTP of the status of this root cause
Update-DiagRootCause -id $RootCauseID -Detected $RootCauseDetected
# Return the opposite of $RootCauseDetected to reflect problem state.
# True means this root cause was not detected.
return (-not($RootCauseDetected))

# This script represents the detection logic for the 'Desktop Window Manager' service
# root cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_DwmService'.
# The primary logic here is to detect whether UXSMS service is running. Upon retrieving
# the service status, this script will communicate with WTP engine via the
# Update-DiagRootCause cmdlet to indicate whether this root cause has been detected.
# If UXSMS service is not running, hence root cause detected, WTP will then invoke the
# associated resolver(s) defined in the manifest for this root cause.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -Activity $localizationString.dwmservice_progress
# The root cause identifier this detection script is a part of
[string]$RootCauseID = "RC_DwmService"
# Detect whether UXSMS service is currently running
[bool]$RootCauseDetected = ($(Get-Service "uxsms").status -ne [ServiceProcess.ServiceControllerStatus]::Running)
# Inform WTP of the status of this root cause
Update-DiagRootCause -id $RootCauseId -detected $RootCauseDetected

# This script represents the detection logic for the 'Desktop Composition'
# root cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_DesktopComposition'.
# The primary logic here is to detect the dwm.exe process and the desktop composition
# registry key value. In addition, two WTP constructs are included to illustrate concept,
# usage, and the effect. The first is the inclusion of emitting progress text when
# processing this particular root cause detection. The second is adding information
# specific to this detection logic to the output report. Just as in TS_DwmService.ps1
# detection script, Update-DiagRootCause cmdlet will be called to inform WTP the detection
# status of this root cause.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -Activity $localizationString.composition_progress
# The root cause identifier this detection script is a part of
[string]$RootCauseID = "RC_DesktopComposition"
# Function to look for and retrieve the specified process per current user context
function GetProcessForCurrentUser([string]$processName=$(throw "No process name is specified."))
{
     return Get-WmiObject Win32_Process | Where {($_.ProcessName -ieq $processName)  `
                                         -and ($_.GetOwner().User -ieq $Env:UserName) `
                                         -and ($_.GetOwner().Domain -ieq $Env:UserDomain)}
}
# Get DWM-related events from the past week for troubleshooting report
$dwmEvents = Get-WinEvent -FilterHashTable @{ProviderName="Microsoft-Windows-WindowsSystemAssessmentTool"; `
                                         StartTime=[DateTime]::Today.AddDays(-7)} | Where {$_.Message.contains("DWM")}
# Convert the retrieved DWM-related events to XML and write to WTP report
$dwmEvents | ConvertTo-Xml | Update-DiagReport -id DesktopWindowManagerEvents `
                                              -name $localizationString.dwmEventName `
                                              -description $localizationString.dwmEventDesc
# Retrieve the desktop composition value. This root cause is detected if DWM process is not present and composition not set to 1
[string]$compositionRegValue = (Get-ItemProperty("HKCU:\software\Microsoft\Windows\DWM")).Composition
[bool]$RootCauseDetected = (((GetProcessForCurrentUser "dwm.exe") -eq $null) -or ($compositionRegValue -ne 1))
# Inform WTP of the status of this root cause
Update-DiagRootCause -id $RootCauseID -detected $RootCauseDetected

# This script represents the detection logic for the 'Themes' service
# root cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_Theme'.
# The primary logic here is to detect whether Themes service is running.
# Update-DiagRootCause cmdlet will be called to inform WTP the detection
# status of this root cause.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -Activity $localizationString.theme_progress
# The root cause identifier this detection script is a part of
[string]$RootCauseID = "RC_Theme"
# Detect whether the Theme service is running
[string]$serviceName = "Themes"
[bool]$RootCauseDetected = ((Get-Service $serviceName).status -ne [ServiceProcess.ServiceControllerStatus]::Running)
# Inform WTP of the status of this root cause
Update-DiagRootCause -id $RootCauseID -detected $RootCauseDetected -parameter @{"ServiceName"="$serviceName"}

# This script represents a resoluton logic for the 'Desktop Window Manager' service
# root cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_DwmService'.
# The primary logic here is to start the UXSMS service. Upon starting the service,
# wait for the service to reflect a running status. Note, the verification for this
# root cause will again use the detection script 'TS_DwmService.ps1' to verify
# UXSMS is running.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Include file containing utility functions
. .\CL_Utility.ps1
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -activity $localizationString.dwmResolve_progress
# Start Desktop Window Manager service
[string]$serviceName = "uxsms"
start-service $serviceName
WaitFor-ServiceStatus $serviceName ([ServiceProcess.ServiceControllerStatus]::Running)

# This script represents a resoluton logic for the 'Desktop Composition' root
# cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_DesktopComposition'.
# The primary logic here is to set the desktop composition value in the registry and
# then start the UXSMS service. The registry checks are simply good practice. Upon
# starting the service, wait for the service to reflect a running status, or timeout
# at 5 seconds, which ever comes first. Note, the verification for this root cause will again use the
# detection script 'TS_DesktopComposition.ps1' to verify composition value.
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Include file containing utility functions
. .\CL_Utility.ps1
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -activity $localizationString.compositionResolve_progress
# Registry path to desktop composition value
[string]$desktopCompositionKey = "HKCU:\software\Microsoft\Windows\DWM"
# Set the desktop composition to correct value
if(-not(Test-Path $desktopCompositionKey )) {
    New-Item -Path $desktopCompositionKey
}
if((Get-ItemProperty $desktopCompositionKey "Composition") -eq $null) {
    New-ItemProperty -Path $desktopCompositionKey -Name "Composition" -PropertyType DWORD -Value 1
} else {
    Set-ItemProperty $desktopCompositionKey "Composition" 1
}
# Restart the Desktop Window Manager service
[string]$serviceName = "uxsms"
Restart-Service @serviceName
WaitFor-ServiceStatus $serviceName ([ServiceProcess.ServiceControllerStatus]::Running)

# This script represents a resoluton logic for the 'Themes' service
# root cause in the Aero diagnostic Windows Troubleshooting package. This script is
# referenced in the Aero diagnostic manifest under the root cause 'RC_Theme'.
# The primary logic here is to start a single response interaction via Get-DiagInput,
# which when this troubleshooting pack is invoked via MSDT.exe, a wizard screen will
# appear with choices of themes as defined in the manifest. Upon retrieving the user
# theme choice, start the Themes service and compose a command to control.exe which
# will set the Aero theme reflecting the user choice.
PARAM($serviceName)
# Load localized text
Import-LocalizedData -BindingVariable localizationString -FileName CL_LocalizationData
# Include file containing utility functions
. .\CL_Utility.ps1
# Emit the following text to convey to user the progress of Aero diagnostic
Write-DiagProgress -Activity $localizationString.themeResolve_progress
# Start an interaction as defined by IT_Theme in manifest. Have user pick a theme
[string]$theme = Get-DiagInput -id "IT_Theme"
# Start the Themes service
Start-Service $serviceName
WaitFor-ServiceStatus $serviceName ([ServiceProcess.ServiceControllerStatus]::Running)
# Set the desktop theme to reflect user selection
$controlArgs = `
    "/name Microsoft.Personalization " `
    + "/page ?Theme=" + $Env:SystemDrive[0] + "%3A%5CWindows%5CResources%5CThemes%5C" + $theme + ".theme"
& control.exe $controlArgs.split(" ")

# Function to wait for expected service status
function WaitFor-ServiceStatus([string]$serviceName=$(throw "No service name is specified"), [ServiceProcess.ServiceControllerStatus]$serviceStatus=$(throw "No service status is specified"))
{
    [ServiceProcess.ServiceController]$sc = New-Object "ServiceProcess.ServiceController" $serviceName
    [TimeSpan]$timeOut = New-Object TimeSpan(0,0,0,5,0)
    $sc.WaitForStatus($serviceStatus, $timeOut)
}

# Localized   text for usage in Aero diagnostic detection and resolution scripts
ConvertFrom-StringData @'
###PSLOC
wddm_progress=Checking video card driver settings...
theme_progress=Checking themes service...
dwmservice_progress=Checking desktop window manager service...
composition_progress=Determining whether desktop window manager is running and checking composition setting...
dwmEventName=Desktop Window Manager Events
dwmEventDesc=Recent events generated by the System Assessment Tool pertaining to the Desktop Window Manager
wddmResolve_progress=Contact manufacturer
themeResolve_progress=Set theme and start theme service
dwmResolve_progress=Restarting desktop window manager service
compositionResolve_progress=Enabling desktop composition and restarting desktop window manager service
###PSLOC
'@

[CatalogHeader]
Name=DiagPackage.cat
PublicVersion=0x0000001
EncodingType=0x00010001
CATATTR1=0x10010001:OSAttr:2:6.1
[CatalogFiles]
<hash>AeroDiagnostic.diagpkg=AeroDiagnostic.diagpkg
<hash>AeroDiagnostic.diagpkgATTR1=0x10010001:Filename:AeroDiagnostic.diagpkg
<hash>AeroDiagnostic.dll=AeroDiagnostic.dll
<hash>AeroDiagnostic.dllATTR1=0x10010001:Filename:AeroDiagnostic.dll
<hash>CL_Utility.ps1=CL_Utility.ps1
<hash>CL_Utility.ps1ATTR1=0x10010001:Filename:CL_Utility.ps1
<hash>MF_AeroDiagnostic.ps1=MF_AeroDiagnostic.ps1
<hash>MF_AeroDiagnostic.ps1ATTR1=0x10010001:Filename:MF_AeroDiagnostic.ps1
<hash>RS_DesktopComposition.ps1=RS_DesktopComposition.ps1
<hash>RS_DesktopComposition.ps1ATTR1=0x10010001:Filename:RS_DesktopComposition.ps1
<hash>RS_DwmService.ps1=RS_DwmService.ps1
<hash>RS_DwmService.ps1ATTR1=0x10010001:Filename:RS_DwmService.ps1
<hash>RS_Theme.ps1=RS_Theme.ps1
<hash>RS_Theme.ps1ATTR1=0x10010001:Filename:RS_Theme.ps1
<hash>TS_DesktopComposition.ps1=TS_DesktopComposition.ps1
<hash>TS_DesktopComposition.ps1ATTR1=0x10010001:Filename:TS_DesktopComposition.ps1
<hash>TS_DwmService.ps1=TS_DwmService.ps1
<hash>TS_DwmService.ps1ATTR1=0x10010001:Filename:TS_DwmService.ps1
<hash>TS_Theme.ps1=TS_Theme.ps1
<hash>TS_Theme.ps1ATTR1=0x10010001:Filename:TS_Theme.ps1
<hash>TS_WddmDriver.ps1=TS_WddmDriver.ps1
<hash>TS_WddmDriver.ps1ATTR1=0x10010001:Filename:TS_WddmDriver.ps1