Welcome to TechNet Blogs Sign in | Join | Help

MDT Script Explanations

I get quite a few emails from people asking if there is a help file that details all of the scripts that are supplied with Microsoft Deployment Toolkit (MDT). The scripts form the engine of a deployment and can also help you to develop a framework for scripts that you need to create for your own tasks. The MDT documentation (installed in \Program Files\Microsoft Deployment Toolkit\Documentation) is a good place to start - but I also point people to the online MDT Reference - which lists the following information for each script supplied:

 

  • Name. Specifies the name of the script.

  • Description. Provides a description of the purpose of the script and any pertinent information regarding script customisation.

  • Input. Indicates the files used for input to the script.

  • Output. Indicates the files created or modified by the script.

  • References. Indicates other scripts or configuration files that are referenced by the script.

  • Location. Indicates the folder where the script can be found. In the information for the location, the following variables are used:

    • program_files. This variable points to the location of the Program Files folder on the computer where Microsoft Deployment is installed.

    • distribution. This variable points to the location of the Distribution folder for the deployment point.

    • platform. This variable is a placeholder for the operating system platform (x86 or x64).

  • Use. Provides the command line and options that can be specified.

  • Arguments and description. Indicate the valid arguments to be specified for the script and a brief description of what each argument means.

  • Properties. The properties referenced by the script.

 

You will find each MDT script breakdown at http://technet.microsoft.com/en-us/library/bb979605(TechNet.10).aspx 

This post was contributed by Richard Smith a Senior Consultant with Microsoft Services, UK.

Useful Script Number 6 - Pausing the Task Sequence

Have you ever wanted to pause the task sequence in MDT 2008 or ConfigMgr 2007 for a few seconds while something catches up...? I had a requirement to do this recently where I ran a task to close and cancel the Windows Sidebar at the start of the State Restore phase of the task sequencer and then turn the Windows Sidebar back on again at the end of the State Restore phase - I was doing this as the Windows Sidebar can sometimes get in the way of some customisation scripts and you can also see peculiar VB messages when 2007 Office System updates are applied. When the Windows Sidebar is turned back on, there is a couple of seconds before the Sidebar actually appears - yet my task for turning on the Sidebar had returned and the task sequence had moved on...it made be think that there may be other situations where a slight delay in returning to the task sequence may be useful - sure you could add sleep commands to the scripts that your running as commands - but that doesn't help with the tasks that are not scripted - so here is an MDT based script that will pause the task sequence for a specified number of seconds (specified on the command line)

I first have a couple of variables to store the time to pause (strTime) and the script name (strSName - for logging purposes) and the integer argument for the sleep method

Dim strTime, strSName, IntTime

ZTIProcess=1

...I then use a call to ZTIUtility.wsf to set the script name to the strSName variable - this is then used to insert the script name at the start of each line in the log.

strSName=oUtility.ScriptName

...then it's another call to ZTIUtility.wsf to use the arguments class - this makes passing input to the script via the command line easy - in this case I am setting a command line input called "Time"

strTime = oUtility.Arguments("Time")

oLogging.CreateEntry strSName & ": Starting Actions ********************************************* ",LogTypeInfo

...then I check that Time has been specified as a command line input (exit if not) or set the IntTime to number of seconds from the command line x 1000 to get milliseconds

If strTime="" Then
    oLogging.CreateEntry strSName & ": No pause time was specified on the command line.",LogTypeError
    ZTIProcess=90
    Exit Function
Else
    oLogging.CreateEntry strSName & ": Pause time has been set to " & strTime & " seconds",LogTypeInfo

    IntTime = strTime * 1000 
End if

...I then take the intTime (in milliseconds) and add it to the sleep method to pause the script

oLogging.CreateEntry strSName & ": Task Sequence will pause for " & int(IntTime/1000) & " seconds",LogTypeInfo

wscript.sleep intTime

oLogging.CreateEntry strSName & ": Task Sequence has been paused for " & int(IntTime/1000) & " seconds - returning control to the Task Sequence now",LogTypeInfo

oLogging.CreateEntry strSName & ": Completed Actions ********************************************* ",LogTypeInfo
ZTIProcess = 0
End Function

The script is called CFG-TSPause.wsf so the command line to run it would be CFG-TSPause.wsf /Time:xx (where xx = the number of seconds that you want to pause the task sequence for) Drop the script into your <Deployment Share>\Scripts directory. You can then add the script anywhere in your task sequence by adding a Run Command Line task and specifying the script and the command line input for the number of seconds you want to pause.

image

 

As usual, the full script is up on the Deployment Guys SkyDrive:

This post was contributed by Richard Smith a Senior Consultant with Microsoft Services, UK.

SMS, OSD and Bitlocker

In this post I am going to talk about a BitLocker solution that myself, Richard Smith and others from Avanade/Accenture - Chris Bird, Jonathan Goulding, Chris Urwin and Steven Westwell - put together for a customer. I should point out that enabling and applying BitLocker via OSD on SMS 2003 SP3 is not supported. So think carefully before implementing this in your environment.

First I want to quickly review the process of applying BitLocker via LiteTouch. There are three stages to this;

  1. Create a partition for the system files
  2. Move the boot files to the new system partition and mark that as active
  3. Boot from the new partition and initialise BitLocker encryption

So what are the problems with doing this process under OSD?

  1. OSD only supports a single partition
  2. the disk partition script needs a location to write the diskpart answer file to
  3. We can not reboot in the middle of the OSD/ZeroTouch task sequence.

Taking these one by one we can break the problem down a bit more and start to deliver solutions.

OSD and Multiple Partitions

The script that is used by LiteTouch to create multiple partitions requires a location to write the diskpart.txt file to. Now LiteTouch uses WinPE2.x which has a built in RAM drive so this is no problem. Under OSD we use a 'legacy' version of WinPE which does not. We could write the diskpart answer file to the hard disk but that would be lost as we used it to wipe the disk so that is no good. Really there are only two options open to us;

a) write the file to a network location

b) hard code the partition sizes

If using the latter option you have some challenges around coping with changes in disk size. You could create the BitLocker 2GB partition first and then create the OS partition in the remaining space - you just have to be careful that Windows Vista does not try to install itself into the 2GB Bitlocker partition – As this will be seen as the first installable partition and Windows Vista will not fit into this size of partition.

