.NET 3.5 (NetFx3) Installation Fails With Error 3017 And HRESULT 80070BC9 on Server 2012 R2

Recently, when rebuilding my System Center Configuration Manager 2012 lab, I ran into an issue.  I was preinstalling SQL Server 2012 and hit a snag.

Image: Error while enabling Windows Feature: NetFx3 Please enable Windows Feature NetFx3 from Windows management tools and then run setup again.

It seems that for whatever reason the SQL installer could not install the .NET 3.5 framework. Thinking this would be a simple fix I opened up PowerShell, fired off a quick Install-WindowsFeature and… it also failed.  Puzzled I headed to the Internet.  As it turns out this was a common problem and quite a few others suggested using DISM in online mode to install the feature either by pointing direct to the source media

Dism /online /enable-feature /featurename:NetFx3 /All /Source:D:\sources\sxs /LimitAccess

or by obtaining the feature from windows update

Dism /online /enable-feature /featurename:NetFx3 /All

Neither worked.  Both returned the error 3017, which basically means “something broke, you need to restart to roll back the installation”.  Examining C:\Windows\Logs\DISM\dism.log revealed the following:

DISM Package Manager: PID=2536 TID=352 Error in operation: (null) (CBS HRESULT=0x80070bc9) - CCbsConUIHandler::Error
DISM Package Manager: PID=2536 TID=2292 Failed finalizing changes. - CDISMPackageManager::Internal_Finalize(hr:0x80070bc9)
DISM Package Manager: PID=2536 TID=2292 Failed processing package changes with session options - CDISMPackageManager::ProcessChangesWithOptions(hr:0x80070bc9)
DISM Package Manager: PID=2536 TID=2292 Failed ProcessChanges. - CPackageManagerCLIHandler::Private_ProcessFeatureChange(hr:0x80070bc9)
DISM Package Manager: PID=2536 TID=2292 Failed while processing command enable-feature. - CPackageManagerCLIHandler::ExecuteCmdLine(hr:0x80070bc9)
DISM Package Manager: PID=2536 TID=2292 Further logs for online package and feature related operations can be found at %WINDIR%\logs\CBS\cbs.log - CPackageManagerCLIHandler::ExecuteCmdLine
DISM.EXE: DISM Package Manager processed the command line but failed. HRESULT=80070BC9

While not terribly helpful the DISM log tells us where we can get more information.  The cbs.log showed:

Info CSI 000000a7 Begin executing advanced installer phase 34 (0x00000022) index 246 (0x00000000000000f6) (sequence 278)
     Old component: [l:0]""
     New component: [ml:276{138},l:274{137}]"WWF-PerfCnt_ini, Culture=neutral, Version=6.3.9600.16384, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=x86, versionScope=NonSxS"
     Install mode: install
     Installer ID: {d82eedee-854e-4f9a-b458-ae1bc62a0e6b}
     Installer name: [16]"LodCtr Installer"
Info CSI 000000a8 Performing 1 operations; 1 are not lock/unlock and follow:
     (0) LockComponentPath (10): flags: 0 comp: {l:16 b:547843cbc942cf0124030000e4088408} pathid: {l:16 b:547843cbc942cf0125030000e4088408} path: [l:184{92}]"\SystemRoot\WinSxS\x86_wwf-perfcnt_ini_31bf3856ad364e35_6.3.9600.16384_none_086429b116eaedfd" pid: 8e4 starttime: 130396348381515426 (0x01cf42c9b949cea2)
