Welcome to TechNet Blogs Sign in | Join | Help

(Virtually) Everything You Need to Know About Hyper-V

Following on from my post last year on general virtualisation resources, here is a similar one just for Hyper-V.  Enjoy!

Note:  Thanks to my colleague, Tushar, who sent some of these links around to our team recently.

Official Hyper-V Web Sites

Hyper-V Homepage

Hyper-V TechCenter

Getting Started with Hyper-V

Top Ten Reasons to Adopt Hyper-V (.docx)

Key Hyper-V Features

Hyper-V FAQ

Hyper-V Release Notes

Hyper-V Step-by-Step Guide: Getting Started

Hyper-V Documents and Articles

Windows Server 2008 Hyper-V Technical Overview (.docx)

Hyper-V Step-by-Step Guide: Testing Hyper-V and Failover Clustering

Solution Accelerator Guide: Windows Server Virtualization

Solution Accelerator Guide: Selecting the Right Virtualization Technology

Microsoft Assessment and Planning Tool

Virtualization and Consolidation with Hyper-V

Hyper-V Installed Help

Quick Migration with Hyper-V (.doc)

Windows Server 2008 Hyper-V and BitLocker Drive Encryption (.docx)

Configuring Hyper-V for Windows Essential Business Server (.pdf)

Virtualisation and Licensing

Windows Server System Licensing for Virtualization Scenarios

Licensing without Hyper-V

Your Ultimate Quick Reference Resource for Licensing and Pricing (.pdf)

Hyper-V Programming and Scripting

Virtualization WMI Provider

Hyper-V Training and Webcasts

Webcasts

Implementing and Managing Windows Server 2008 Hyper-V

Exam 70-652: Windows Server Virtualization, Configuring

Hyper-V Related Blogs

Virtual PC Guy's WebLog

John Howard - Hyper-V and virtualization blog

Rob Larson's blog

Virtual Varia

Virtualisation Team Blog

Miscellaneous

Hyper-V Capable Server Hardware

Hyper-V Discussion Forum

Virtualisation Solution Center

Windows Server 2008 Hyper-V Resource Kit

Performance Tuning Guidelines for Windows Server 2008

System Center Virtual Machine Manager

Windows Server 2008 Evaluation Virtual Hard Drive Images (for Hyper-V)

Msdn Technet Powered By Hyper V (.docx)

Infrastructure Planning and Design

Windows Server Virtualization Technologies

Hyper-V Knowledge Base Articles

949222 - Virtual machines that were created on the beta version of the Hyper-V role do not start after the Hyper-V role is updated to a later version

950050 - Description of the update for the release version of the Hyper-V technology for Windows Server 2008

950792 - When you try to enable, disable, or update Hyper-V technology, the process stops responding

951636 - Description of the Hyper-V Language Pack for Windows Server 2008

952627 - Description of the Windows Vista Service Pack 1 Management Tools update for the release version of Hyper-V

953828 - The NLB host does not converge as expected on Windows Server 2008 Hyper-V virtual machines

954279 - You are not prompted for credentials after you receive an "Access Denied" error message when you try to connect to a virtual machine from the Windows Server 2008 Hyper-V MMC snap-in

954280 - Error message when you try to export a virtual machine on a Windows Server 2008-based computer that uses Hyper-V: "An error occurred while attempting to export the virtual machine"

954281 - After you install Windows 2000 on a virtual machine that is running on a Windows Server 2008-based computer that uses Hyper-V technology, you can only create a maximum startup disk that is 127 GB

954282 - The VMBus device does not load on a virtual machine that is running on a Windows Server 2008-based computer that has Hyper-V installed

954283 - You experience issues after you install Windows Server 2008 Hyper-V Integration Services on a Vista Home Premium virtual machine or a Vista Home Basic virtual machine

954356 - After you deploy a Sysprep prepared image, the Hypervisor layer service does not start automatically in Windows Server 2008

954357 - Error message when you use Vmconnect.exe to connect to a virtual machine in Windows Server 2008: "A connection will not be made because credentials may not be sent to the remote computer."

954358 - Virtual Hard Disk (.vhd file) contents may be accessed by all users after you mount the file as a loopback device in Windows Server 2008

954958 - Guest operating systems that are supported on a Hyper-V virtual machine host

Vista, Server 2008 and the Case of the Bitlocker Dual Boot

This week, I received my shiny new work laptop, which I'd been anticipating for some time.  Normally, I'm not much of a hardware geek and don't get overly excited with new kit, but I was really looking forward to this as it is 64-bit and finally allows me to install Server 2008 and Hyper-V for customer demos, testing, etc.

Although I wanted to use Server 2008, I still wanted Vista as my day-to-day desktop for email and the like, so I planned to dual boot with a shared data partition.  However, as I sometimes have sensitive documents on my laptop I wanted to use Bitlocker to secure everything.

At first I wasn't sure what would happen if I just booted to Vista or Server 2008 and Bitlockered all of the drives.  Would the system boot at all?  Would I lose access to one or both operating systems?  What about the shared data?

As it turns out, this dual-boot scenario is no problem for Bitlocker.  In case you're faced with a similar scenario, here's how I installed mine:

  1. Installed Vista Ultimate SP1 to C: partition.  Vista Enterprise also supports Bitlocker.
  2. Installed Server 2008 Enterprise on D: partition.
  3. Created data partition E:.
  4. Created a small partition, S:, for the unencrypted boot files.  You can do this manually with Disk Manager or you can use the Bitlocker Drive Preparation Tool (also available as an Ultimate Extra).
  5. Booted into Vista and applied Bitlocker to the C: drive, saving the recovery key to a USB drive and setting a boot PIN.
  6. Booted into Server 2008 and applied Bitlocker to D:, saving the recovery key to a USB drive and setting a boot PIN.  The PIN is not shared across the two operating systems, but you can use the same number for both.