In our solution we chose option a. The main reason for doing this was that we were also having to support an OEM solution in the same image/task sequence. The OEM solution can only cope with one partition on the hard disk when it boots up - this meant we could not pre-create the BitLocker partition. So now we have to write the diskpart answer file to a network location - but where? In a large organisation spread around the globe you do not really want all 100,000 systems writing their answer file back to a single server somewhere. Luckily there is a server in OSD that is always close to the client system; or should be anyway. This is the SMS Deployment server. We used the SMS Deployment Point server to store the additional scripts, drivers and other files used by the solution (resourceroot=\\%SMSDP%\BDDResource$ - you have to create this package yourself - make sure you specify a fixed share to access it on all DPs). It was easy to create a sub-directory in our SMS package that was writeable by the SMS account to host the answer file. Each answer file is given the name of the computer that will use it, ensuring uniqueness, and not wanting to clog this directory up over time we delete the answer file once used.

So now we can create multiple partitions and define their sizes from values in the backend database. What's the next problem?

Moving the Boot Files

This is not so hard as it might seem. We use a slightly modified version of the normal BDEHDCfg.vbs script to do this. Although when it runs you see an error in the BDD.log file saying it wanted to reboot but OSD blocked it. That is fine. The boot files have been moved to the system partition and the partition marked as active.

Re-Boot and start BitLocker

So this gets pretty complex and even, may I say, a little messy. I have already covered off forcing OSD to reboot in a previous blog. We are now going to build on that process. In the previous post I described how we setup the system to autologon and run a job to reboot the system. Now we need to go one step further and have it run a script once it has rebooted. We have to copy the script down from the framework location (on the SMS Deployment Point Server) to a location on the hard disk that will not get deleted when OSD completes. In fact we need everything that will be required post reboot to be on the local hard disk. Remember OSD has completed so there is no BDD/MDT framework to use any more. In the previous blog post the second script that ran cleaned out the auto-logon entries before forcing the reboot - we need to do other things. So in the second script configure the system to run the third script once the machine has logged back on. This carries out all the tasks we need to initialise BitLocker running. Once BitLocker has started running we reboot the system again.

NOTE: We changed the shell at reboot to be the third script - this helps to make to solution a bit more secure in that there is no desktop for the user to interact with. However while you are developing the solution you might want to place a shortcut in the start up folder as this will make debugging easier. We also show a warning dialogue on the screen, BuildWarning.hta, informing the user that the system is still building.

 

Scripts and Task Sequence

Partitioning the disk

Because we needed to support an OEM solution we re-worked the disk partitioning script quite a bit. The script ZTIDiskPartOSD.wsf, in the zip linked below, actually has to be run twice. Each time it is run you need to specify a switch on the command line. This switch tells it if it is going to create the OS partition or the BitLocker partition. So in your task sequence you need to create two tasks - one to create the OS partition to other to create the BitLocker Partition. The screen shot below shows the two task sequences. The zipped file, link at the end of this post, has a file TS-snippets.txt that contains these two steps that you can cut and paste into your task sequence.

OSDTS

NOTE: You could use the normal script that comes with BDD however you still need to make sure this writes to a network location.

So now we have the two partitions created. The OS image is laid down onto the disk and mini-setup runs before rebooting to start the Zerotouch part of setup.

Moving the system files and rebooting

So by this time we have two partitions on the disk and the OSD process is running. Any custom tasks you  have defined, including installing applications happen in this stage. Before this stage completes we need to do two things;

  1. move the boot files to the system partition
  2. configure the system to reboot and initialise BitLocker.

The modified BDE script (ZTIBdeOSD.wsf) does not try to start BitLocker - it just moves the boot files across to the BitLocker partition. It then asks for a reboot - you will see errors in the BDD log files saying that OSD has suppressed the reboot.

Next we need to re-boot from the new partition so BitLocker can be initiated.

As mentioned I covered off the basics of how force a reboot in an earlier post - I'll outline the process again here as it has changed a little to accommodate more than just rebooting the system. The OSD part of a ZTI process runs before the system has logged on for the first time. So before we can reboot the system we need to logon. However once we logon ZTI has completed and we no longer have the ZTI framework to rely on. So any scripts or files we need are going to have to be copied to the local hard disk for execution post re-boot. We essentially have three phases;

  1. copy scripts locally and prepare for reboot
  2. auto-logon once OSD completes and reboot
  3. carry out post reboot tasks.

The script z-osdpart1.wsf copies the required files (z-OSDPart2.vbs, z-OSDPart3 and Buildwarning.HTA) locally and configures the auto-logon settings. Once OSD completes the system auto-logons, runs z-OSDpart2.vbs which configures the system to run z-OSDPart3.vbs after reboot and then z-OSDPart2.vbs initiates the reboot. Because ZTI has completed there is no minint directory to use we copy the required files to c:\OSDTemp, if we copied them to the c:\minint directory they would be deleted by the ZTI cleanup process.

The screen shot below shows the two tasks as part of a much larger task sequence. As you can see they are placed towards the end of the task sequence.

image

The zipped file, link at the end of this post, has a file TS-snippets.txt that contains these two steps that you can cut and paste into your task sequence.

 

Post Re-Boot

So the system should have rebooted and be running Z-OSDPart3.vbs as the shell. This is quite a simple script that carries out the steps required to initialise encryption of the hard disk. It runs the BuildWarning splash screen, ejects the optical disk, (this is required because if a bootable disk is left in the optical drive then BitLocker cannot start), then starts BitLocker, cleans out the auto-logon information and resets the shell back to the normal desktop before rebooting.

We use the manage-bde.wsf script to initialise BitLocker once the system has restarted. For our client there was no requirement for a startup PIN - thy just wanted the hard disk encrypting and the recovery key stored in the Active Directory. We used a group Policy to make sure the BitLocker recovery password is stored in AD. The command line we used in Z-OSDPart3.vbs is given below. This turns on BitLocker on drive C: with a recovery password (-RP)

cscript.exe %windir%\system32\manage-bde.wsf -On c: -RP

So now you should have a system that has been built using OSD and is BitLockerd. Simple wasn't it! ;-)

 

Scripts

The link below takes you to the zipped archive of the files required for this solution.

 

This post was contributed by Richard Trusson a Senior Consultant with Microsoft Services, UK.

 

Editing the HTML template files

A great new tool has been released that allows you to edit the contents of those XML/HTML files you see during the WinPE phases of a deployment using MDT, the MDT Wizard Editor.  I saw a demo of this tool a while back but was never able to get my hands on a copy.  Well, now everyone can!