Error CSI 00000002@2014/3/18:16:47:48.324 (F) Logged @2014/3/18:16:47:48.324 : [ml:242{121},l:240{120}]"RegQueryValue_ServiceFirstCounter("SYSTEM\CurrentControlSet\Services","Windows Workflow Foundation 3.0.0.0") fails (2,0)"
[gle=0x80004005]
Error CSI 00000003@2014/3/18:16:47:48.324 (F) Logged @2014/3/18:16:47:48.324 : [ml:354{177},l:352{176}]"Extract actual INI path "C:\Windows\inf\Windows Workflow Foundation 3.0.0.0\PerfCounters.ini" from "C:\Windows\inf\Windows Workflow Foundation 3.0.0.0000\PerfCounters_D.ini"."
[gle=0x80004005]
Error CSI 00000004@2014/3/18:16:47:48.324 (F) Logged @2014/3/18:16:47:48.324 : [ml:354{177},l:352{176}]"Extract actual INI path "C:\Windows\inf\Windows Workflow Foundation 3.0.0.0\PerfCounters.ini" from "C:\Windows\inf\Windows Workflow Foundation 3.0.0.0409\PerfCounters_D.ini"."
[gle=0x80004005]
Error CSI 00000005@2014/3/18:16:47:48.340 (F) CMIADAPTER: Inner Error Message from AI HRESULT = HRESULT_FROM_WIN32(1010)
[
[44]"The configuration registry key is invalid.
"
]
[gle=0x80004005]
Error CSI 00000006@2014/3/18:16:47:48.340 (F) CMIADAPTER: AI failed. HRESULT = HRESULT_FROM_WIN32(1010)
...

Checking the registry key mentioned in the error revealed that the key was related to performance counters. A little more research led me to the lodctr.exe tool, and running

lodctr.exe /R

performed a rebuild of the performance counters. After rebuilding the performance counters installing the .Net 3.5 framework feature with DISM succeeded.

PXE Boot Fails and WDS Fails to Start With Event 258 and Error 0xC1030104 After Removing Multicast Service Point Role form an SCCM / ConfigMgr 2007 Distribution Point

During an office-wide Windows 7 OSD migration this weekend we had some workstations downloading extremely slow over multicast. While that is a problem unto itself that may need to be solved at a later date we were down to 8 workstations so I decided to cut multicast off and let them fall back to SMB since SMB downloads on other workstations seemed to be working just fine. It seemed the best way to accomplish this was to simply remove the multicast role from the distribution point. This strategy appeared to work. The workstations did in fact fall back to SMB and the installations completed in a reasonable amount of time.

Of course if that were the end of the story I wouldn’t be writing this now. We tried to PXE boot one last workstation that had failed the night before and found that it couldn’t contact the PXE service point for a boot file. This behavior seemed odd as it was working fine only a few hours ago. Checking the pxecontrol.log showed the following:

adding address to server list [Site System IP]
adding address to server list 127.00.00.01
Sending availiability packet to: [Site System IP]
Sent 274 bytes to [Site System IP]:4011
Recieved Packet 04EC6B38 does not have associated request.
Error validating replies
Sending availiability packet to: 127.0.0.1
Sent 274 bytes to 127.000.000.001:4011
Error receiving replies

A quick inspection of the Windows Deployment Services Server service showed it to be stopped and attempting to manually start the service gave an error.  Checking the event log showed (among other things) Event 258 which looked like this:

An image from the event view showing event 258 with the text The description for Event ID 258 from source WDSIMGSRV cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer. If the event originated on another computer, the display information had to be saved with the event. The following information was included with the event: 0xC1030104

I’ll skip all the boring troubleshooting and cut right to the solution.  To correct the issue:

  • Remove the boot images from the PXE distribution point
  • Remove the PXE service point from the site server
  • Remove the WDS roles from the server
  • Restart (as requested by the role removal)
  • Reinstall the WDS roles on the server
  • Add the PXE service point back to the site server
  • Copy the boot images back to the PXE distribution point (note that this doesn’t take too long because the server will still have the compressed copy of the package so it just has to decompress it)

Setting the color and properties for all CMD and PowerShell windows based on admin / elevation status.

To quote Mark Twain, “The rumors of my death have been greatly exaggerated”. 

This blog is not dead. I realize it’s been quite some time since my last post. Two factors have contributed to the lengthy hiatus. First, I’m busy. Not just “I wish I had some time to catch up on some television, movies, and books.” busy, but “I wonder just how few hours of sleep the human body actually needs to survive.” busy. Second, my goal with this blog is not just to aggregate what’s already out there, but to add unique value to this little corner of the internet. If I don’t have something useful to say that hasn’t been covered elsewhere I see no need to add to the din.