At this point both operating systems are protected by Bitlocker, both boot fine (using the appropriate PIN) and both can access the unencrypted data partition E:.  However, they cannot access each other's partition.  Next, to protect E: and make it accessible to both operating systems, I did this:

  1. Booted into Vista and applied Bitlocker to the E: partition, saving the recovery key to a USB drive.
  2. Booted into Server 2008, where E: is now inaccessible.
  3. Started the Bitlocker Drive Encryption tool and selected the "Unlock Volume" option for E:
  4. Selected to load the volume recovery key from removable media when prompted and inserted the USB drive.
  5. Selected the "Save key..." option and unlocked the partition.

Now, partitions C:, D: and E: are all protected by Bitlocker and each OS can boot without problem and can access the shared E: drive without any need to enter the recovery key.  I deliberately left it so that each OS still can't see the other's install partition, so as to avoid accidental changes, but using the "unlock" method above it would be possible to make all drives accessible under each OS.

There is possibly a neater way of doing this, but apart from waiting for the encryption steps to complete it was all very quick and painless.

A couple of notes:

  • I used a new system with clean installs of Vista and Server 2008, so if things had gone wrong all I'd have lost is a bit of my time.  If you do this on an existing system, please remember to back up your data first - I'm sure everything will be fine, but you never know ...
  • If you follow the method above you will end up with a USB drive with all of your recovery keys on it.  Remember to keep this in a safe place away from your computer (e.g. don't leave it in your bag with your laptop).
  • If you're interested in dual-booting with an OS that doesn't support Bitlocker, have a look here.
  • Above, I assume you know how to turn on Bitlocker, but if you don't, you can find details in the Windows BitLocker Drive Encryption Step-by-Step Guide.

Manipulating Performance Monitor Logs

If you need to monitor or troubleshoot performance problems on a Windows system, chances are you'll simply fire up PerfMon,  log some data to a file, which you later load in PerfMon for analysis.  This is great and is often all that you need, but it's a bit of a passive use of the log and gives the impression that if you make a mistake in your selections at the start you're stuck with it.  What if you didn't gather the data and the log you're given contains counters you don't need, or is too big to use easily, or you're only interested in a short period of the logging interval?  What can you do?  As it turns out there is quite a bit you can do.  The little-known, but highly-useful, Relog.exe tool can perform some clever manipulation once you have your log, allowing you to focus your troubleshooting a bit more (or at least make it a bit easier). 

Relog is built-in for Windows XP and later, and is available to download for Windows 2000. Here are some things it can do:

 

Converting Logs to Different Formats

The default log format for performance logs is Binary (.blg) and you usually just want to leave it that way as PerfMon can read it just fine.  However, what if you wanted to use another tool (Excel, for example) to analyse the data and the tool doesn't understand binary files?  Relog allows you to take an existing log in, say, .blg format and generate a new file in, say, Comma Separated Value (.csv) format:

Relog OriginalLog.blg -f CSV -o NewLog.csv

This command takes OriginalLog.blg and creates NewLog.csv from it, with this new log containing all of the same datapoints as the original.  You can convert between .blg, .csv, Tab Separated Value (.tsv), and .sql formats.

 

Resampling the Data

When creating a log file one of the parameters you need to set is the sample interval.  You should set this according to the nature of the troubleshooting or monitoring you're doing, so, for example, you would not set the same sample interval on logs that will run for 3 weeks as you would for one that runs for 3 hours.  However, you can still end up with some unwieldy log files, which are a pain to view in PerfMon.  Relog allows you to resample the data, generating a new log file containing every n-th datapoint.  For example, this command will take OriginalLog.blg and generate NewLog.blg, which contains every 5-th datapoint:

Relog OriginalLog.blg -t 5 -o NewLog.blg

Clearly, you are discarding information here and care needs to be taken or you may end up missing something important from the new dataset - for example, if you originally sampled every 60 seconds, but change this to the equivalent of every 30 minutes, you are likely to miss a transient problem that lasts 5 minutes.  However, this isn't really any worse than if you'd set the sample interval differently in the first place, so better to select the correct interval before logging begins.

If you don't want to lose data, but know that the problem your investigating happened mid-way through the logging period, then you can create a new log of just the datapoints in a given time window.  For example, if we have a log that ran between Midnight on 3rd March to Midnight on 10th Match, we can extract the data for 5th and 6th March using this command:

Relog OriginalLog.blg -b 05/03/2008 00:00:00 -e 06/03/2008 00:00:00 -o NewLog.blg

Relog does its best to match the times specified, but if these do not correspond to specific sample times, then it chooses the closest ones.

 

Extracting Specific Counters

As an alternative to the above approach of re-sampling the datapoints, you can split your log file into multiple files, each with all the datapoints, but with a subset of the original counters.  For example, the following command will take all of the Memory-related counters from OriginalLog.blg and copy them to NewLog.blg:

Relog OriginalLog.blg -c "\Memory\*" -o NewLog.blg

If you need to do more complex filtering of the counters, then you can list the counters you want in a text file and pass the path to Relog:

Relog Original.blg -cf CounterList.txt -o NewLog.blg

The counter list is specified with a single counter per-line.  For example:

\Memory\Pool Paged Bytes
\Process(*)\Pool Paged Bytes
\Process(*)\Handle Count
\Thread(Explorer*)\% Processor Time
 

 

Merging Logs

If you have several logs you've split out as described above and would like to re-combine two or more of them, say for easier comparison in PerfMon, then Relog can do this as follows:

Relog SeparateLog11.blg SeparateLog2.blg -o CombinedLog.blg

This takes SeparateLog1.blg and combines it with SeparateLog2.blg and writes the result to CombinedLog.blg.  You can do this for more than two logs, but all of them must be in .blg format.

 

Combining Actions

It is possible to combine some of the actions mentioned above in a single command.  For example:

Resample and convert log type

To convert from .blg to .csv and copy only every 10th datapoint, us this command:

     Relog OriginalLog.blg -f CSV -t 10 -o NewLog.csv

 

Extract Counters, Change Time Window and Resample

To extract every 5th datapoint for just the Memory counters from 5-6th March, use this command:

     Relog OriginalLog.blg -b 05/03/2008 00:00:00 -e 06/03/2008 00:00:00 -c "\Memory\*" -t 5 -o NewLog.blg 

 

Obviously, analysing the data after you've played around with it is the critical part, and that's beyond the scope of a simple blog post, but to get you started, here are a few resources that you might find useful:

Performance Analysis of Logs (PAL) .   PAL automates the analysis of the logs by applying specified thresholds (supplied) to the data, generating reports with details of what it found.

Windows Performance Guide.  Part of the Server 2003 Resource Kit, this is the place to read up on performance analysis.

Performance Tuning Guidelines for Windows Server 2003.  Provides guidance on parameter to tweak in order to maximise performance in Server 2003.

Performance Tuning Guidelines for Windows Server 2008.  Server 2008 equivalent of the guide mentioned above.

Viewing Your MSDN Product Keys Off-Line

If you have an MSDN subscription, then you'll know that the subscription includes a set of product keys for use with the versions of Office, Windows, etc that your subscription gives you access to.  The keys can be viewed on-line at the MSDN subscriber site, but this isn't great if you don't have any network access, and even then it's not all that convenient to have to log on each time to get a key.

Now, there is an option to export your keys to an XML file, which means you can have them available off-line.  However, XML isn't the most user-friendly format:

Capture

Admittedly, XML is great for developers looking for a nice file format to store data in and MSDN subscribers you would assume are developers, but you really don't want to have to write a script or app to read the keys.  So, to save you the trouble I wrote a simple tool, KeyView.exe, that loads the XML file and displays the keys in a more useful format:

Capture2

Download KeyView as a Visual Studio 2008 project here (get VS 2008 from the MSDN download site):

KeyView C# Code Download  [Updated: 15 March 2008]

Note: you may need to install .NET Framework 3.5 to make KeyView work.

Once compiled, to get KeyView to work, you simply need to export your keys from the MSDN site to a file called MSDNkeys.xml in the same folder as KeyView and it will load the data automatically when it's launched.  Alternatively you can browse to the file if it's stored, say, on a network share.  Also, if you need to, KeyView allows you to export the data to CSV format.

Yes, yes, not the most useful tool in the world, but I was bored one evening while stuck in a hotel on a business trip!

Forcing Theme Settings in Windows Vista

Recently I was working with a customer to find a way to automate forcing a specific Aero theme in Windows Vista.  The idea was to have the Vista clients "colour-coded" according to their use; so whenever a user logs on the window border colour would indicate the type of system (which was actually based on security levels).  So, for example, if a user logs onto a public terminal with more relaxed browsing settings, the window borders should be red as a reminder the system is less secure, a more secure system might have blue border.

 

Unfortunately there isn't any public API or scripting interface for this, nor a GPO setting - the only "theme" GPO setting relates to deploying a specific "style" (stored in an 'msstyles' file), which is not the same as the theme (stored in a 'theme' file).

 

After some work we devised the workaround below.  This isn't ideal, by any means, but does the job.  I thought I'd blog about it in case it's useful to anyone in a similar situation.  The usual caveats apply about hacking the registry, etc.  While this seems to work for the moment, there's no guarantee that a future update may change the behaviour. 

 

We created these two Aero-based themes:

red  

Red.theme - for non-secure systems

 

blue

Blue.theme - for secure systems

 

To forcibly apply these at logon we: 

  •  Copied the .theme files to a location on the local disk of the target system
  • Changed the "InstallTheme" value in the following registry key to point to the full path of the specifice .theme file:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes

NOTE: A custom ADM file that sets this can be downloaded here.  Using this you can set the registry key centrally in the computer policy for the target system(s).

  • Added the following commands to the user's logon script:

reg delete HKCU\Software\Microsoft\Windows\CurrentVersion\Themes /v SetupVersion /f
regsvr32 /n /s /I:/UserInstall themeui.dll

When the user logged on, the script forced the custom theme to apply.  With all this in place, we were able to manage the themes centrally in Active Directory to easily change between themes without visiting the clients.

I'd be interested to hear of your experience using this or any better method you have for doing the same thing.

 

Service Security in Windows Vista

After a long break from blogging due to holidays and a heavy workload, I've finally got round to writing something new.  To follow on from my last post on File and Registry Virtualisation, I thought I'd take a look at another Vista security-related topic:  Service Security

Services generally run with elevated privileges and are therefore very attractive targets for hackers looking for ways to elevate their own privilege level. In Windows Vista several key changes help reduce the security risk when using system services.  Important changes are:

Session 0 Isolation

Previously Windows services would all run in the same session as the first user who logged on to the console. This session is called Session 0.  

Running services and user applications together in Session 0 poses a security risk.  Some services have visible and invisible windows and dialogs that the user or other processes can interact with directly using mouse input or programmatically via window messages.  This makes them vulnerable to certain attacks such as the so-called Shatter Attack.

Vista mitigates the risk by isolating system services in Session 0 and making Session 0 non-interactive; in Vista, only system processes and services run in Session 0 and the first user logs on to Session 1.  Subsequent users log on to sessions 2, 3 ,4 , etc. This means that services never run in the same session as user applications and are therefore protected against attacks from malicious user-mode code.

Figure 1 shows an example service, RegAlert, running on Windows XP.  This service monitors a specific registry value and will display a dialogue box to the user when the contents change.  In XP, the console user sees the dialogue and can interact with it easily, but as I mentioned this means that malware can also interact with it.  Since users and system services no longer "live" in the same session in Vista, this dialogue is not visible to the console user on a Vista system (though there is a workaround, that I'll discuss shortly). 

Figure 1: Service dialogue shown on the XP user desktop

Figure 1: Service dialogue shown on the XP user desktop

Consequences of Session 0 Isolation

Any service (or service-hosted driver) that assumes the user is running in Session 0 won't work correctly in Windows Vista. Some examples of where this is potentially a problem are:

UI Interaction

As mentioned above, any service that assumes the user is in the same session is going to have problems interacting with users.  Services that show dialogs like this should use alternative methods; for example, use the Terminal Services APIs such as WTSSendMessage to send messages to the appropriate session or use CreateProcessAsUser to create a new process in the user’s session.

Window Messages

If a services and applications use window message functions such as SendMessage and PostMessage to interact they are not going to work as the session isolation means they will have isolated message queues.

Using Named Objects

For services running in Session 0, named objects they create are usually in the \BaseNamedObjects\ namespace. However, user applications that try to open these objects using the default Local\ prefix are going to have problems as the objects are not local to the user session as they were in XP. The proper thing to do here is to create the object with the explicit Global\ prefix.

In actual fact these implications for services are also a problem with Fast User Switching (FUS) in Windows XP because FUS users all run in different sessions. Services that assume that the user is running in Session 0 encounter the same issues as above when subsequent users log on using FUS. Services that work fine with FUS are likely to be ok in Vista, but should be thoroughly tested before migration.

Interactive Service Detection Service

To help work with legacy services that send dialogue boxes to the Session 0 desktop a new system service, the Interactive Service Detection Service (UI0Detect), is available.  

The UI0Detect service notifies the user when a dialogue box or window appears in Session 0. Information about each of the last ten dialogue boxes will appear in turn.

Figure 2 shows the RegAlert service running on a Vista system.  This time, the dialogue is not displayed to the user; instead the UI0detect shows its own dialogue detailing the service that wants to interact with the user.

Figure 2: UI0detect service alerts the user that a dialogue was shown in Session 0

Figure 2: UI0detect service alerts the user that a dialogue was shown in Session 0

At this point users can:

•    Respond to the dialogue box immediately by clicking the "Show me the message" button to switch to Session 0, interact with the dialogue box, then switch back to their session.

•    Be reminded again in 5 minutes. They will continue to be reminded until the dialogue box closes.

Figure 3 shows what the user will see if they select the "Show me the message" option shown in Figure 2.  The user can then interact with the dialogue as they would in XP, but the critical difference is that other applications running on the user's desktop are prevented from any interaction.

Figure 3: the Session 0 desktop showing the service dialogue

Figure 3: the Session 0 desktop showing the service dialogue

The UI0detect service can notify users logged on at the physical machine or via Remote Desktop.

Privilege Management

Windows Vista now runs many services under accounts that have a lower level of privilege than the LocalSystem account that was typically used in previous Windows versions.  In addition, service developers (and administrators) can have their service declare to the Service Control Manager (SCM) which privileges they actually need and the SCM then gives the service a “filtered” token, with just those privileges. This means that even if the service is compromised the rights gained by the hacker are limited to only those the service uses and not the full set granted to LocalSystem, for example.

Administrators can use the built-in SC command to manage the privileges of a given service, so that legacy services (which don’t declare their privilege needs), can also be restricted:

Querying Service Privileges
The privileges allowed to a particular service can be queried using the qprivs option:

SC [server] qprivs [service name]

Figure 4: Showing the privileges allowed for the Windows Installer Service

Figure 4: Showing the privileges allowed for the Windows Installer Service

Setting Service Privileges
The privileges allowed to a particular service can be set using the privs option:

SC  [server]  privs [service name] [privilege1/privilege2/...]

For example, to allow the Windows Installer service on the local system only the "act as part of the operating system" and "debug programs" rights, use this command:

SC privs msiserver SeTcbPrivilege/SeDebugPrivilege

Or, to clear all privileges set for the Windows Installer, use this command:

SC privs msiserver /

The privileges for a particular service can be set programmatically using the ChangeServiceConfig2 API and are stored in clear text here in the registry:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<service name>\ RequiredPrivileges

Figure 5: Windows Installer service privileges shown in the registry

Figure 5: Windows Installer service privileges shown in the registry

 

Service Isolation 

The final tool available for securing services is the ability to restrict object access for system services as if the service itself is a user - this is known as Service Isolation.  In Vista, the SCM can create a new Security Identifier (SID) for the service itself (hence, it's called a per-service SID).  That is, the service will have a new, unique, SID that can be used to grant/deny it permissions to files, etc regardless of the account the service runs under.

The SCM adds the service SID to the security token used when the service is running and it is possible for Administrators to apply a blanket restriction on any “write” operations by the service by setting the SID type. 

The SID type can be:

NONE - new SID type is not used

RESTRICTED - SID is restricted from writing to files, registry, etc unless explicitly granted access

UNRESTRICTED - new SID is created and added to the token, but write operations are not automatically restricted

Again this setting can be managed with the SC command:

Viewing the Current SID Type

To query the current type of the service SID, use this command:

SC [server] qsidtype [service name]

Figure 6: Showing the SID type for the RegAlert service

Figure 6: Showing the SID type for the RegAlert service

Setting the SID Type

To set the SID type, use this command:

SC [server] sidtype [service name] [none|restricted|unrestricted]

Once the SID is restricted, the service will not be able to write to any resources. Administrator can then use normal file/registry permissions to allow the service access to only the resources they want it to access.

Figure 7: File permissions for the RegAlert service

Figure 7: File permissions for the RegAlert service

Further Reading

This is just a brief look at a couple of changes I found interesting.  For more detail on these and other improvements, have a look at these documents:

Services in Windows Vista

Impact of Session 0 Isolation on Services and Drivers in Windows Vista

Posted by richmac | 1 Comments
Filed under:

Windows Vista File and Registry Virtualisation

Windows Vista is designed to be more secure than previous versions of Windows. Part of the improvements are related to User Account Control (UAC), which encourages the good practice of not logging on with an Administrator account (and even if you do, it limits your available rights by default). While this is good for security, it can be problematic when dealing with legacy application, many of which were developed with the expectation that the user can make changes to locations such as the Windows directory.

Ideally, applications should be re-written or patched to make them compliant with Windows Vista security, but where this is not possible Windows Vista provides a new feature that will help alleviate problems in this area. The feature is known as File and Registry Virtualisation (FARV).  Below is a brief overview of FARV:


How File and Registry Virtualisation Helps

FARV presents a “virtual” view of certain parts of the filesystem and registry to legacy applications. That is, the legacy application can read and write to what it thinks is the correct location in the registry and filesystem, but any changes are actually redirected to a user-specific location.

File changes are redirected to the following location:
%UserProfile%\AppData\Local\VirtualStore
This directory contains subdirectories matching the location that was redirected. For example, if changes were redirected from the Windows directory, the store will look similar to this:

 

The FARV VirtualStore, showing some redirected folders.

If you navigate to the Windows drectory in Windows Explorer, you will not see the virtual version of the file. Explorer will show the actual content of folder. However, it does alert you to the fact that virtual copies of some files exist by a new button on the taskbar:


Explorer alerts you to the existence of user-specific files in the VirtualStore

Clicking this button takes you to the virtual store mentioned above.

A similar store exists for redirected Registry changes:

HKEY_CLASSES_ROOT\VirtualStore
This may appear to be a system-wide store since it doesn’t contain any user-specific information in the path. However, this key is actually just a pointer to the following location:
HKEY_USERS\<user SID>\Software\Classes\VirtualStore
[also accessible via: HKEY_CURRENT_USER\Software\Classes\VirtualStore]
So, registry changes are also stored on a per-user basis.


What is Virtualised?

File and Registry Virtualisation is hard-coded to present a virtual view of only these locations in the filesystem and registry:
Registry (includes subkeys)
HKEY_LOCAL_MACHINE\Software
Exceptions are:
  • HKLM\Software\Microsoft\Windows
  • HMLM\Software\Microsoft\Windows NT
  • Other subkeys under “Microsoft”
Keys can be excluded by setting the new DONT_VIRTUALIZE flag for the key using the Reg.exe tool.

Filesystem (includes subfolders)
  • %SystemRoot% (e.g. C:\Windows)
  • %ProgramFiles% (e.g. C:\Program Files)
  • %AllUsersProfile% (e.g. C:\ProgramData – previously C:\Documents and Settings\All Users)
Binary executable files (.exe, .dll, .sys, etc) are excluded from virtualisation. Additional extensions can be added here:
HKLM\System\CurrentControlSet\Services\Luafv\Parameters\ExcludedExtensionsAdd
These are locations where it is common for legacy applications to store their settings and data, but which should be secured against unauthorised access. There is no mechanism for adding additional folders or registry keys.


When is File and Registry Virtualisation Enabled?

File and Registry Virtualisation is an “opt-out” feature. That is, it is enabled for an application unless Windows is told otherwise. The mechanisms that Windows uses to tell if it should disable FARV are:
  1. Process Target Architecture. FARV is not enabled for 64-bit applications.
  2. Logon Type. Only activity originating from an interactive logon is virtualised. So, for example, any file writes due to file sharing across the network are not subject to FARV.
  3. Running as Administrator. If an application was launched with a Full Token, then Windows does not enable FARV since it is assumed that the user has appropriate access permissions for the locations discussed above.
  4. Application Manifest. If the application has an associated manifest file (embedded or external) that contains the new requestedExecutionLevel entry, Windows assumes the application has been written specifically for Windows Vista and thus will deal appropriately with security restrictions.
  5. User Intervention. If the user decides that FARV is not required, they can disable it using Task Manager:

     

Virtualisation status shown in Task Manager

Right-clicking on an entry in Task Manager shows a context menu with an option to toggle FARV on and off.


Limitations of File and Registry Virtualisation

FARV is not intended to be a complete answer to dealing with poorly written legacy applications. It is really a stop-gap mechanism to help with migration to the new Windows Vista Security model. It is likely that this feature will be dropped from future versions of Windows, so application developers should not rely on it for the proper operation of their applications, but should instead change their applications to work within the security constraints of Windows Vista.

Some places where FARV is limited are:
  • Target locations. The locations handled by FARV are hard-coded and apart from the Registry exclusions mentioned above users cannot alter this list. Nor can the user specify where the redirected data is stored.
  • Machine-wide changes. FARV works on a per-user basis, thus changes stored by one user are not seen by other users. Also, since user-specific data over-ride any actual data, Administrators have no way to make changes for all users at the same time.
  • Roaming users. FARV data that is stored in the local filesystem and does not roam with the user when they move to another computer.
  • Application functionality. For poorly written applications that may rely on settings stored in the virtualised locations to determine what they allow users to do, etc, this can be by-passed by the user changing data in the virtualised location, which over- rides any “real” settings in the restricted locations. Even if this does not result in a security problem (which it might), it could still lead to unexpected behaviour.
Posted by richmac | 0 Comments
Filed under:

Clustering Best Practices: Checking Hotfix Compliance

Do you use Microsoft Clustering? Are your clusters configured according to the current Microsoft recommended practices? How can you be sure of the configuration?

Questions, questions. The first is easy, the second you might be unsure of and the third is somewhat more difficult. If you search around Microsoft.com you will find recommendations on how best to configure your cluster, but the thing is that there is no easy way to double-check everything is as it should be, except by making a tedious manual review of all the settings.

While clustering isn't overly complicated, this checking process can be time-consuming, and, as with every manual process, is subject to human error.

So, what to do? In this article, I will be developing a script that takes care of part of the checking, namely auditing the status of the updates on each of the nodes.

UPDATE: My colleague, Ben Pearce, has created a PowerShell version of this script.  Check it out on his blog.
What Will the Script Check?
Well, to ensure your cluster is a stable as possible, there are two things to do in relation to updates:
  • Recommended Updates. Are the Microsoft recommended updates (see below) installed on all nodes? These updates address very common cluster issues, so installing them will help you avoid some known problems.
  • Update Parity. Does each node have the same set of updates installed, recommended or not? As clustered applications could potentially run on any node in the cluster (depending on the configuration), the ideal situation is that the nodes are identical in all aspects of hardware and software, including updates.
The script will check both of these aspects of patching.

The Recommended Updates for Microsoft Clusters
As mentioned above, Microsoft publish a number of lists of updates that are recommended for installing on Cluster servers. The following articles list the recommended updates:

895092 - Recommended hotfixes for Windows Server 2003-based server clusters
923830 - Recommended hotfixes for Windows Server 2003 Service Pack 1- based server clusters
935640 - Recommended hotfixes for Windows Server 2003 Service Pack 2-based server clusters
895090 - Recommended hotfixes for Windows 2000 Service Pack 4-based server clusters

Obviously, you don't need to install these updates, and in general Microsoft do not recommend arbitrarily installing updates. However, the updates in these articles are recommended because they are known to have resolved a lot of issues raised with Microsoft Support Services. So, it isn't enough for our script to just query for a list of the updates installed, but it will also need to check these against the recommended updates.

Script Overview
The general steps that the script will need to implement are:
  • Get a list of nodes in the cluster
  • Connect to the nodes and enumerate the installed updates
  • Check the installed updates against the list of recommended ones
  • Flag any missing updates, or disparity between nodes
Using VBScript together with a couple of WMI calls should be sufficient to take care of this.

The Script
Finally, down to business. Here's a walkthrough of the key points in the finished script:

To keep things simple, we will expect some user input from the command-line. The user needs to supply the cluster name and the file containing the list of recommended updates, which we check for before doing anything else:
strClusterName = WScript.Arguments.Named.Item("cluster")
strKBList = WScript.Arguments.Named.Item("KBlist")

If(("" = strClusterName) OR ("" = strKBList)) Then
   Wscript.Echo "Error parsing command-line. Check Command-line and try again."
   wscript.quit
End If
From this you can see that for the script to work properly, the user must call it like this:
cscript ClusterHotfixCheck.vbs /cluster:<cluster_name> /KBlist:<KB_list_text_file>
To know which nodes to check we need to connect to the cluster and ask for a list:
Set objWMICLuster = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strClusterName & "\root\mscluster")
Set collNodeList = objWMICLuster.ExecQuery("Select name from MSCluster_Node")
Here we are using the cluster WMI provider. In this case we are connecting using the user's credentials. WMI allows you to supply alternate credentials for remote connections, but for this example, we take the simple approach.

Next we interrogate each of the nodes:
Set dictFixes = CreateObject("Scripting.Dictionary")

For Each objNode in collNodeList

intNodeID = intNodeID + 1

Set objWMINode = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & objNode.Name & "\root\cimv2")
Set collFixes = objWMINode.ExecQuery("SELECT HotfixID FROM Win32_QuickFixEngineering")

For Each objFix in collFixes
  strTempFix = StripPrefix(objFix.HotfixID)
  If(dictFixes.Exists(strTempFix)) Then
    arrTemp = dictFixes(strTempFix )
    arrTemp(intNodeID) = "1"
    dictFixes.Remove(strTempFix)
    dictFixes.Add strTempFix , arrTemp
  Else
    arrNodes(9) = Len(objNode.Name)
     arrNodes(intNodeID) = "1"
    dictFixes.Add strTempFix , arrNodes
  End If
  Next
Next
A dictionary object is used to store details of all of the updates installed on all of the nodes. A normal array would probably do, but the dictionary object has a simple method (Exists) for checking if an update is already in the list. I'm not sure how this is implemented internally (maybe a hash table), but it is almost certainly faster than iterating through the elements of an array in the script to look for a given update. For each update we flag it as installed on a particular node by adding a "1" to the nodes place in a simple array.

Again, WMI is used to gather the data we need. This time the Win32_QuickFixEngineering class gives us the list of installed updates.

The StripPrefix() function is defined later in the script and is used to remove any "Q" or "KB" prefix commonly found in the ID for an update:
Function StripPrefix(strHotFixID)

If(1 = InStr(strHotFixID, "Q")) Then
  StripPrefix = Mid(strHotfixID, 2, 6)
ElseIf(1 = InStr(strHotfixID, "KB")) Then
  StripPrefix = Mid(strHotfixID, 3, 6)
Else StripPrefix = strHotfixID

End If

End Function
Now we have a list of what is actually installed, we need to load the list of recommended updates and check if they are in our existing list. Here's where we again take advantage of the ease of searching the dictionary object to check if a specific update is installed somewhere in the cluster:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFixList = objFSO.OpenTextFile(strKBList, 1)

arrNodes = Array(0,0,0,0,0,0,0,0,0,0)

Do While objFixList.AtEndOfStream <> True
  strHotFix = objFixList.ReadLine
  If("" <> Trim(strHotfix)) Then
    If(dictFixes.Exists(strHotfix)) Then
      arrTemp = dictFixes(strHotfix)
      arrTemp(0) = "2"
      dictFixes.Remove(strHotfix)
      dictFixes.Add strHotfix, arrTemp
    Else
      arrNodes(0) = "2"
      dictFixes.Add strHotfix, arrNodes
    End If
  End If
Loop

objFixlist.Close

DisplayOutput()
From the code, you can see that it simply reads a line from the supplied file and uses this as the name of an update to check. So, for the script to work properly, the input file needs to be a simple text file with one KB ID on each line.

This time, we use "2" to indicate that this update is on the recommended list. The DisplayOutput() function is defined later in the script (but not discussed in this post as it's a little messy) and is used to output the results to a text file on the user's desktop. Typical output looks like this:

Typical script output
Patching Status
Determine the status of your patching from the output as follows:
Recommended Updates
"--" is used if an update is on the recommended list and is installed on all nodes.
"XX" is used if an update is recommended but is missing from one or more nodes.

General Updates
"++" is used if an update is not on the recommended list and is installed on all nodes.
"**" is used if an update is not on the recommended list and is missing from one or more nodes.

Specific Nodes and Updates
"0" is used to show that an update is not installed on the given node.
"1" is used to show that the update is installed on the given node.
Known Limitations
The script as it stands has some limitations. Two key ones are:
  • No account is taken of the existing Service Pack level or any roll-up packages, which may make some updates redundant.
  • No account is taken of whether a particular update is actually needed on the cluster. Some of the recommended updates only apply to certain resource types and if you don't use that type, then the update is not needed.
It is left to the reader to implement these improvements if required - I thought I'd leave some fun stuff for you to do!

Download
You can download the full script together with lists of recommended updates from the link below:

ClusterHotfixCheck.zip

[This script is subject to the Microsoft Terms of Use.  Essentially, you use it at your own risk!]

I'd be interested in hearing your experience of using the script, so let me know if you find it useful or have any problems with it.

Professional Microsoft Virtual Server 2005

The eagle-eyed among you may have noticed a reference to an unpublished Virtual Server book buried in the middle of my recent list of virtualisation resources.  At the time I compiled the list, the book wasn't actually available, but it is now, so I thought I'd give it a bit of promotion:

If you’re into virtualisation, then this new book from Ben Armstrong, virtualisation Program Manager, is a must read:

Professional Microsoft Virtual Server 2005

[Note: the book is available now in the US, but won't be available in the UK for a few more days]

If you know Ben (maybe from his blog Virtual PC Guy), then you'll know he really knows his stuff and is very good at explaining virtualisation topics, so I’m anticipating that this will become the VS resource to have.  Check here for a more detailed description of the contents:

Mumbling to Myself: Professional Microsoft Virtual Server 2005

Enjoy!

Posted by richmac | 0 Comments
Filed under: ,

(Re-)Start Me Up ...

As I mentioned in a recent post, I'm currently working on a Windows Vista workshop. As part of that, I've created a simple application that demonstrates the basic interaction of the Windows Installer with Vista's new Restart Manager (RM). I thought I'd post some information on how easy this was to do, which you might find useful for your own applications and packages.

My sample application is a basic text editor that uses a multi-line edit control to allow the user to write short notes:

Screenshot 1: RMtestX - not Restart Manager aware

There are two version of the application, RMtestX (non Restart Manager aware, used for screenshots 1-3) and RMtestV (Restart Manager aware). If RMtestX were to crash, you'd see something like this:

Screenshot 2: RMtestX crashes

So, the user can close the application or debug it, which is not any better than Windows XP offers. Generally, the user doesn't want to do either. They just want to carry on with their work. Similarly, if a patch is applied when the application is running, they have two equally unappealing option:

Screenshot 3: RMtestX is being patched.

If they want to update to happen, then the user can either manually save data, close the application, complete the update, restart the application, then open the saved data, or opt for a full system reboot. Neither option is ideal.

So, how can we use Restart Manager to improve things?

Becoming Restart Manager Aware
Firstly, before the application can interact with the RM, it needs to register itself using the RegisterApplicationRestart API. Doing this is extremely simple:

// register with Restart Manager
RegisterApplicationRestart(L"-rm", 0);
For RMtestV, I call the API just after the main window is created and just before jumping into the message loop, though you could call it elsewhere - doing it early makes sense since your application can't know when it might be called upon to restart. The "-rm" switch is an arbitrary command line that the RM passes to the application if it's been restarted. You can make this more or less anything you like. The idea is that the application can tell from this that it was restarted and can respond appropriately. In the case of RMtestV, this check is performed when the WM_CREATE message is received:

case WM_CREATE:
   //
   // some initialisation stuff
   //

   // check to see if RM called us
   if(RMstart())
   {
      RestoreText(GetDlgItem(hWnd, IDC_EDIT1));
      MessageBox(hWnd, L"RMtestV was restarted by the Restart Manager", L"RMtestV: Restart Alert", MB_OK|MB_ICONEXCLAMATION);
   }

   return 0;
RMstart() uses the GetCommandLine and CommandLineToArgvW APIs to check if RMtestV was called with "-rm". If it was, then the RestoreText() call restores the contents of the EDIT control saved during shutdown (as mentioned below). Alerting the user to what just happened isn't mandatory, of course, but is probably a good idea. Restart Manger adds entries like this to the Application Event Log:

Event ID: 10002
Source: Restart Manager
Type: Information
Description: Shutting down application or service 'Restart Manager Example: RM Compliant'.


Event ID: 10003
Source: Restart Manager
Type: Information
Description: Restarting application or service 'Restart Manager Example: RM Compliant'.

To make this automated stopping and starting more useful, RMtestV needs to be able to save any text the user has entered before it shuts down. When the RM is wanting to restart an application, it sends two window messages in order, which the application needs to process, WM_QUERYENDSESSION and WM_ENDSESSION:

case WM_QUERYENDSESSION:
   // no need to do anything special here
   // but must return "1" if the application is ready to restart
   return 1;

You can perform some clean up work when handling WM_QUERYENDSESSION, but the application has to respond quickly at this point, so it is better to delay this work until handling WM_ENDSESSION. In particular, it is a bad idea to prompt for user input in response to WM_QUERYENDSESSION.  If your application can't restart, say because it is doing work that can't be interrupted, return "0". 

Next comes the notification that the session is ending:

case WM_ENDSESSION:
   if(ENDSESSION_CLOSEAPP & lParam)
   {
      SaveText(GetDlgItem(hWnd, IDC_EDIT1));
   }
   return 0;
If the application is being asked to restart due to file replacement during patching, the ENDSESSION_CLOSEAPP flag is passed to the application. RMtestV responds to this flag by saving the current contents of the EDIT control in a temp file using the user-defined SaveText() function.

So, now the application is ready to respond to the Restart Manager. For example, if RMtestV crashes now, the user sees this:

Screenshot 4: Restart Manager Prompt

To make things a lot smoother, RMtestV should regularly save the user's data to a temporary location, so that if the user selects "Restart the program", RMtestV will close and re-open with the data restored with minimum interruption. As I was mainly interested in the Windows Installer interaction, I didn't implement this, but it would be a simple matter to use the SetTimer API to trigger a call to SaveText() or similar on a regular basis.

Before looking at how Windows Installer makes use of this, two important points to note about the above are:
  • Adding Restart Manager functionality to your application is not hugely complicated
  • You need to do all of the important work of saving/restoring any data, configuration settings, etc.

 

Interacting With the Windows Installer
As mentioned above, prior to Windows Vista, any attempt to patch files held open by an application would fail. The best you could get was to prompt the user to manually close the application (and re-open it themselves later), or to require a system reboot. Once an application is RM aware, we need to author the MSI package correctly to take advantage of it. The outline of what needs done is as follows:

Dialog Table
You need to define the MsiRMFilesInUse dialog. This is very similar to the existing FilesInUse dialog, but it allows the user to select an automatic restart of the application using Restart Manager.

Dialog HCentering VCentering Width Height Attributes Title Control_First Control_Default Control_Cancel
MsiRMFilesInUse 50 50 374 266 19 [ProductName] PushButton1 PushButton1 PushButton2


Control Table
The controls used on the MsiRMFilesInUse dialog are defined as follows:

Dialog_ Control Type X Y Width Height Attributes Property Text Control_Next Help
MsiRMFilesInUse DlgLine Line 0 234 375 0 1        
MsiRMFilesInUse Banner Bitmap 0 0 374 44 1   [BannerBitmap]    
MsiRMFilesInUse DlgDesc Text 21 23 292 25 65539   Some files that need to be updated are currently in use.    
MsiRMFilesInUse DlgTitle Text 13 6 292 25 65539   {&MSSansBold8}Files in Use    
MsiRMFilesInUse DlgText Text 21 49 348 17 3   The following applications are using files that need to be updated by this setup.    
MsiRMFilesInUse BannerLine Line 0 44 374 0 1        
MsiRMFilesInUse RadioButtonGroup1 RadioButtonGroup 19 187 343 40 16777219 ShutdownOption   List  
MsiRMFilesInUse List ListBox 21 66 331 118 7 FileInUseProcess   PushButton1  
MsiRMFilesInUse PushButton1 PushButton 228 244 66 17 3   OK PushButton2  
MsiRMFilesInUse PushButton2 PushButton 299 244 66 17 3   Cancel RadioButtonGroup1  


ControlEvent Table
Once the controls are defined, we need to define what actions they trigger when used:

Dialog_ Control_ Event Argument Condition Ordering
MsiRMFilesInUse PushButton1 EndDialog Return 1 1
MsiRMFilesInUse PushButton1 RMShutdownAndRestart 0 ShutdownOption=1 2
MsiRMFilesInUse PushButton2 EndDialog Exit 1 1


RadioButton Table
We use a pair of radio buttons to alow the user to choose between using restart manager and going for an old-style post-boot replacement:

Property Order Value X Y Width Height Text Help
ShutdownOption 1 1 6 9 331 14 Automatically close all applications and attempt to restart them after setup is complete.  
ShutdownOption 2 2 6 21 322 17 Do not close applications. (A reboot will be required.)  


Property Table
A property is used to determine which of the radio buttons the user has selected:

Property Value
ShutdownOption 1

I've exported examples of these tables as IDT files, which you can import into your packages using ORCA:

MsiRMFilesInUse Related Tables

Once this is in place, the user will see different options when patching while the application is in use:

Screenshot 5: MsiRMFilesInUse dialog 

Further Reading
The above isn't everything the Restart Manager has to offer. For example, you can call on it to give you a list of processes holding a given file open, then (if the applications are registered), ask for them to be restarted - essentially what the Windows Installer does behind the scenes. Get more information here:

Restart Manager Documentation
Application Recovery and Restart Documentation
Using Windows Installer with Restart Manager
Windows Installer Team Discussion on Restart Manager

Windows Vista Resource Kit Released

If you're a long-time Windows Admin, then you'll know how invaluable the Windows Resource Kit has been for the various Windows versions over the years.  Now the Windows Vista version has been released and with 1,500 pages of in-depth technical information and over 150 scripts and tools I'm sure it will prove just as much of a "must-have" item for your bookshelf.

Get more details on the Windows Vista Team Blog

The only downside seems to be that the competition to win a free copy is closed ...

Posted by richmac | 0 Comments
Filed under: ,

How to Interpret Windows Installer Logs

[Updated: 4 April 2007]

If you have a problem with the Windows Installer or an MSI package you're installing, it's a sure bet that you will be told by some smart person to "enable logging".

That's great advice, except ... what do you do with the log once you get it? A common technique is to open it in Notepad and scroll up and down aimlessly, hoping to spot the "cause of your problem" section. While this is a very popular approach, it rarely yields good results. In this post, I'll walk you through the contents of a typical log so that next time you have an Installer problem you'll be in a better position to troubleshoot it yourself.

"Enable Logging"
First things first. If you are to take your smart friend's advice, you need to know how to generate a log. There are a number of ways to do this:

Command-Line
If you can install the MSI package from the command-line, even if only for troubleshooting, then this is a very easy way to generate a log. Simply use the "/l" switch during install:

msiexec /i SomeApp.msi /l*vx %temp%\SomeApp.log

Using the "*vx" modifier gives the most detail possible - you should always use this when troubleshooting.

Registry or Group Policy
If you cannot run the package from the command-line, then enable logging directly in the registry or via Group Policy, as described in KB223300: How to enable Windows Installer logging.

MsiLogging and MsiLogFileLocation properties
With MSI 4.0 these two properties can be set in the Property table of a package to enable logging and specify the log location. Se