You are invited to help out with the testing of the tool via the CodePlex site.  Go get it here: http://www.codeplex.com/MDTWizardEditor

This post was contributed by Daniel Oxley a consultant with Microsoft Services Spain

Robocopy exit codes

Robocopy is a great tool, and I often use it in a deployment project for moving files around; I think the most useful feature it has is the /MIR switch.  It lets you update the contents of a folder, only copying the files that have changed or are missing.

One problem with the use of Robocopy in the task sequence is that it doesn't always return an error code of 0, even if the copy has been successful.  This can give a problem if you have your task sequence set up similar to the screenshot below.  As you can see, I have added the Robocopy command direct to the task sequence, and I have left the default "Success codes" on the options tab.  This works fine for most scenarios, but with Robocopy you might find that your deployment fails stating that Robocopy returned a non-success code, even though the copy appears to have been successful.

 

image

 

There are several ways to fix this, but the way I prefer is to add the additional success codes to the task sequence, that way it will only fail if a genuine error occurs.  So, below I have included a list I compiled of the codes I have come across (I have included the non-success codes I have seen for completion).  Feel free to comment on this post if you can help expand the list!

 

Code Meaning
0 No errors occurred and no files were copied.
1 One of more files were copied successfully.
2 Extra files or directories were detected.  Examine the log file for more information.
4 Mismatched files or directories were detected.  Examine the log file for more information.
8 Some files or directories could not be copied and the retry limit was exceeded.
16 Robocopy did not copy any files.  Check the command line parameters and verify that Robocopy has enough rights to write to the destination folder.

 

I strongly recommend that you use the /LOG parameter with Robocopy in order to create a complete log file of the process.  This file is invaluable for finding out what went wrong.

 

This post was contributed by Daniel Oxley a consultant with Microsoft Services Spain

Implementing the "Windows XP Tablet PC Edition 2005 Single-Image Deployment Supplemental Guide" Process - Important Update

In my post on May 23rd, I described using this process with MDT 2008.  Since that post, another Microsoft Consultant (Barry Hartmann of MCS Federal, thanks Barry!) encountered an issue with this process if you have the .NET Framework installed in your Windows XP Professional image. The XP Pro to Tablet PC Edition conversion uses a rather unintelligent, brute force installation process to install .NET Framework 1.0 (which is required by some Tablet PC Edition components).  If a newer version of the .NET Framework is installed in your image, this process will downgrade shared files and registry values.  This essentially breaks the newer version of the .NET Framework. 

Barry encountered this problem when he tried to install Project 2003 on a machine deployed with the "single image" process that had the .NET Framework 3.5 installed in the original XP Pro image.  The Project installation fails with the .NET Framework in this state.

The one obvious solution (the one my customer has chosen) is to not include the .NET Framework in the XP Pro image.  My customer will be installing .NET Framework 3.5 as an operating system specific post deployment item in the SCCM Task Sequence.  The other thing that seems to correct this if the .NET Framework is in the image, according to Barry's testing, is to initiate a repair on the highest version of the core Framework installed (1.1 or 2.0) after the deployment/conversion process.

These blog posts referenced below contain the command lines you should be able to use to repair the .NET Framework 2.0 RTM and 2.0 SP1:

Finally, a few fixes were made to one of the scripts from the May 23rd post.  Barry discovered incorrect paths were written to files in certain SCCM deployment scenarios.  The attachment with that post has been updated with the newer version.

This post was contributed by Michael Murgolo, a Senior Consultant with Microsoft Services - U.S. East Region. 

Adding Hyper-V Integration Components to WinPE using MDT 2008.

Mike Sterling recently posted and excellent blog on Using the Hyper-V Integration Components in WinPE on his MSDN blog. 

 

Wouldn’t it be nice if we could add the Integration Components to the WinPE Images created by MDT 2008?

The procedure assumes you want to import both the x86 and x64 integration components.  You will need the MSU files that contain the Integration Components.  These can be found on the VMGuest.ISO.  The easiest way to get them is to mount the VMGuest iso in a VM and just copy them.  Mike’s blog lists several other tools that can also be used to extract the MSU files. 

Place the MSU files in a empty folder and use the following batch file to extract the drivers that we will import into MDT.  This batch file produces a folder called OutOfBoxDrivers in the same folder where the MSU files are.

MD MSU
expand  Windows6.0-KB951633-x86.msu -F:*.CAB MSU

MD Files
expand  MSU\Windows6.0-KB951633-x86.cab -F:* Files

MD OutOfBoxDrivers
for /d %%I in (files\*_none_*) do xcopy %%I OutOfBoxDrivers-x86\%%~nI\ /e
rd /s /q MSU
rd /s /q Files

After batch file completes, start the MDT 2008 console and right click on Out-Of-Box-Drivers and choose new.

 Untitled picture

I normally put drivers that are only going to be used in WinPE in a separate group, this is optional, but i would recommend it.

Note that since the x86 and x64 filenames are the same and they use the same inf files, you cannot add both x86 and x64 drivers unless you put them in separate groups and check Import drivers even if they are a duplicates of an existing drivers. You will then have to create the x86 and x64 WinPe images in separate steps

This post was contributed by David Hornbaker, a Senior Consultant with Microsoft Services - U.S. East Region.

Injecting Hyper-V Synthetic drivers to WinPE

One of the things we try not to do on this blog is just post links to other peoples blogs. But this is, I think, too good to miss.

Anyone who is using Microsoft's new Hyper-V solution will have found problems when trying to build a Hyper-V guest machine. WinPE just does not have the Hyper-V synthetic divers in it out of the box. So you go and change the drivers to legacy which means you can do the build but then you have to change back. Also having the drivers in WinPE results in a faster build.

The blog post below outlines how to inject the synthetic drivers into WinPE in a clear step by step way. It even provides a little script to semi-automate the process.

http://blogs.msdn.com/mikester/archive/2008/05/30/using-the-hyper-v-integration-components-in-winpe.aspx

NOTE

Be sure to read the comments for some updates regarding paths in WAIK x86 as opposed to x64.

 

This post was contributed by Richard Trusson a Senior Consultant with Microsoft Services, UK.

Posted by rtrusson | 1 Comments

Useful Script Number 5 - Adjusting the Default User Registry Hive