Now, on to the “value”!

Several years ago Aaron Margosis posted a way to make all your CMD windows running as admin “visually different” than your non-admin windows. You can (and should) read that blog here. Fast forward a few years and I find myself using PowerShell more and more.  Furthermore, UAC makes it even more valuable to know which CMD and PowerShell windows are running with administrative credentials and which are not. Needless to say, as someone who has become accustomed to the functionality Aaron provided for CMD windows I wanted to port this same behavior to my PowerShell windows.  Here is how I did it…

Read more of this post

Unable to Pin an Item to the Start Menu

Admittedly this is not specifically SCCM or managed desktop related but I thought I’d share anyway.

As part of an OSD build I was trying to automate pinning a company-wide in-house application to the start menu, but my pinning script* wasn’t working. Right clicking on the EXE for the item revealed why. There was no option for “Pin to Start Menu” or “Pin to Taskbar” available on the item’s context menu. A little digging on the internet lead me to the following MSDN page: How to Exclude Items from Taskbar Pinning and Recent/Frequent Lists

The Remarks section at the end of that page revealed the answer to my problem. The application I was trying to Pin contained the word “help” in the filename, which is on a list of “restricted” items. The documentation states “This automatic exclusion can be overridden by applying an explicit AppUserModelID.”, and if you’d like more information on applying an explicit AppUserModelID feel free to read this page.  Now, setting up this AppUserModelID would have probably been the right way to solve my problem, but I didn’t have that kind of time to investigate what that entailed and work out this little issue.  All I wanted was to not have to worry about if the program I wanted to pin had the word “help” in the file name so I took the easy way out and just removed the “help” entry from the AddRemoveNames value under the HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\FileAssociation key and viola I was able to pin the program.

Images showing the AddRemoveNames value in the Software\Microsoft\Windows\CurrentVersion\Explorer\FileAssociation key that prevents an item from being pinned to the start menu

This certainly isn’t the recommended solution for a program you’re going to distribute to third parties since it would be considered bad form to go changing system wide settings on someone else’s computer without asking, but in this case it’s all in-house and the powers that be seem fine with my “quick fix” solution.  If you’re going to do this “in the real world” you should investigate the AppUserModelID route. 

On a side note, sure I could have re-named the EXE to something that didn’t contain the restricted word, but since the EXE or Shortcut, (ahem “Shell Link”) name gets used for the pinned item’s start menu text that would have meant coming up with some new creative name not using the word “help”.  Further, the new name would be different from what the users currently see on their XP start menu and we all know that means more support requests for the help desk which tends to make them grumpy.

 

                                                                

*Technically not my pinning script, but rather the pinning script I use compliments of the fabulous Hey Scripting Guy! blog.  Check it out at: “Can I Pin a File to the Start Menu by Using a Script?

Secondary Site stuck in a pending state with the error “Cannot find a public key for instruction \inboxes\despoolr.box\receive\somefile.ist coming from site XYZ, retry it later” in the despool.log

I certainly like the fact that I can setup a new secondary site right from the Configuration Manager console and that additionally I can choose to push the installation files to the new secondary site as part of that setup process.  Sometimes it even works.  However, more often than not I end up with a site stuck in a pending state.  Usually checking the despool.log on the primary site I see something similar to:

CPublicKeyLookup::CPublicKeyLookup("XYZ")
Cannot find a public key for instruction \inboxes\despoolr.box\receive\somefile.ist coming from site XYZ, retry it later

To correct this problem log on to the secondary site server, open a command prompt, and from the \Bin\i386\00000409\ folder run

preinst /keyforparent

This command will create a <XYZ>.CT4 file in the root of the drive. Copy the <XYZ>.CT4 file into the \inboxes\hman.box\ folder on the primary site. Wait a few minutes for the hierarchy manager to import the file (it will disappear from the folder) and the despooler to finish processing its backlog and everything should be back on track.

Likewise, you may also subsequently encounter a similar issue where the new secondary site doesn’t have a key for the primary site.  In that case the despool.log on the secondary site server should show similar errors to what we saw in the primary site’s despool.log. In this case log on to the primary site server and run

