narrow default width wide
colour style colour style colour style colour style

MDT Apps using transforms returning 1624

I was just building a new XP SP3 WIM using MDT 2010 and ran into an issue getting ISScript 11.5 installed. The logs showed error 1624. I ran 'net helpmsg 1624' and it returned a transform issue:

Error applying transforms. Verify that the specified transform paths are valid.

I double and triple checked my paths and it all looked good. This is the command line I was using:

msiexec /qb! /i ISScript1150.Msi TRANSFORMS=ISScript1150.mst

So, time to try to manually install to see what happens. Same error. My first thought was the MST was corrupt. So, I re-copied it from a source that I knew was good. Still no go.

Thankfully my next guess was right. It needed a newer version of Windows Installer to install (kind of ironic since ISScript is used to install software). So, I manually installed Windows Installer 4.5 and then ISScript installed just fine.

All that was left after that was to make a new entry in the Task Sequence to install it before the ISScript installation entry.

Ta da!

VBA to convert UTC time to something friendly

I'm doing some account cleanup in a number of directories to prepare for a metadirectory implementation. AD has been as painful as anything to work with. Here's some code that you can use to convert the UTC time that AD likes to use to something a bit more usable. (I dumped everything into Access so I could write a bunch of queries against all of the directories)

I'm having it return 1/1/1601 if the record doesn't exist (i.e. for lastlogontimestamp, the user has never logged on). You could have it return whatever you wanted to though..

Function UTC2Normal(utcDate) As Date
    If utcDate "" Then
        intvartype = VarType(utcDate)
        'utcDate = CDbl(utcDate)
        intutcDate1 = utcDate - 1.16444736E+17
        intutcdate2 = intutcDate1 / 10000000
        intutcDate3 = intutcDate2 / 1440
        intutcdate4 = intutcDate3 / 60
        '148012 = days from 1601 til today (3/31/06)
        '13238 = days from 1970 til today (3/31/06)
        '"d" compare is MUCH faster
        'UTC2Normal = DateAdd("s", intutcdate2, "1970-01-01")
        UTC2Normal = DateAdd("d", intutcdate4, "1970-01-01")
        UTC2Normal = "1/1/1601"
    End If
End Function

Here's some sample SQL syntax to utilize it:

SELECT ADUsers.lastLogonTimestamp, utc2Normal(ADUsers.lastlogontimestamp) AS LastLogonFriendly, * FROM ADUsers;

If you don't care about seconds, just days, use the line in blue instead of the line in green. It is much faster.

To my everlasting shame, it took me about 4 hours to get this working correctly. I kept trying to get it to work using straight SQL but I'm not sure if it was even possible. After beating my head against the wall for way too long I stepped out for a smoke and my brain starting thinking about other options. Presto! Problem solved.

VBA to perform bitwise comparisons

More lessons learned from my account cleanup efforts...

Here is a function you can use to do bitwise comparisons. This is a function I am using in MSAccess for a couple of things to help write queries against AD.

Function SQL_And(Num1 As Long, Num2 As Long) As Long
  SQL_And = (Num1 And Num2)
End Function

Here's the SQL syntax I am using to find Disabled accounts:

SELECT SQL_And(2,ADUsers.userAccountControl) AS Expr1, *
WHERE (((SQL_And(2,[ADUsers].[userAccountControl]))=2));

Here's what I am using to find accounts with password expiration disabled:

SELECT SQL_And(65536,ADUsers.userAccountControl) AS Expr1, *
WHERE (((SQL_And(65536,[ADUsers].[userAccountControl]))=65536));

I mentioned in my other recent VBA post that it took me 4 hours to get a simple function working. This one is even worse....a one line function took me about 6 hours to get working correctly. Most of the time was doing research and trying to get it to work using straight SQL instead of calling a function...It's amazing how sometimes you can crank out 100's of lines of code in a couple of hours but one thing can stump you for hours and hours...

Behavior of Site to Zone Assignment List

We managed to figure out a couple of things concerning this policy setting that is available in IE6/7 under XP SP2 that I couldn't find documented anywhere. This is *THE* setting that I was happiest that they finally included in Group Policy because using proxy exceptions has been about the only decent way to manage them so you could have different security settings for specific sites. Either that or modify a custom ADM every time you wanted to add another site. (Now, if they would just finish the job and get rid of all of the other IE policies that still use that buggy CSE).

First off, a really nice thing. This setting works in conjunction with other policy settings that I was afraid it might conflict with. For instance, if you have your policies setup to add any sites that are in the Proxy Exceptions list to the intranet zone and also configure specific sites to be in the Intranet zone using this policy, the settings from both policies will apply.

Now, the learning points. This may work the same way that adding them manually to security zones works but I do pretty much everything by policy so I can't speak to that.