Michael Murgolo did a great post on the different ways to adjust default settings when building an image (Configuring default settings for Windows image deployment) and one of the options presented was to targeted changes to the Default User Registry hive and profile folders. I had to do this recently and put together a script that can be launched from the MDT task sequence because I was finding my customised Administrator profile wasn't being copied over correctly to the Default User profile as part of SysPrep.

As Michael mentioned in his post - there are three main processes...you first need to load the default user hive (NTUser.dat) - make the changes you require - then unload the user hive. I have reproduced the core part of my script that does this process for discussion.

The first section sets the two variables that will be used - one to store the temp key (sTempHive) that we will load to, and the second to hold the profile file and location that we want to load (sDefaultUserHive)

For Windows Vista the entry """%USERPROFILE%\..\Default\NTUSER.DAT""" refers to C:\Users\Default\ntuser.dat

sTempHive = """HKEY_USERS\Test"""
sDefaultUserHive = """%USERPROFILE%\..\Default\NTUSER.DAT"""
sSName = oUtility.ScriptName
set oshell = WScript.CreateObject ("Wscript.Shell")

iZTIRetValue="1"

We then need to start logging - it's the law :-)

oLogging.CreateEntry sSName & ": Actions Start - Updating Default Profile",LogTypeInfo
oLogging.CreateEntry sSName & ": Loading the Default User hive",LogTypeInfo

The next section runs reg load to load the NTUser.dat file from the default user directory to the temp key (HKEY_USERS\Test) set in the first section - if there is an error the script fails and quits with a specific failure number or we log success.

oShell.run "reg load " & sTempHive & " " & sDefaultUserHive
If Err<>0 Then
  oLogging.CreateEntry sSName & ": Failed to load the registry hive " & sDefaultUserHive,LogTypeError
  ZTIProcess=70
  Exit Function
End If
oLogging.CreateEntry sSName & ": Default User Hive Loaded to " & sTempHive,LogTypeInfo
oLogging.CreateEntry sSName & ": Starting Registry Changes... ",LogTypeInfo

Now that the hive is loaded we can start changing stuff...as an example - I have set the code to change the wallpaper and the screen saver for the default user - again with error checking and specific failure codes

This codes sets the wallpaper (the file needs to be where you set the key to :-)

oLogging.CreateEntry sSName & ": Setting Default User Wallpaper",LogTypeInfo
RegPath = "HKEY_USERS\Test\Control Panel\Desktop\"
oshell.RegWrite Regpath & "WallPaper", "C:\Windows\Web\Wallpaper\CorporateWallpaper.bmp", "REG_SZ"
If Err<>0 Then
  oLogging.CreateEntry sSName & ": Failed to update wallpaper file setting",LogTypeError
  ZTIProcess=60
  Exit Function
End If

...and this codes sets the screen saver (again - the file needs to be where you set the key to :-)

oLogging.CreateEntry sSName & ": Setting Default User Screensaver",LogTypeInfo
RegPath = "HKEY_USERS\Test\Control Panel\Desktop\"
oshell.RegWrite Regpath & "SCRNSAVE.EXE", "C:\Windows\CorporateScreensaver.scr", "REG_SZ"
If Err<>0 Then
  oLogging.CreateEntry sSName & ": Failed to update Screensaver settings",LogTypeError
  ZTIProcess=50
  Exit Function
End If

Once all of the changes have been made - its time to unload the hive from its temp key - again with logging and error checking

oLogging.CreateEntry sSName & ": Unloading the Default User hive",LogTypeInfo

oShell.run "reg unload " & sTempHive
If Err<>0 Then
  oLogging.CreateEntry sSName & ": Failed to unload the default user registry hive",LogTypeError
  ZTIProcess=40
  Exit Function
End If
oLogging.CreateEntry sSName & ": Actions completed",LogTypeInfo

The completed script can be added to your MDT task sequence towards the end - so that it runs before the machine SysPreps and reboots for capture.

The complete script - in MDT format (to include logging and access to classes from ZTIUtility.wsf) with a number of other changes included is available on the Deployment Guys SkyDrive:

This post was contributed by Richard Smith a Senior Consultant with Microsoft Services, UK.

Shameless Self-Promotion #1: Elevation PowerToys for Windows Vista

My post for today is a little off topic (although not too far off).  One of the biggest changes to the user experience on Windows Vista is User Account Control (UAC).  I'm not going to repeat the details of UAC here.  My purpose today is to make you aware of some tools that I have created to make UAC more palatable for people who work with UAC on (as we all should) but frequently have to elevate tasks.  Many people in IT fall into this category.  The "deployment" tie-in here is that you can deploy these PowerToys as a Role-based application for IT Admin-type users to improve their UAC experience on Vista.  This will hopefully encourage those who have Administrator rights (either directly or they know the credentials of an Admin account) to stay secure and keep UAC turned on.

I also won't describe the tools here since the TechNet Magazine articles already do that.  Please take a look at both articles if you think these would be useful to you or your organization's "Power Users".  Download the tools from the June 2008 article.  This download has the complete set of tools.

Script Elevation PowerToys for Windows Vista - Utility Spotlight column, TechNet Magazine, June 2007
http://technet.microsoft.com/en-us/magazine/cc162321.aspx

New Elevation PowerToys for Windows Vista, TechNet Magazine, June 2008
http://technet.microsoft.com/en-us/magazine/cc510320.aspx

 

This post was contributed by Michael Murgolo, a Senior Consultant with Microsoft Services - U.S. East Region.

Who are the Deployment Guys

You may be wondering - exactly who is in the crack Deployment Guys and how do I find out more about these special individuals - fear not - for here is the current guide to the Deployment Guys team:

You can revisit our Bio's at any time by using the About link from the blog...

 mvp_hunter_120x160
 
Ben Hunter

 

Location:
Auckland – New Zealand
Job Title:
Consultant – Microsoft New Zealand
Time with Microsoft:
2 years
Special Powers:
I see dead pixels
Favourite food:
Thai
Favourite film:
Quiet Earth
Bio:

 