preinst /keyforchild

Copy the resulting CT5 file to \inboxes\hman.box\ on the child site and wait for the child site to import the CT5 file and complete processing just like you did for the primary site.

Error 0x80070490 Running Task Sequence From Run Advertised Programs

Here’s a quick tip.  If you’re getting the errors below in your smsts.log when running a task sequence from Run Advertised Programs it may be because you’ve advertised the task sequence to a user rather than a computer.  Remove the user from the targeted collection, add the computer, and refresh policy and everything should work.

No execution request with PRG_DependentPolicy=FALSE found for advertisement <Advertisement ID>
Error getting running advert info. Code 0x80070490
Error getting package location and access account information. Code 0x80070490
Error initializing TS environment. Code 0x80070490
Task sequence launcher advertisement failed!. Code 0x80070490

Adding a Password to a Single PXE Boot Task Sequence

If you PXE boot for OSD and you need to add a password to your task sequences you can browse to your PXE service point properties, check the box labeled “Require a password for computers to boot using PXE” and enter a password. Any computers booting from that PXE service point will prompt for the password prior to presenting the user with the list of advertised Task Sequences.

PXE Service Point properties page with Require a password for computers to boot using PXE checkbox called out.
Simple enough, but what if you want to add a password to a single task sequence?  One possible solution is to create a script to do the password checking, which I’ve already done for you and you can find at the end of this post, then created a Run Command Line step as the first step in your task sequence that utilizes the script.  The script takes a single argument, the password, and when run prompts the user with a simple input box to enter the password.  If the input password matches the password from the command line the script exits with a success return code and the task sequence continues as normal.  If the user cancels the input or enters a blank password the script exits with a failure return code and the task sequence fails.

Task Sequence showing a Run Command Line step as the first step of the Task Sequence to perform password checking on a single PXE Booted task sequence.
To be fair this script is pretty basic.  It certainly could be expanded upon by masking the password or validating the user against Active Directory.  It also isn’t terribly secure since someone could easily examine the logs and discover the password, but the script suited my needs and it should be good enough for situations where you just want to keep the average user from shooting themself in the foot.

As always, the standard disclaimer applies.  This works for me, it may not work for you.  Use it at your own risk.

TSPass.vbs

“Failed to resolve selected task sequence dependencies. Code(0x80040104)” or “Failed to find CCM_SoftwareDistribution object …” for an OSD Driver Package that is on a Distribution Point

A few months ago while working with a consultant to get OSD up and running in my environment the consultant had mentioned a curious bug he had seen whereby if a driver package version was 1 it would appear to be unavailable to a task sequence.  At the time my test driver packages had been updated a few times so I didn’t think much of it but made a note of it “just in case”.  Fast forward to present day, and after creating some new driver packages my previously functional task sequence all of a sudden started failing.  Checking the SMSTS.log I noted the following:

Getting policy for CCM_SoftwareDistribution[AdvertID="P01201B1", PackageID="P0100187", ProgramID="*"]
FALSE, HRESULT=80040104 (e:\nts_sms_fre\sms\framework\tscore\tspolicy.cpp,2301)
Failed to find CCM_SoftwareDistribution object for AdvertID="P01201B1", PackageID="P0100187", ProgramID="*" (*iTSReference)->Resolve( pTSPolicyManager, dwResolveFlags ), HRESULT=80040104 (e:\nts_sms_fre\sms\framework\tscore\tspolicy.cpp,2862)
m_pSelectedTaskSequence->Resolve( m_pPolicyManager, TS::Policy::TaskSequence::ResolvePolicy | TS::Policy::TaskSequence::ResolveSource, fpCallbackProc, pv, hCancelEvent), HRESULT=80040104 (e:\nts_sms_fre\sms\client\tasksequence\tsmbootstrap\tsmediawizardcontrol.cpp,1208)
Failed to resolve selected task sequence dependencies. Code(0x80040104) 
hrReturn, HRESULT=80040104 (e:\nts_sms_fre\sms\client\tasksequence\tsmbootstrap\tsmediaresolveprogresspage.cpp,408)

