January 2009 - Posts
First off some credit to Aaron Stebner since i pulled a lot of this from his blog and that’s where i found the information first. He has a ton of information on .Net Framework on his blog.
One of the frustrating things about troubleshooting installs is not having log files to review, or figure out who is running when. There have been times where i’ve created a custom new image that has advanced MSI logging turned on so i can see what is going on during the State Restore phase of the SMS ZTI process.
Here are the steps to enable logging for MSI based installations.
- Click on the Start menu, choose Run, type cmd and click OK
- Run this command in the cmd prompt: reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer" /v Debug /t REG_DWORD /d 7 /f
- Run this command in the cmd prompt: reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer" /v Logging /t REG_SZ /d voicewarmupx! /f
- Re-run the setup and let it fail one more time
- Go to your temporary folder (go to the Start menu, choose Run, and type %temp%)
- Locate a file named msi*.log (where * is a randomly generated set of letters and numbers)
- Zip the msi*.log file (because it tends to be very large but since it is text it compresses nicely)
- Run this command in the cmd prompt: reg delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer" /v Debug /f
- Run this command in the cmd prompt: reg delete "HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer" /v Logging /f
This will create logs in the %TEMP% folder that you can review.
You can also review this KB article from Microsoft:
So as i’ve mentioned in previous blogs, i’ve been working with dynamic applications quite a bit lately. The one issue i kept running into lately was 1618 error codes for the execution history. Eventually i was able to resolve everything, but there were a few reasons for those types of errors to show up, so i wanted to create a blog to help others troubleshoot the issue. Obviously the 1618 error messages are related to MSI based installs. So you won’t receive such an error with a setup.exe or another type of install.
I found 2 main causes of the 1618 error codes, and you could have one or both of the issues in your environment depending on configurations.
1) Conflicting installs with SMS 2003
2) SMS Client Health Script
1 - Conflicting install with SMS 2003
I specifically mention SMS 2003 here because from what i understand and have been told, SCCM does not have this issue anymore. Essentially what happens is that when ZTIPackages is installing it’s applications, SMS can also attempt to install it’s applications, so you end up with 2 MSI installs trying to run at the same time and one of them will work, the other(s) will fail with the 1618 error code which is “another installation in progress.” I didn’t run into this problem very often, if at all, on a new computer build, since there wouldn’t be a client history and standing advertisements. However, the problem was very easy to reproduce when doing a ZTI through SMS. Since the advertisements were standing and ready to go, when the machine was doing imaging and back online, there was enough time while ZTIPackages was running for the client to receive it’s policies and attempt to start installing the requested applications.
So, now that we identified the issue, how do we resolve it? Well simply we need to “take care” of the SMS Client, and stop it from doing anything while ZTIPackages is running. The 2 best ways to do this are to either stop the SMS Client Service, or to disable the Software Distribution Component. Disabling the Software Distribution component is a more reliable method, but also has a great risk since you are disabling the component, if your “re-enable” script doesn’t work, you are stuck with a machine or machines that won’t install software until the issue is resolved. Stopping the SMS server (CCMEXEC) works as well, but is less reliable, because if the service starts up again for some reason, you are back to square 1 and installs will start conflicting.
Stopping the CCMEXEC service:
You can use a few methods of stopping the service. You can use simple command lines like “net stop” and “sc stop”, along with “net start” and “sc start”. Or you could use a more advanced method calling a script. Here is a script from the Deployment Guys that allows you to stop and start a service. Here is the usage of the script:
Usage: cscript zCFG-Services.wsf [/service:ServiceName] [/state:Start or Stop] [/debug:true]
NOTE: /service:ServiceName is case sensitive. /state: can be Start or Stop only
Any of the above methods will work, just each have their advantages and disadvantages. Just remember to restart the service back up after the fact. I typically put the stop service command at the beginning of the State Restore phase. I restart the service after User State in the State Restore phase, this makes sure that no program from SMS are running while you are restoring the user state data. The only important thing is that you are stopping and starting the service before/after ZTIpackages, “Install Packages”.
Disabling the Software Distribution agent:
I’ve blogged on this before, so i won’t repost that info again. The information you need is located here: http://myitforum.com/cs2/blogs/cnackers/archive/2009/01/25/pausing-or-stopping-sms-software-distribution.aspx
If you are using this method, I disable the agent before ZTIPackages runs, and i re-enable it after USMT restores user data.
2 - SMS Client Health Script
The client health script is a wonderful script created by some of the guys on MyITForum that work with Dudeworks. This is a great free solution to dealing with common client issues and just keeping a good watch over your clients. Typically you would configure this script to run through Group Policy as a start up script.
I did run into a few issues with the script and conflicting with the Dynamic Applications process. Here are the checks that can be enabled/disabled for the script to verify.
do_CHK_CCMEXEC = true
do_CHK_SYSTEMPATH = true
do_CHK_AUTOUPDATE = true
do_CHK_SMSLOCALADMIN = false
do_CHK_ADMSHARE = true
do_CHK_RemoteReg = true
do_CHK_WMI_SERVICE = true
do_CHK_BITS_SERVICE = true
do_CHK_REGXML = true
do_CHK_AdvClient = true
do_SEND_CCR = true
do_RUN_CCMSETUP = false
do_CHK_CACHESIZE = false
So first off you can see the script is checking for the CCMEXEC service to be started :) Well that’s a problem if we are stopping it for ZTIPackages to run. Depending on the alignment of the planets (or just simple timing), the startup script will see that CCMEXEC is stopped and restart it, which then allows SMS to start running programs again, which will give you the wonderful application conflicts, again.
The next main point of interest is “RUN_CCMSETUP”. If some of the checks fail, the script will automatically initiate a reinstall of the SMS Client. Which is a MSI based install :) So you can also end up with some 1618 failures, because the SMS Client will be reinstalling while ZTIPackages starts running it’s first few applications.
Now if you are using the disable software distribution agent method, software distribution will still be disabled, so the only issue that will likely run into is that the first few applications from ZTIPackages might fail with a 1618 error code because of the SMS Client being reinstalled. In my case, only my first application was failing, everything else would go through successfully after the fact. Quite frustrating. If you are stopping/starting the service, you will most likely have more failures since you will have ZTIPackages and SMS butting heads throughout the ZTIPackages process, it’s first come first serve.
Hope that information helps, let me know if you have any questions.
I’ve answered this question multiple times in the forums. Someone is looking for a way to copy their packages to a new DP they’ve created, or want to remove multiple packages from a DP. Question is always asked, is there a tool to do this? Well yes there is! Yet another fantastic tool from Roger Zander. Enter stage right…. SMS CloneDP.
This tool lets you copy or remove packages from a Distribution Point. You can browse by packages and then select the DP you want to remove or add the packages to, or you can select a DP and then browse all packages on that DP and then copy or remove those packages from another DP. There is even a nifty little check box that lets you only assign missing packages. I use it quiet often to make sure that i’ve copied all my packages to my remote locations. Much easier to go through and assign missing packages than try to browse all my packages in the SMS admin console and determine if I’m missing something from a remote DP.
SMS CloneDP Link:
If you’ve ever needed to freeze software distribution for a period of time, or just disable it all together on a client, here's how to use an SMS local policy override for SW Distribution. I always name my files with a Z* or ZTI* in front of them so that when i place them in my MDT \scripts folder, they are automatically copied to my deployment points. If you are adding these files to your SMS OSD package, remember to make sure you add them as required files to a phase under the OSD program, otherwise SMS will not pull them into your OSD package source folder.
Disabling Software Distribution Agent
Save the below text as a file like ZTI-SMSSD-Disable.mof or download the files I posted below.
instance of CCM_SoftwareDistributionClientConfig
SiteSettingsKey = 1;
PolicySource = "Local";
//override only this property, all others from the Site/Management
Enabled = FALSE;
I would first run a mofcomp –check on the file to make sure your file is valid. Then to run it on a client, you would run “mofcomp ZTI-SMSSD-Disable.mof”
You can view the execmgr.log to see the entry stating “Software Distribution Agent was disabled”.
You could also look at Control Panel –> Systems Management –> Components Tab, you should see that the SMS Software Distribution Agent is disabled.
Enabling Software Distribution Agent
If you want to re-enable it, here is a VB script that will do the trick.
Set objSWbemServices = GetObject("winmgmts:" &_
Set objSWbemRequestedConfig = GetObject("winmgmts:\\." &_
Set colSWbemObjectSet = objSWbemRequestedConfig.ExecQuery _
("SELECT * from CCM_SoftwareDistributionClientConfig")
For Each objSWbemObject In colSWbemObjectSet
if objSWbemObject.PolicySource = "Local" then
Here are the files: ZTI-SMSSD-Scripts
Nothing like sitting at work on a Saturday waiting for things to run…
Was browsing forums and found these links posted, pretty neat GUI’s for USMT that people have developed.
USER STATE MIGRATION TOOL - GRAPHICAL UI
WORKSTATION MIGRATION ASSISTANT
I’ve seen a lot of various posts discussing drivers and the best way to manage them. SCCM has some great built-in features for dealing with drivers, but not all of us have the ability to upgrade to SCCM just quite yet. So, what is the best way to handle drivers if you have MDT 2008 and SMS 2003? Well hopefully I can help explain the various options and then you can choose what works best for your environment. This post will address MDT 2008, SMS 2003, and Windows XP and I’m assuming you have some knowledge of working with the workbench and SMS OSD.
When I talk about drivers, i like to break it down into a few categories, well fundamentally, 2 categories, 99.9% of your drivers will fit into one of these two categories.
1) Mass Storage Drivers
2) Everything else
Mass Storage Drivers
Windows Vista – I won’t touch on this, we don’t have this in our environment currently so my knowledge is limited
Windows XP – Without getting into great deal, the best way to deal with mass storage drivers is simply that they need to be included in your image before you capture it and correctly identified in your sysprep.inf file
See this post for more information:
Most of your drivers can be extracted out, and I would recommend cleaning up the unnecessary files to help keep the sizes down. If you have .exe driver that doesn’t extract out, i have used Driver Genius Professional in the past to create the necessary files that I needed. It’s a very cool little utility. A good example of this is the Microsoft UAA driver bus you need for most of the Soundmax Audio. Until that UAA bus is installed you cannot install the audio drivers. This is also a good example of why i don’t recommend PNP detection for all of your drivers.
Ok great, that now we’ve covered the driver basics, what about SMS and MDT, what do I actually need to do in order to get this stuff working? Well…
Quick Summary: You only need to make sure that your WinPE source is up to par with the correct mass storage drivers and NIC drivers for your environment.
I’ll talk about SMS first because quite frankly you don’t really have to do a lot in regards to driver management. You really only need to be concerned with making sure the your WinPE source is up to par and has the appropriate mass storage and NIC drivers built into it. Unless you get a new mass storage driver or a new NIC, you don’t need to update your PE source in SMS very often. I would also recommend that you are using WinPE 2005 from a Server 2003 SP1 source, so that you can take advantage of RAMdisk for booting from RIS and for some other things you can use RAMdisk for. I use the source created from the MDT workbench for my WinPE source files. The one thing to note is that you need to re-add your mass storage driver support to the WinPE source everytime you do a full update in the workbench and don’t update just the files. A full update recreates the boot source, and for whatever reason it’s been my experience that MDT will not integrate the SATA drivers into the boot source for you, i’m sure for the same reasons it won’t integrate mass storage drivers into Windows XP for you, assuming it’s just a limitation. So just keep that in mind, if you suddenly are getting a blue screen, or WinPE can’t see your SATA drive.
When you pull in a new PE source, SMS will create a new osdwinpe.wim under your \sms\osd directory. When you do a “update operating system files” on your SMS OSD package, it will pull this new .wim file into your OSD package source folder. You will also see previous versions of your osdwinpe.wim file under the sms\osd folder, so if you suddenly notice a drop in the size, you might want to double check your work.
Here is the meat and bones of driver management with SMS. Most of your work will be done through the work bench in some way shape or form. You can manage drivers with 2 core methods or a combination of them both. The first method is to utilize PNP detection and have MDT pull the drivers and copy them down during the OSD process for you. This works 95% of the time i would say and therefore i don’t typically recommend this method, but it is useful for some scenarios. The other method is to use a method to identify the model and set the driverpath variable for that model and then MDT will copy down everything in that driver path. The one advantage to PNP is that if you have a new model or unknown model, you have a good chance of getting some or all of the drivers to come down for that new model. The one disadvantage to using the driverpaths method, is that if you have a unknown model, you won’t pull anything down for that model.
I also want to touch on a PNP detection issue that i’m not fond of. We utilize Solidworks which is a high-end CAD application in our environment. We run a specific driver version that is certified by Nvidia/ATI to work with a particular version of Solidworks. Most graphics companies utilize a unified driver architecture which is a problem when you want to have certain driver version installed. What typically happens is that when PNP runs, it grabs the “best” “newest” driver, so if you have a particular version of the driver you want (i.e. certified) but your newest laptop needs the most recent unified driver, you have a problem. That “best” driver will now get installed on your workstation that runs CAD, because it’s the “best” driver found during PNP. Now you can modify the INF’s and all sorts of fun messy stuff to get around that, but this is another reason i prefer using what i call the “driver direction” method since I then only have available the driver i want available.
Either method requires the use of the RESOUREROOT variable. This variables needs to be specified in your customsettings.ini file and in your boostrap.ini for it to work correctly. Either method always requires the use of a drivers.xml file, although how they use that file is vastly different.
You will need to point the RESOURCEROOT to either your custom share or the deployment point you want to use in both cs.ini and boostrap.ini
This is the line i use in both files:
DRIVERSMDT$ is my share that contains my drivers for OSD.
In customsettings.ini you would typically put this under the [Default] section, unless you are defining it somewhere else based upon locations or something of your choosing. Note that i’m taking advantage of the %SMSDP% variable, i will normally use as many of the known variables as i can because it makes your task sequence commands and anything else you set much easier to work with.
So if you are using PNP then your need to point the RESOURCEROOT variable to the deployment point you want to use (more info below) and if you are using the other method then you need to point the RESOURCEROOT variable to your share you want to use.
MDT 2008 – PNP
Disclaimer: It’s been awhile since I’ve managed drivers through this method, so it’s possible i have a few things mixed up below, so just be aware that some of what i detail below might not work exactly as i’m describing it, and if so, forgive me and shoot me an email and i’ll correct it. I’m doing my best from memory so that you have the information available to you.
If you are going to use PNP then I would recommend creating a “NETWORK” Deployment Point in the workbench, this will allow you greater control over the drivers you are dealing with. When you create this type of deployment point, then you can make use of driver groups to control what drivers are on that deployment point and thus which drivers are listed in the drivers.xml.
PNP relies upon the drivers you have imported in to the workbench, so anything have listed under “out of box drivers” could be fair game depending on how you configure it. Again this is why i recommend using a network deployment point and creating driver groups when you import drivers. Always assign drivers you are importing to at least one driver group.
Here is an example screenshot of how you can use driver groups to control the drivers in your network deployment point. You can pick and choose the driver groups you want to use and then you will have some control over what drivers PNP is scanning. Also that network deployment point basically becomes a mirror of your Distribution share except you have some control over what files are going there. There is more data copied to that share than you will need for driver integration, but if you were using the Workbench for builds, then you would need the extra info. The only files in the network deployment point that are of interest for what we are talking about are your out of box drivers and the drivers.xml under the \control folder.
So, now that you’ve specified your RESOUREROOT path in both customsettings.ini and boostrap.ini and you’ve created your NETWORK deployment point or whatever you have decided to use, and assuming you have imported the drivers you want to work with, you should be ready to rock. I’m also assuming you’ve made changes to your files and you have updated your deployment point, then used the “update operating system files” action in SMS to pull the files into your OSD packages source, and then updated your Distribution Point(s) in SMS. Once that is all done, you can being testing PNP driver management.
So what will happen is that when the Task Sequence runs, it will pick up on the RESOURCEROOT path and scan the drivers.xml, and then when the “ZTIDrivers” process runs, it will run PNP and copy down all the drivers it finds that match PNP detection to your \Drivers path on the machine being imaged. This is based upon the data contained within the drivers.xml file, which when you are using this method is every driver you have told it to have in the deployment point or workbench. Then it will update sysprep.inf with the new drivers paths, and when your machine images, it will have the drivers found during PNP detection available to it.
Works great as long as the devices are available and don’t have dependencies upon another device being installed. Also works great for unknown machines since it can use whatever you have available, which when working with the same vendor, typically you have alot of the same hardware on various models. However if your new machine has a new NIC, when then you won’t get this far anyways :)
MDT 2008 – Driver “Direction” Method
I’ll call this the direction method and you can do it 2 different ways, one which is preferable i think, but either way you are basically saying, hey look “here” for your drivers! I’ll show you the 2 ways to do this type of driver management, but neither will work without having a drivers.xml in place. Typically you are going to be using a share of some sort in this, i have a folder on my SMS server called \DriversMDT, i then have this configured as package in SMS called “MDT Driver Share”. I prefer to use the Share Distribution folder for data access so i know what the share will be called, otherwise you will have to set your RESOURCEROOT to the \SMSPKGX$\XXXXXXXX\ value, which just seems like you are asking for a typo/mistake. So i prefer this method so you can control the end result and still take use of SMS DP’s for your drivers, so that when you image a machine in another state, it’s not pulling drivers from your primary server.
In the root of this “source” you will want to create a blank XML document labeled “drivers.xml” without this file the driver detection process will halt and you’ll end up with a machine with no drivers. I don’t know why it’s like that, but that’s just the way it is from what I have gathered. The process will run, find the blank file and then continue on to do what what we want. You still see PNP detection in your bdd.log, but that’s fine, there is nothing to detect and no drivers for it to pull down, since drivers.xml is blank.
This method takes advantage of the “driverpaths” variable, this can be set in customsettings.ini, but i typically do it through the task sequence. I like to create a “Driver Management” group in the Preinstall phase, just before the “Inject Drivers” action.
One of the ways to do this driver management method is to simply create a custom task that sets a TS variable.
Task Sequence Variable: DriverPaths1
This will do a model query and then look in the DRIVERSMDT$ share for that model. So, that’s great, but here’s the problem i have with this method. HP doesn’t do a good job with their models :) Because “HP Compaq 6910p (GM120UT#ABA)” and “HP Compaq 6910p (RM231UT#ABA)” are 2 different models, thus you need to have a folder for each model variation, or any possible %model% value that could be returned. So you end up with a nasty folder looking something like this:
So, that’s great, but i like neat and tidy. Like this:
So, how do you get it to look that the above? Well this is method 2. This is why i use a the “Driver Management” group in my TS, to keep it nice and clean. For every model you have, you will need to create a TS step, what will happen is that it will run through all the steps and it will populate your Driverpaths variable when it finds the correct model.
So in this case, you still need to define the TS variable as “DriverPaths1” and then for the value you would put “\\%SMSDP%\driversmdt$\HP NW8240” I’m using the NW8240 as an example. You want to define the folder here, so you are basically saying, i want you to go here for this model and this will be the driverpath you need. What makes this work is a WMI query on the backend. You need to set your queries to “continue on error” so that when the query doesn’t return a result it process the next and so on. Here is the query for the NW8240:
So you can see i’m using a “LIKE” statement so that i can use “%” and thus get rid of the nasty part #’s on the end of the models. This allows me to have a single folder for all variables of that model. Within that folder, i have the drivers needed for that model. Which i think is about 75mb for this model. So when this process runs, i’m only pulling down the 75mb of drivers i need for this exact model.
So now when you run the OSD process, the Task Sequence processes the queries, sets the driverspath and then copies down all the drivers for that model to the \drivers path locally. Then updates sysprep and continues on.
Thus you have dynamic driver management that allows you to control what drivers come down for each model, and you can control the video driver version (my certified driver issue with PNP) and you are only grabbing the drivers you need for the model you are imaging. Also, it’s very easy to update the drivers for a new model, since everything is outside of the image.
That’s it! Let me know if you have any questions! I hope this helps some people out and clarifies a few things.
I have been working on a custom script to move the OSD logs up to the server after a deployment. If you have the debug option enabled, the logs stay after a deployment, then having the MININT folder doesn't allow you to do a new build until that folder is removed, unless you do a ZTI through SMS. So i wanted to have a way to upload the logs to the server before they are wiped and to be to review all the logs, not just the BDD.log, and i posted on the forums and was graciously given this link:
I built off of this and created my own custom tasks for MDT 2008 with SMS 2003. The information above is mostly for SCCM, but it gave me a start.
Here is a screenshot of my TS steps. I just put it on the end of everything, but I might move it around if need be, but for testing purposes this worked.
I haven’t taken my debug switch off quite yet, but at least my logs are being copied up to the server now. I’ll have to see if i can have that step there or if i need to move it around once i take the debug switch off.
Update: I removed the /debug:true from the OSD Program and did some testing and everything seems to be working great. So I no longer have a MININT folder left on the C: drive, and i have a copy of all the logs i need under my log share on the DP.
The command lines i used are:
Make Log Folder
cmd.exe /c mkdir "%SLSHARE%\%COMPUTERNAME%"
Copy Logs to Server
cmd.exe /c copy "C:\MININT\SMSOSD\OSDLOGS\*.log" %SLSHARE%\%COMPUTERNAME%
So basically i just created a custom command line step, and then i’m making use of the built-in TS variables to get the logs copied up to my "logs” share on my DP’s. This allows for the logs to go to the correct server in my remote locations as well.
So far working great.
First and foremost, credit goes to www.smsutils.com for creating the original HTA.
Which can be found here:
And which looks like this:
If you use AD Groups and Collections to distribute your software, this is a must have HTA in my opinion.
We took this and modified the heck out of it to do exactly what we wanted it to do for our environment.
We wanted to be able to select what collection it went to, and what OU in AD it was created in. We only have the one Primary/Central Site, so it’s hardcode to that site code. And then we just cleaned up the interface a bit and removed the things we didn’t need anymore, and thus you see the screenshot below.
Alot of the time i see people confused about exactly how to use $OEM$ to get files copied down.
In it’s simplest form, lets say you have Windows XP SP3.
Here is a screenshot of the structure:
The drivers folder will allow you to put anything you want to come down when you build the image. In my case I have the SATA drivers and the Vmware SCSI drivers come down, those are the ONLY drivers in my image.
Then under system32, i add devcon.exe so i can do any driver updates if need be.
That’s it, much easier to understand i think when you have a visual aid!
I've worked alot with Dynamic Application Deployment over the past few months. The documentation in the MDT toolkit is pretty good, but I did need to change the query to suite my needs. The default query uses ProdID0 in the database, i found that DisplayName0 makes alot more sense, since that is what you actually "see" when you look at the ARP in Control Panel.
Also to note, that i've found it's a good idea to always make sure you specify your SQLShare property for all your database sections in your customsettings.ini, it's also a good idea to use a differen share from your logs, i just use a generic SQL$ share that isn't linked to anything else. Otherwise I've seen some errors on the logs because another process owns that share.
So your new stored procedure would be:
CREATE PROCEDURE [dbo].[RetrievePackages]
SET NOCOUNT ON
/* Select and return all the appropriate records based on current inventory */
SELECT * FROM PackageMapping
WHERE ARPName IN
SELECT DisplayName0 FROM SMS_SZ0.dbo.v_GS_ADD_REMOVE_PROGRAMS a, SMS_SZ0.dbo.v_GS_NETWORK_ADAPTER n
WHERE a.ResourceID = n.ResourceID AND
MACAddress0 = @MacAddress
If you have any questions, feel free to contact me...
Just wanted to post on a bug i found in MDT a few weeks back. If you are working with Dynamic Applications, then you know that you can call applications in customsettings.ini through packages001=(packID):(program name), you can also call packages in the MDT database through a role, make and model, or however you want. What's important to note is your capitlization, basically what will happen is that if you don't have your entires match, you will end up with the same package twice when ZTIPackages processes.
[say, a role package]
What you will see in your logs is that you will have
Packages001 is now SZ000011....
Packages002 is now sz000011...
I emailed Tim Mintner about the bug and i believe it will be fix, but just wanted to post about incase anyone else sees this.
First things first, want to make sure i have this information posted since this is one of the most common things I see on the forums.
In my environment we have mostly HP and Lenovo laptops, which all use Intel SATA, so it's fairly easy for us.
Basically I took HP's sata guide and modified it to encorporate all the steps needed for integration into SMS.
Adding Sata Support to WINPE and SMS 2003 OSD.doc
Also see these threads on MyITforum:
SATA integration -
Finally got my blog up and running. Figured it was about time to start posting some of what I've gathered in the hopes that it helps someone else. Myitforum has been a tremendous help to me and I can only hope that others find it as useful as i have.