I focus on  engagements around Windows Vista and Windows Server design and deployment, with a dash of Virtualization on the side. I work closely with other consultants and the Redmond-based teams to develop deployment best practices. I also speak frequently at both TechEd and Microsoft Deployment related events.
Unlike Richard Smith I don’t have any spare time :-( Between working for Microsoft and two young children my days are full.
 mvp_smith_120x160
 
Richard Smith
Location:
Birmingham – United Kingdom
Job Title:
Senior Consultant – Microsoft Consulting Services
Time with Microsoft:
4 years
Special Powers:
Playing a mean piano and taking a top landscape photograph (at the same time!)
Favourite food:
Sausage and Mash
Favourite film:
Die Hard - the first and the best of the quadtrilogy in my humble opinion
Bio:

 

I have worked in the IT industry for over 20 years, and I enjoy working within a cross-sector environment at Microsoft. I deliver engagements around Windows Vista and Windows Server 2008 design and deployment, but have previously delivered consultancy services in Windows Server 2003, Active Directory design, Exchange 2000/2003 and SharePoint Portal Server.  I speak frequently at both TechEd and Microsoft Deployment related events.
In my spare time (not that I have much of that :-) I enjoy writing and producing musical theatre, digital photography, music and video production and anything to do with using technology for creative means.

 

clip_image001
 
Richard Trusson
Location:
Leeds – United Kingdom
Job Title:
Senior Consultant – Microsoft Consulting Services
Time with Microsoft:
10 years
Special Powers:
Flying stunt kites and SCUBA dive to 50m+ (not at the same time!)
Favourite food:
Roast Beef, Yorkshire Pudding, Roast Potatoes and some vegetables
Favourite film:
Stickmen or maybe its Pulp Fiction or maybe The Big Blue or maybe Blues Brothers; some great music in that one.
Depends who is asking and what mood I’m in! ;-)
Bio:

 

I have worked in IT for 20 years since graduating with a Communications Engineering Degree from Leeds. After a brief sabbatical – a year cycling around Nepal, India, Pakistan, China, Australia and New Zealand I joined MS New Zealand nearly 10 years ago. Initially focusing on Active Directory and DNS design I quickly moved to back to the area I love and everyone else depends on – deployment!
I returned to the UK six years ago and continued to focus on highly automated deployment solutions across the whole Microsoft product family. Recently focusing on Vista and Windows Server 2008.
I hold a patent for a deployment methodology and I also speak frequently at both TechEd and Microsoft Deployment related events.
My spare  time is currently taken up with my young family and caving or diving with my friends. When not doing that I am trying to re-learn a musical instrument.

clip_image002

 
Daniel Oxley

 

Location:
Madrid - Spain
Job Title:
Consultant – Microsoft Consulting Services
Time with Microsoft:
1.5 years
Special Powers:
I can play all the Metallica and Megadeth guitar solos note-perfect with my air guitar
Favourite food:
English: Cheeseburger  -  Spanish: A tapas of Jamón Ibérico and Queso Manchego
Favourite film:
Hunt for Red October
Bio:

 

I have been breaking and then fixing computers since I was 8, and doing it professionally for the last 12 years.  Working at Microsoft is good fun, especially in such a talented team as the one I am in as I get to learn something new every single day.
I deliver projects on a broad range of areas, but my specialties are in the deployment of Windows XP/Vista, Active Directory/Group Policy, and scripting.
Although I live in Spain, I am in fact British.  I have been in Madrid for the last 4½ years and absolutely love it; I think it must be the combination of almost year-round sunny days, great food and cold beer!  In my spare time I enjoy watching a good film, seeing new sights in Spain, a good lunch on a terrace in the sun, or having a nice peaceful siesta in the shade.

clip_image002[6]

 
Michael Murgolo

 

Location:
New Jersey – USA
Job Title:
Senior Consultant – Microsoft Consulting Services
Time with Microsoft:
8+ years
Special Powers:
Creating Elevation Powertoys and other cool scripts
Favourite food:
Shrimp Fra Diavolo from Enza's Ristorante in Hawthorne, NJ
Favourite film:
Tie: Star Wars (the original) and the Lord of the Rings Trilogy
Bio:

 

I focus on operating systems, deployment, network services, Active Directory, systems management, automation, and patch management. Most of my recent engagements have been in the area of OS deployment and migration.  I have worked in the IT industry for over 11 years.  In my previous life I worked as a Mechanical Engineer in the areas of product development and machine/tooling design.
I moonlight periodically as a Contributing Editor (authoring and reviewing articles) for TechNet Magazine.
In my spare time I enjoy anything having to do with the accurate reproduction of audio and video for music listening and home theater.  Always calibrate your equipment and use matched loudspeakers for all channels!
Posted by DeploymentGuys | 1 Comments
Filed under: ,

Getting caught out by your logon script

Whenever I go onsite with a customer to start a Windows Vista deployment project I always like to discuss with them the issues that we will be having during the project.  I do this so that, together, we can try and avoid having the issues in the first place.  Most of the issues the customer is already aware of as they have been testing Windows Vista in a laboratory environment for a while; however, there is one issue that nearly always catches them unaware and gives them major headaches, their logon script.

This is often one of the biggest problems that a company will have when trying to deploy Windows Vista.  The reason that most people do not notice that the logon script does not work on Windows Vista is because they have done their testing only in a laboratory environment where the logon script does not exist.

 

Let's look at a hypothetical example.  Contoso developed a MS-DOS based logon script when they first rolled out their systems on Windows NT 4.0.  When Windows 2000 was realised, they made some amendments and added more code to the script in order for it to work on the new platform.  When Windows XP was released, they had to tweak it again and add substantially more code in order to be able to migrate it to the Windows XP platform.  Because the script has been extended each time they rolled out a new OS, it is now a monster of a script with almost 2000 lines of code.

Now, based on their past experience, they have assumed that they will just need to tweak it and probably add some more code so that it works with Windows Vista, consequently, they have not actually gotten around to testing the script yet, nor assign the resources to this task.  Big mistake, because they haven't realised that the chance of the script working 100% on Windows Vista is almost 0.

Why?  The new security model that Windows Vista uses, that's why.  Let me give an example.  Contoso has an application that is vital to their business.  It is an application that requires certain keys to exist in the HKEY_CURRENT_USER section of the registry, and without those keys the application will not start.  Because Contoso users do not have roaming profiles, the IT team added the following line to their logon script to ensure that this application always works, regardless of which computer the user logs on to:

regedit.exe /s %logonserver%\vitalapp.reg

Consequently, when the user logs on the registry file imports the required keys into the registry and the application works correctly, and because this is in the logon script the process is invisible to the end user.  However, if the same script is run on Windows Vista, the following window will appear during the execution of the logon script:

image The famous (or infamous...?) User Account Control (UAC) window

 