A quick investigation revealed that P0100187 was one of my new driver packages.  I had put this package together as I was headed for the door on friday night, had I forgotten to send it to the distribution points?  A quick check of the package status in the Configuration Manager console showed that the package had in fact been distributed.  A little time with Google and the SCCM database led me to the fact that although the package had been created and copied to the distribution points the hash values had not been populated in the database.  The scenario that led to this situation was as follows:

  1. Right click the Drivers node in the SCCM console and choose import
  2. On the Add Drivers To Package step create a new package and uncheck the box to update distribution points
  3. Complete the import of the drivers
  4. Right click the new driver package and choose Manage Distribution Points
  5. In the Manage Distribution Points wizard select Copy the package to new distribution points, and complete the wizard

The package will proceed to replicate to the distribution points normally, however upon completion even though the package appears to be installed correctly in the package status in the console if you examine the SMSPackages table in the database you will see that the Hash and NewHash fields are empty for the new package.  Because the hash fields are empty the MP appears to not return any distribution points for that package when the Task Sequence requests them.  The solution is fairly simple:

  1. Right click the driver package and choose Manage Distribution Points
  2. Choose update all distribution points with a new package source version

The package hash will be calculated and the package will be re-distributed to the distribution points (although since the files are already on the distribution points the actual data transfer is fairly minimal), at which point the Task Sequence will no longer fail searching for the driver package source.  Although it’s nothing more than a guess, I’m betting this is the exact behaviour the consultant was seeing.  Given that the fix causes the package source value to be incremented from 1 to 2 it could appear as if the issue was in fact caused by the package having a source value of 1.

To GUI or not to GUI…

That really is the question in my environment.  First, a little background, I serve an environment with a bunch of knowledge workers.  Unfortunately these knowledge workers cover different areas in their field and more unfortunately because of this diversity it’s hard to break most of them down into nice tidy groups for software distribution.  Some may work in areas A, B and C, while others work in areas C, D, and E, and still others work in A, D, and F. That is to say while we have about 5 apps that run 80% of the business functions, another 50 or so fill niche roles depending on what type of work a user is doing, and those don’t always overlap cleanly.

To make matters worse these folks like to move around so we also have a very “self service” culture.  For areas where licensing permits we allow users to determine what software load they really need and self install from Run Advertised Programs.  However, many of the calculations done with the niche software change on a periodic basis and so that software must be regularly updated for those who have self installed.

This arrangement presents some unique challenges, not the least of which is that when a user self installs from RAP we want them to see the installation progressing and at the end be notified of the installation’s success or failure.  However, when updating, where possible we don’t want to bother the user and just want the update to install silently.  Normally this would dictate doubling up programs for each piece of software to be deployed, one for the self service install with UI and one for the silent updates, but not being a fan of doing everything twice I’ve come up with what I think is a rather novel solution.

It all starts with a way to determine if the installation in question has been started via Run Advertised Programs or via a mandatory assignment.  The former we assume to be a user directed self service installation for which we should show a GUI, and the latter an update which should run silently.  So the question becomes how to make that determination.

Enter C++.  Ok, quit groaning, I realize that the SCCM crowd is more relegated to the likes of VBScript, PowerShell, and .NET, but in this case I had my reasons.  You can’t go mucking around with window handles and the like in VBScript and I use this tool in builds where .NET may not be installed, which excludes .NET or PowerShell.  So for the tool to work for me it needed to have no dependencies (I’ve even statically linked the C Runtime in this case).  Fortunately if C++ is not your native tongue, I’ve provide all the bits for you and you can just skip ahead to how to use the tool.  For those that are interested I’ve included the source so feel free to have a look and/or modify at will, but if you make modifications please respect the GPL and post your source (a link back would be appreciated too but certainly isn’t required).

So how does the ShowGUI.exe tool make the determination that it’s running from Run Advertised Programs?  Through some careful examination with one of my favorite Sysinternals tools, Process Explorer, I’ve found that Run Advertised Programs and its related processes always load the module “ccmcore.dll”.  So basically the process goes something like:

  • Get a window handle to the foreground window
  • Find the process ID that belongs to that window handle
  • Enumerate the loaded modules to see if one of them is ccmcore.dll