1. Adding named sites seems to work the same as the proxy exceptions list. You can add something like "*" to a specific zone and all pages at that website will be in that security zone.

2. Adding IP ranges seems to work a bit different than proxy exceptions do. For proxy exceptions, you can add something like "192.168.*" and all sites that begin with 192.168 (the entire class-B range) will be affected.

IP ranges don't work the same in this policy. You have to specify the exact ranges that you want the policy to apply to. To work with the class-B range listed above, you need to use the following: "192.168.1-255.1-255". If you just wanted to add a specific class-C, just use "".  This does actually give you some pretty good flexibility but it probably isn't anything that most people will need. (note: the policy explanation does say that you need to specify ranges, I just couldn't find anything about managing a class-B).

3. Differences in IE6 and IE7: The policy appears to function the same for either version of IE, but the user experience is a bit different. IE7 does it right--if you have this policy set for a security zone, everything is greyed out when you go to manage the sites in that security zone.

IE6 doesn't work quite as well. A user can still go into the settings for a security zone that is managed by this group policy and add sites/IP ranges. But, the settings don't stick. You can hit OK back out of all the internet settings windows and go right back in and the setting won't be there. So, it appears that XP SP2 was made smart enough to use the settings correctly...they just didn't get around to updating the Internet Options windows to grey everything out like most true group policy settings do. So, functionally it is fine under IE6--just possibly a bit confusing if you allow your users to access the security tab in the internet options.

So, kudos to Microsoft on this one. It works like a champ once you figure out the proper syntax for the policy settings.

EDIT: We have since discovered that if you use this policy to configure even 1 zone, it will affect the way that you can manage any and all security zones. So, if you only use this policy to manage the "Local Intranet" zone, anyone who gets the policy will be unable to manage sites in any of the security zones.

Fixing SMS Package deployment to Distribution Points

I've recently done some digging into why certain SMS packages don't make it to either all or specific Distribution Points. As I Googled around I saw that a number of other people were having similar issues and I never saw anyone with a good fix for any of the problems. I've done quite a bit of testing and I think I have a pretty decent process that you can follow to fix these problems.

Before we get into the actual fix, let me share the query I used to identify all of the “bad“ packages.

SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE State != 0

This will return any Package/DP combination where the package hasn't been deployed to that DP properly. I've written a nice little HTA for this that also gets some information about the Package itself (name, manufacturer, etc). A screenshot can be found here. I plan to add an automated fix to the HTA and make it available for download at some point. I may go ahead and compile it in VB.Net...not sure what will make sense at this point.

First off, the obvious things to check or try for a misbehaving package:

  1. Go to System Status->Package Status and browse to the Package/DP having issues. Right-click on the DP and choose “Show Messages“-> “All“. This should show you some useful information on what might be going on.
  2. Confirm that the Source Directory for the Package actually exists.
  3. Try re-pushing the Package to the DP.
  4. Make sure the permissions on your DP are good. I found one DP where the Administrators group had their permissions applied only to the root of the Dist share. This caused problems with any packages that were configured to store themselves in a nested subfolder. SMS was able to create the first level folder but was not able to create the subfolders under that folder.

(Let me preface the next part by saying that almost all of our remote DPs are also CAPs and MPs - I'm not exactly sure what components will be on a separate server if you have these functions split up. The same methods should work though)

Ok, now on to the fun stuff. After doing the things above, I was left with about 50 instances of packages that didn't want to deploy properly.

After doing a bit of digging, I found the following errors in DISTMGR.LOG on the remote DPs for every package that wouldn't deploy:

Processing incoming file E:\SMS\inboxes\\INCOMING\Z3AWAX9I.PKG.
Package 009000B7 requires a newer version (3) of source files and the new compressed files haven't arrived yet, current version is 2, skip E:\SMS\inboxes\\INCOMING\Z3AWAX9I.PKG

My friend Brian Tucker told me about a method he has used in the past to fix these issues. I tried it and it had a good success rate of fixing the issue. The only thing I didn't like about it is the fact that it forces the package to re-deploy too ALL DPs. Sometimes you have a really big package that you don't want to saturate your entire WAN with. Also, I wanted to understand why changing the sourcepath forced the package to redeploy.

This leads us to PCK files. PCK files are the compressed copies of each package that SMS sends to each DP. Once the PCK gets copied to the DP it gets extracted onto the Dist share. At least, that is what is supposed to happen. For the majority of the packages that were misbehaving, this wasn't occurring. I was able to fix the majority of them by using the following process:

  • Manually copy the PCK from \\primaryserver\smsdrive\SMSPKG to \\DPServer\smsdrive\SMSPKG
  • Make sure the Read-Only attribute is set on the PCK file. I also removed the Archive attribute so it would be like all of the other PCK files.
  • Run PreloadPkgOnSite.exe to force the package to decompress and register itself propery at the DP.(PreloadPkgOnSite.exe comes with the SMS 2003 Toolkit 2. All you have to do is give it the Package ID as a command-line parameter)
  • Re-push the package to the DP. You can use the SMS Console for this. This will not copy the compressed content to the server again since we just manually did this. This will just give SMS a little kick to help things along.

During my testing with PCKs I was able to determine why Brian's fix (linked up above) works most of the time. Whenever you change the sourcepath on a package, it regenerates the PCK on the Primary. The new PCK is then deployed to all of the SMS servers. It seems to go ahead and push itself on through on the DPs that were having problems fairly well after this. I have a feeling this is because the package has a new source version so the problematic DPs start the entire deployment process over again. Also, I found that I didn't have to permanently change the sourcepath on the package. All I had to do was just add a number to the end of it and then go right back into the sourcepath and change it right back to what it originally was set to. This way you don't have to actually rename the folder on the file server.

While testing this process I did run into a few cases where updating the source path did not generate a new PCK. If you are ok with redeploying to all DPs, I found that you could go ahead and delete/rename the PCK on the Primary (located at \\primaryserver\smsdrive\SMSPKG ) and then update the sourcepath and detailed above. This will definitely force it to regenerate the PCK on the Primary.

Now for the remaining packages... I had a few that were giving me the following error when I tried to run PreloadPkgOnSite.exe on them:

The compressed package path for package 0090002C is already set in the database
OR this is the site where the package was created.
 There is no need to use this tool for this package on this site.

Apparently these packages got just a little bit further into the deployment process before they bombed out. I was able to get around this problem by deleting \INBOXES\DISTMGR.BOX\packageid.PKG on the DP. Then I was able to run PreloadPkgOnSite.exe on that DP for that package without any problems.

You might have to re-push the package to the DP before running PreloadPkgOnSite.exe. If you get the following error, just re-push and wait a few minutes:

Failed to get the specified package 0090002C in the database. Please check if you have instance rights to that package.

You should see the following when it works properly:

Forward package status for pkg 0090002C to site 009
****** Successfully set the Compressed Package Path on this site ******
****** Successfully forwarded the information up the hierarchy ******

Note: At any time, feel free to go into the SMS Console and re-push the package to the DP. It really seemed to help kick things through once I did some of the other steps to fix the underlying issue. I always did a re-push after running PreloadPkgOnSite.exe.

That's pretty much it. These steps might not work for every situation but I have a feeling that most people running into this problem can fix the majority of their issues with these steps.

Other misc. info I found while doing my testing:

  • Each package also gets the following files generated when it gets deployed:
    • \SMS\inboxes\\packageid.NAL
    • \SMS\inboxes\\packageid.PKG
    • \SMS\inboxes\\packageid.ICO (this is a folder)
    • \SMS\inboxes\\packageid.CLF
    • \CAP_XXX\\packageid.NAL
    • \CAP_XXX\\packageid.PKG
    • \CAP_XXX\\packageid.ICO (this is a folder)

I messed around with deleting these files to help things along but it didn't seem to make a difference.

  • Removing the package from a DP (via the SMS Console) and then re-adding it never seemed to help things much.

Script to find SMS Packages with bad SourcePaths

This is a simple little VBS script that will help you to find SMS Packages that are pointing to a Source Path that doesn't exist. I just threw it together but I plan to set it up as a scheduled task that runs nightly. I'll have it e-mail me whenever it finds a package without a valid Source Path so we can get it fixed right away instead of waiting for someone to call and complain.

Not a whole lot to it really. You might want to take a look at the query:

SELECT PkgSourcePath, Name FROM SMS_Package WHERE PkgSourceFlag != '1'

Only checking packages that have PkgSourceFlag something other than '1' makes sure we only check for Packages that are configured to use source files.

The script runs really fast. It checked 400+ packages in around 5 seconds. I was a little surprised that it ran that fast since it had to use the FileSystemObject to check for the existence of each one of the source paths.

Just update the server name and the Site Code for your environment....

Option Explicit
'On Error Resume Next

Dim objWMIService, SWBemlocator, colItems, objItem
Dim UserName, Password
Dim strComputer, objFSO
strComputer = "servername"
UserName = ""
Password = ""
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set SWBemlocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = SWBemlocator.ConnectServer(strComputer,"\root\sms\site_XXX",UserName,Password)
Set colItems = objWMIService.ExecQuery("Select PkgSourcePath, Name from SMS_Package where PkgSourceFlag != '1'",,48)
For Each objItem in colItems
 If objFSO.FolderExists(objItem.PkgSourcePath) Then
  'WScript.Echo "OK"
  'WScript.Echo "NO SOURCE"
  WScript.Echo objItem.Name & vbTab & objItem.PkgSourcePath
 End If