This window will appear because the resource regedit.exe is a protected file that requires administrative rights to be able to run it.  Unfortunately for Contoso, their logon script imports 12 different registry files which means that their logon script causes the UAC prompt to appear 12 times.

There are several ways to stop this message appearing, but they all reduce the overall level of security of the operating system (for example, you could disable UAC or give all users admin rights).

But don't panic!  There are plenty of solutions that you can use to solve these issues whilst maintaining the UAC feature and the extra security benefits that it gives.  The method I also recommend to customers is to use custom ADM files to create the registry keys, see here for a good guide on how to do it.  That way, every time the user logs on and receives their group policy configuration, the registry key will be created.  And, because it runs in a different context to the user, it will have enough permissions in the registry to create the keys without invoking the UAC window.

 

If you are considering, or even if you have already started, deploying Windows Vista in your business environment, I strongly recommend that you test your logon script thoroughly and as soon as possible on Windows Vista.  The last thing you want is to have to put the deployment on hold when the problems start appearing.

 

This post was contributed by Daniel Oxley a consultant with Microsoft Services Spain

Implementing the "Windows XP Tablet PC Edition 2005 Single-Image Deployment Supplemental Guide" Process in MDT 2008

For just about as long as there has been Windows XP Tablet PC Edition, there has been a guide on the Microsoft web site for the process of taking a image of Windows XP Professional and "transforming" it at deploy time into Tablet PC Edition.  This guide can currently be found here.  A few years ago, I scripted this process for one customer's home-grown deployment framework.  Last summer I ported this process over to BDD 2007 Lite Touch.  Finally, about a month ago, I moved this process over to MDT 2008 for both Lite Touch and Zero Touch (SCCM) deployment.  In this post, I will review what needs to be done to prepare your Windows XP SP2 or SP3 image to use this process and how to use the scripts (included in the Attachments link below) to implement this process with MDT LTI or MDT ZTI with SCCM.  (Note: This will likely work with BDD 2007 and/or SMS 2003 OSD, but I haven't tested this.  Let me know what happens if you try it by adding a comment to this post.)

To create an image with MDT that will support this process, you need to include the CMPNENTS folder (of the same Service Pack version) from CD 2 of the Tablet PC Edition 2005 media in your Windows XP SP2/SP3 installation media.  I will describe here how to do this with MDT Lite Touch.  After adding the Window XP SP2 or SP3 installation media as an Operating System in the Deployment Workbench, use Windows Explorer to open the Distribution folder.  Copy the CMPNENTS folder from CD 2 of the Tablet PC Edition 2005 media (must be from the matching Service Pack version) into the Windows XP installation media folder at the same level as the i386 folder as shown in the figure below.

Distribution