Now, some of you may be asking “If you’ve got the handle for the foreground window why not just make a call to GetWindowText and see if the title is ‘Run Advertised Programs’?”. and this is in fact what the first iteration of ShowGUI did.  I happen to be in an organization that is English only, and before starting this blog I used ShowGUI operating that way for quite some time without issue.  However as I got ready to release this little utility out into the wild it dawned on me that what this first iteration failed to account for was localization.  If you’ve installed any of the Client operating system localization ICPs Run Advertised Programs may not be titled as such. So I thought I would do you my dear reader a favor and retool things to work regardless of the window title.

So that’s all great theory, but how do we put things into practice?  Well first another bit of background is in order.  The people I work for generally shun all out repackaging.  Sure an MST here and there are fine, but a full blown repackage is usually out of the question.  Why?  Well over the years we’ve been burned by people who didn’t do it well, sure, but more explicitly when you tell a vendor’s tech support that you repackaged their app for installation generally all bets are off.  Also, given that most of the people who I work with are by no means coders but most can hack out a little VBScript here and there, most of our installations are wrapped up in a nice bit of script.  Further, not being a fan of doing things twice you’ll find that I’ve developed a pretty extensive VBScript snippet library (much will land on this blog throughout future posts so stay tuned) which really reduces most of the scripting to “coding by Lego” as I like to call it.  In other words you’ve got all the building blocks, go snap them together to make something cool.

To that end you will also find attached to this blog the “standard script template” that makes using ShowGUI.exe easier.  I won’t cover it all here, but we’ll look at a few of the bits relevant to this discussion.  First we have a header that among other things includes a silent flag and defaults it to false.

Dim bSilent: bSilent = False  ' Silent Flag

Enough for the warm up, moving on we have a call to a function ScriptInit.  This is where the meat of the automatic GUI determination happens.  ScriptInit looks like this:

Private Sub ScriptInit()
      ' Auto check for silent mode if helper exe exists
      Dim objFSOSilent: Set objFSOSilent = CreateObject("Scripting.FileSystemObject")
      Dim ScriptPathSilent: ScriptPathSilent = objFSOSilent.GetParentFolderName(WScript.ScriptFullName)
      If Right(ScriptPathSilent, 1) <> "\" Then ScriptPathSilent = ScriptPathSilent & "\"
      If objFSOSilent.FileExists(ScriptPathSilent & "ShowGUI.exe") Then
            Dim objShellExecuteSilent: Set objShellExecuteSilent = CreateObject("Wscript.Shell")
            Dim iFailSafeSilent
            For iFailSafeSilent = 1 To 5
                  Dim testResultSilent: testResultSilent = objShellExecuteSilent.Run("""" & ScriptPathSilent & "ShowGUI.exe" & """", 0, True)
                  If testResultSilent <> 1 Then
                        bSilent = Not cBool(testResultSilent)
                        Exit For
                  End If
                  WScript.Sleep(500)
            Next
            If testResultSilent = 1 Then bSilent = True ' Fail silent. 1 means that GetForegroundWindow in ShowGUI.exe returned Null
                                                        ' Usually this is because a window was deactivating or the desktop on which
                                                        ' the app is running is not the active desktop (i.e. computer is locked etc.)
            Set objShellExecuteSilent = Nothing
      End If
      Set objFSOSilent = Nothing
      ' Force if flag is Set
      Dim strArg
      For Each strArg In WScript.Arguments
          strArg = UCASE(strArg)
          Select Case strArg
            Case "/S", "-S", "--SILENT", "/QN"
                  bSilent = True
            Case "/QB", "/QB!"
                  bSilent = False
              Case "/TS"
                  bSilent = True
                  bTaskSequence = True
            End Select   
      Next
End Sub

First ScriptInit checks to see if the ShowGUI helper EXE exists in the script path.  If not we’re not doing any auto GUI mode determination and the script will proceed to check for any explicit flags, which we’ll cover that later.  If the ShowGUI helper exists in the script path then ScriptInit will go into a loop and execute it up to 5 times at half second intervals.  Why execute the helper EXE up to 5 times?  Well if you read the documentation for the GetForgroundWindow API you’ll notice that it is possible for there to be no foreground window.  If anything failed while executing, ShowGUI returns 1 and usually delaying a few milliseconds and trying again will get a valid result.  I picked half a second and 5 tries because they’re nice round numbers, and at most it will delay the program start by 2.5 seconds which is tolerable.  One instance where the script will not get a valid result even after waiting is when there is no user logged on or the console is locked.  In this scenario ScriptInit defaults to silent mode under the assumption that if there is no foreground window after 5 attempts then there is probably no user logged in or the console is locked and it’s a safe bet the user didn’t initiate the program from RAP.

Once any automated GUI mode detection has been made ScriptInit enumerates all of the command line parameters passed to the script and if any of them are in a list of well known silent or basic GUI flags (i.e. /s, /qn, /qb, etc.) it will override the automatic determination.  The assumption is that if you explicitly specify a GUI mode on the command line you probably know what you are doing and that should take precedence over anything the script decided on its own.

So, the bSilent flag  is set appropriately, what now?  Now the real work happens and this is generally left up to your imagination, but here’s a quick example.  Let’s say we’re installing a simple MSI.  No changes needed, nothing fancy, just “MSIEXEC.EXE /I MyInstaller.msi /QB” will give you your basic hands off install.  Well, to get that wrapped in the standard script template would be:

Dim objShellExecute: Set objShellExecute = CreateObject("Wscript.Shell")
iRetVal = objShellExecute.Run("MSIEXEC.EXE /I MyInstaller.msi /QB", 1, True)

However instead of relegating our installation to always use the /QB switch and thus always show a basic UI, what if we did something like this:

Dim objShellExecute: Set objShellExecute = CreateObject("Wscript.Shell")
iRetVal = objShellExecute.Run("MSIEXEC.EXE /I MyInstaller.msi " & IIF(bSilent, "/QN", "/QB"), 1, True)

Now if bSilent is true the command will be run with the /QN switch and be silent, otherwise it will be run with the /QB switch and show our basic UI.  Viola!  One package, program, and script that executes silently when run from a mandatory assignment and with a basic GUI when run by the user from RAP.

To be fair this system isn’t perfect.  In a download and install situation if the user checks the box to automatically run the program when the download completes and then closes RAP before the program runs, well, it’s going to run silent.  Also, if your environment changes the foreground window all bets are off.  In other words you can’t call ShowGUI.exe from a batch file or PowerShell script because they both create a new console window which steals the focus (but if you’re creative I’m sure you can figure out how to run ShowGUI.exe from a VBScript helper and then launch your batch file or PowerShell script from there).  If you find a better way I’m all ears (I’ll even do the coding for you), but I posted this question in the MyITForum.com forums several months ago and got no replies, so this is what I’ve come up with.

Keep in mind, the “standard disclaimer” applies.  This works for me, it probably will not work for you.  In fact, you probably shouldn’t use it at all as it may do things in your environment that can’t be foreseen, and let’s face it I very well may not have any idea what I’m talking about.  But, if you’re brave and decide you really really want to give it a try despite my warnings, then you should probably do some extensive testing in a non-production environment first.  I take no responsibility if this code and/or information causes your garden to wither and die, your hair to fall out, and your car keys to be forever missing.  In fact I take no responsibility for anything this code may or may not do.  Use it at your own risk.

ShowGUI.zip

DefaultTemplate.vbs

Dell Ships Version 2.0 of the Windows 7 Notebook Combo Driver CAB

If you’re a Dell shop using OSD you’re probably a fan of their one size fits all “Combo Driver CABs”. Dell just released version 2.0 for notebooks which adds support for the new 3rd generation E series (i.e. the Exx20 models). Be aware however, from the notes on the site, it looks like there may be issues with the Nvidia driver with the E6420 / E6520 at the moment.