Then use MDT Lite Touch to build and capture your image.  If you want to use an MDT Task Sequence in SCCM to build and capture your reference image, add the matching CMPNENTS folder to the Window XP SP2 or SP3 installation media before importing it into SCCM as an Operating System Install Package.  This will ensure that the MDT scripts will place the CMPNENTS folder in the \Windows\Source folder in the image.  This is where the scripts expect to find it at deploy time.  (I don't usually recommend doing the following since it can lead to bad image version management habits but if you have an existing Windows XP Professional SP2/SP3 WIM image, you can use ImageX to mount the WIM, copy the matching CMPNENTS folder into the \Windows\Source folder, and commit the changes.  This WIM will then be useable with this process.  Since this is really a new "version" of your image, update any image version tattoo (Registry, file, etc.) in the image as well.  However, if you have already automated the image build with MDT, I recommend that you just rerun the image build and capture instead.)

After your image has been updated in this manner, you must then update MDT.  There are two parts to this process.  The first part is determining whether the target computer is a Tablet PC and the second is executing the scripted changes to convert the OS to Tablet PC Edition if the target computer is a Tablet PC.  There are a numbers of ways to determine whether the target computer is a Tablet PC.  You could add a custom property to Make/Model detection called IsTablet (must have a value of True or False). If you are using CustomSettings.ini to store your Make/Model information, you would put a direct entry in the CustomSettings.ini Make/Models sections.  If you are using the MDT database, you could add an IsTablet field to the Settings table, populate the IsTalbet field of the Make/Model rows with True or False, and add a database query to CustomSettings.ini to retrieve the IsTalbet field.

However, I took another approach that I find simpler to maintain.  It involves detecting whether the target computer has Tablet digitizer hardware.  I add a custom property to CustomSettings.ini called TabletPnpIds.  In this property I place a comma separated list of the Plug & Play Device ID's of the digitizer devices on all supported Tablet PC model.  Then a user exit script uses this list to determine if the target computer is a Tablet PC and set the IsTablet property accordingly.

To update MDT to use my entire process, use the following steps (respecting any change management process or change windows you have, of course).  If you want to use your own method of setting IsTablet, then you can skip the Edit CustomSettings.ini for detecting Tablet PC hardware steps and implement you own method.

  • Add the Custom Scripts to the MDT Scripts:  First, extract the two scripts from the attached ZIP file and add them to either your LTI Scripts folder or your SCCM MDT File package.  Be sure to update your MDT Files package and Distribution points in SCCM after doing this.

  • Edit CustomSettings.ini for Detecting Tablet PC Hardware:  You will need to add the following to CustomSetting.ini to use my method of determining whether the target computer is a Tablet PC (additions in blue).

    [Settings]
    Priority=IsTabletCheck, Default
    Properties=MyCustomProperty, TabletPnpIds, IsTablet

    [IsTabletCheck]
    TabletPnpIds=ACPI\WACF004\,ACPI\WACF008\,ACPI\MAI3310\,ACPI\FUJ02E5\
    UserExit=ZTI-DectectTabletExit.vbs
    IsTablet=#DetectTabletPC#

    You will need to populate TabletPnpIds property with the digitizer Device ID's for your Tablet PC models.  To determine the Plug & Play Device ID's of the digitizer devices, you will need one of each supported Tablet PC model with Windows XP SP2 or higher or Windows Vista already installed and the digitizer driver installed.  On each PC, open Device Manager and find the entry for the digitizer device.  This will likely be under the Human Interface Devices category and will likely have the word "Pen" or "Digitizer" in its name.  Right click on the device and select Properties.  On the Details tab, select Device Instance Id (or Device Instance Path on Vista) from the drop down list.

    DeviceMgr    DeviceID

    In the case of the "Wacom Penabled MiniDriver" shown above, the Device Instance Id is ACPI\WACF004\4&2F7DB942&0.  The portion of this ID up to the last backslash, ACPI\WACF004, is the Device ID.  The portion after the last backslash, 4&2F7DB942&0, is the Instance ID for this device.  The Device ID is one of several hardware ID's embedded in the device by the manufacturer to be used for Plug & Play detection.  The Instance ID is a unique identifier assigned to a particular device by Windows when it is detected.  The Instance ID allows Windows to uniquely identify a device when there is more than one of the same device present in the system (for example, two of the same model network card).  The part we are interested in is the Device ID.  Put the Device IDs, including a trailing backslash, in the TabletPnpIds entry separated by commas.

    The last two entries in the IsTabletCheck section tell the MDT Gather task to run ZTI-DectectTabletExit.vbs and set the IsTablet custom property to the result of the DectectTabletPC function in the script.

  • Edit CustomSettings.ini for Setting the Tablet PC Edition Volume License Key:  The next changes to CustomSetting.ini set a custom property called XPTabletProductKey to your Tablet PC Edition Volume License Key.  If you do not have one and you are a Select License, Enterprise Agreement, and Enterprise Subscription Agreement customer, then see the Notes section in the Single Image Deployment Guide to obtain one.

    Add the following changes to CustomSetting.ini so that XPTabletProductKey will have a value when IsTablet is true.  Replace AAAAA-BBBBB-CCCCC-DDDDD-EEEEE with your Tablet PC Edition Volume License Key.  (Additions for this part in green):

    [Settings]
    Priority=IsTabletCheck, ByTabletType, Default
    Properties=MyCustomProperty, TabletPnpIds, IsTablet, XPTabletProductKey

    [IsTabletCheck]
    TabletPnpIds=ACPI\WACF004\,ACPI\WACF008\,ACPI\MAI3310\,ACPI\FUJ02E5\
    UserExit=ZTI-DectectTabletExit.vbs
    IsTablet=#DetectTabletPC#

    [ByTabletType]
    Subsection=Tablet-%IsTablet%

    [Tablet-True]
    XPTabletProductKey=AAAAA-BBBBB-CCCCC-DDDDD-EEEEE

    If you are using SCCM, remember to update your Settings Package with the updated CustomSetting.ini.

  • Edit the Task Sequence to Add a Step to Run ZTI-XPTabletSingleImage.wsf:  The next step is to edit the Lite Touch or SCCM MDT Task Sequence to run ZTI-XPTabletSingleImage.wsf during the middle of the PostInstall phase.  The picture below shows this for an SCCM MDT Task Sequence.

    Task

    For an SCCM MDT Task Sequence, be sure to check the Package box and select your MDT Files package.

  • Import Digitizer Drivers:  This should go without saying but you must import digitizer drivers into the Deployment Workbench for LTI or into the Drivers library and add them to Driver Package(s) for SCCM.  The Single Image Deployment Guide shows how to extract the "in the box" digitizer drivers.  But if you don't have any devices that need them, use the PC manufacturer's drivers instead.  You do not need to place any drivers in the C:\Sysprep\i386\Digitizer folder as shown in the Guide.  Use the Deployment Workbench Out-of-Box Drivers or SCCM Driver Packages to handle drivers instead.

That completes the setup.  When you deploy this XP Task Sequence to a Tablet PC, your Windows XP Professional Image should magically transform into Windows XP Tablet PC Edition 2005.  If you want to test this process and don't have any Tablet PC's handy or you want to test using Virtual Machines (Virtual PC, Virtual Server, Hyper-V, VMWare, etc.) then use the following trick.  Pick a device on your target computer (it's not really important which one it is) and place it's Device ID in the TabletPnpIds list.  This will cause the IsTablet property to evaluate to True for this machine and it will result in Tablet PC Edition being installed on this non-Tablet computer.

12 June 2008 - Important Update

In this post, I described using this process with MDT 2008.  Since that time, another Microsoft Consultant (Barry Hartmann of MCS Federal, thanks Barry!) encountered an issue with this process if you have the .NET Framework installed in your Windows XP Professional image. The XP Pro to Tablet PC Edition conversion uses a rather unintelligent, brute force installation process to install .NET Framework 1.0 (which is required by some Tablet PC Edition components).  If a newer version of the .NET Framework is installed in your image, this process will downgrade shared files and registry values.  This essentially breaks the newer version of the .NET Framework. 

Barry encountered this problem when he tried to install Project 2003 on a machine deployed with the "single image" process that had the .NET Framework 3.5 installed in the original XP Pro image.  The Project installation fails with the .NET Framework in this state.

The one obvious solution (the one my customer has chosen) is to not include the .NET Framework in the XP Pro image.  My customer will be installing .NET Framework 3.5 as an operating system specific post deployment item in the SCCM Task Sequence.  The other thing that seems to correct this if the .NET Framework is in the image, according to Barry's testing, is to initiate a repair on the highest version of the core Framework installed (1.1 or 2.0) after the deployment/conversion process.

These blog posts referenced below contain the command lines you should be able to use to repair the .NET Framework 2.0 RTM and 2.0 SP1:

Finally, a few fixes were made to one of the scripts.  Barry discovered incorrect paths were written to files in certain SCCM deployment scenarios.  The attachment has been updated with the newer version.

Please post comments with any feedback, suggestions, or issues.

 

This post was contributed by Michael Murgolo, a Senior Consultant with Microsoft Services - U.S. East Region.

Off Topic: Embedding Sky Drive Links

I have been asked a number of times now how we embed links to SkyDrive hosted files in our blogs. In this Off Topic post I'll cover how you can setup a SkyDrive folder and embed links as we do or send URLs to the files in emails. This would be great if ( when ! ;-) ) you have problems and want to post the MDT logs somewhere for review or have other files you want to share with people outside your company. SkyDrive gives you 5Gb of storage space for free - we hope this will keep the Deployment Guys going for the next few months!

I have broken the post into three main sections; however the whole process is very simple and took me about 10 mins the first time I did it, this includes setting up the SkyDrive. Now I can post a file and embed the link in 1-2 mins each time.

 

Setting Up a SkyDrive

To setup a SkyDrive you will need a Live ID, if you already have a hotmail account or Passport ID then you are good to go. If not then you need to create one. You can create these in a number of 'formats' using a generic email address such e.g ending in @live.com or using your own domain name; fred@contoso.com. To create your Live ID go to http://get.live.com/

Once you have your live ID go to the SkyDrive site, http://skydrive.live.com, and click on the Get Started button in the middle of the page.

You will be asked to sign in and then presented with your SkyDrive home page. From here you can create and manage folders.

Setting Security on your SkyDrive

Security on your SkyDrive is controlled by Live IDs and the 'All Internet Users' group.

You can grant access to folders you create to specific Live IDs or to the whole Internet - by default only you have access to the folders. For example in the Deployment Guys SkyDrive folder we have granted all Internet Users read access the the Deployment Guys folder. We have granted specific Live IDs full control of the folder. The advantage of granting individual Live IDs access is that they can use their Live IDs to sign in to their SkyDrives - they will then see a list of SkyDrives they have specifically been granted access to on their SkyDrive home page.

So when you setup your SkyDrive make sure you know who is going to be accessing it and what their Live ID is. Although you can modify the list later on to add or remove users or change users from Editor to Reader or vice versa.

Uploading and sharing a SkyDrive file

There are two ways to upload a file to SkyDrive;

1) Using the web interface

2) Using the file upload tool

I use the web interface to that's the one I'll cover here. Once you have created the folder you want to share now click on the add files link. If you know the full path of the file you want to add just type it here. If you don't then click the browse button. While the file is loading you get the chance to play a game. Why? Just what is the point - of the game or presenting it? I have no idea. Once the file has loaded you can share it out.

NOTE: Large files that are close to the maximum file size limit for skydrive may take a while to become available to everyone who may try to access it as the content is replicated around the backend servers - as some of you have found when accessing some of the video files. If you are going to make a big file available upload it some time before you publish the link. The bigger the file the longer you should wait before you publish.

There are two ways to share out files on your SkyDrive site.

1) Using an embedded link - this is how we do it in the blog

2) using a web address you can post into an email.

Find the file you have uploaded and click on it. To the left you will see a dialogue with two URLs listed. To get the effect we use in the blog copy the embedded one, circled below.

 image

If you use the Embed button, Embed button , instead you get to change how the embedded link will look.

image

If you want to email a link to someone; either copy the Web Address or click the send link button above the file. This will attempt to open your default mail program - so you may get a security alert depending on which OS your are running and what security settings you have.

image

 

NOTE:

SkyDrive has an individual file limit of 50Mb - this is enough for most things. Richards Smiths videos only just fit though and that was after some re-work by him. So watch out how big you make those files. If you ZIP files you can always split the ZIPs into 50Mb chunks.

Some of the blog writing software have plugins to Insert a SkyDrive embedded link. I must confess I have had mixed success with these. My success rate is higher with just copying and pasting the link from the web page.

This post was contributed by Richard Trusson a Senior Consultant with Microsoft Services, UK.

Posted by rtrusson | 0 Comments

OSD: Forcing a reboot

In this post I will talk about the method I use to force a reboot at the end of a ZTI task sequence; when running from OSD. This solution was put together with input from Richard Smith a fellow Deployment Guy and also with help from Avanade/Accenture - Chris Bird, Jonathan Goulding, Chris Urwin and Steven Westwell. We developed this to help us enable BitLocker as part of an OSD deployment. I'll post the scripts and steps for doing that a little later. This post covers some of the ground work that made enabling BitLocker possible, there is a whole lot more around drive partitioning - but that is for another post.

So why would we need a special way to force a reboot of a ZTI/OSD build? During the build process any reboots requested by the task sequence or applications, such as BitLocker install, are suppressed. Take a look in the log file of a build and you'll see the occasional entry saying that OSD has suppressed a reboot. You may have other things that you need a reboot for at the end of your build process.

It is important to point out that this forced reboot only occurs at the end of the OSD process. We can not force a reboot during that process and have OSD carry on.

OSD Process Overview

Before we can start writing scripts it is important to cover off what happens when the OSD process runs in a deployed OS. After an OS has been deployed and mini-setup has run the system reboots. On reboot OSD deployment (Zerotouch Installation) starts before the system has reached a logon prompt/the desktop. So OSD never actually logons to the desktop - it all happens prior to the GINA being displayed. Next time you do an OSD build watch it carefully at the end. OSD ends and you are presented with the CTRL+ALT+DEL prompt - this is the first time the OS will have reached this stage.

So knowing this how do we force our reboot? Well we have to logon of course!

The reboot process.

You may want to grab the sample scripts (see the link at the end) to follow through them as I discuss this process.

Forcing the reboot is a two stage process;

  1. Logon to the desktop
  2. run a script/cmd to reboot.

I set the system up to auto logon as part of the ZTI task list - this means I can take advantage of BDD environment variables to get the local administrator username and password. The other thing I must think about is am I going to run a script at logon or a command? If I am going to run a script then I need to grab these and place them in a directory structure outside c:\minint. Remember c:\minint gets deleted once OSD completes. The script, z-OSDPart1.wsf does these tasks. Firstly it copies down any scripts we'll need later to c:\OSDTemp. Then SetAutoRun function sets up the autologon keys and configures the runonce key to call the next script, z-OSDPart2.vbs

Once the OSD task sequence completes the system will now autologon and run the z-OSDPart2.vbs script. This second script can be quite simple (as in this example) or more complex. When I post on getting BitLocker working well see an example. So z-OSDPart2 clears out the autologon entries and issues a reboot. Note that when this runs, because it is running as a runonce command, z-OSDPart2 runs before the desktop can fully establish itself. So you will see the logon start to happen and then the machine will restart. This is a bit of a hidden bonus as anyone walking past the machine at this point will not get the chance to access the desktop while it is logged on as administrator - depending on what you have z-OSDPart2 do of course.

So your OSD machine should now have restarted and be back at a logon prompt.

When I post about getting Bitlocker working we'll actually have it logon again and do some more tasks. Remember that once OSD has completed you no longer have access to the scripts and environment variables so any tasks you get it to do must be self contained.

The sample scripts are linked below. Once you have them you will need to drop them into the distribution scripts directory and then update all your deployment point scripts directories (don't forget the ones on your SMS servers as well) so you can use them. Also because z-OSDPart1 referances z-OSDPart2 if you change the name of the second script you will need to change it in the first one as well.

 

This post was contributed by Richard Trusson a Senior Consultant with Microsoft Services, UK.

Posted by rtrusson | 7 Comments
More Posts Next page »
 
Page view tracker