InstallShield Could Not Find File – Error Code -6103

My current client uses the standalone InstallShield repackager to snapshot applications on virtual machines.  When we copy the captured project back to the host machine and try to build the project, we often get errors such as “Could not find file xxx” (Error code -6103)

This issue is present because in the ISPathVariable table, the SOURCEFILEPATH entry will contain a hard coded path – usually C:\Packages.  What we need to do is change this to a relative path so that we can build our package successfully from any location.  So, considering a project folder structure similar to the below:

 

 

 

 

 

We can replace the SOURCEFILEPATH value with <ISProjectFolder>..\ like so:

 

 

<ISProjectFolder> is merely a reference to the project folder location (the folder that contains your .ISM file).  By adding a couple of periods and a backslash to the end, we are telling InstallShield to look up one level from our project folder (i.e, look in the Software folder), and that will contain the source files for our package!

Clean Up the Windows Start Menu

Sometimes after an install or an uninstall we want to clean up the start menu – usually this involves removing shortcuts to uninstall the application, shortcuts that link to help files and/or shortcuts that attempt to install additional components.  This tidy script (tested on Windows 7) can be used to populate file(s) and folder(s) names that require deleting.

 

A Guide to Signing Un-signed Drivers (Part 3)

This post continues from part 1 of the driver signing series found here and part 2 of the series found here.

Part 3 of our driver signing guide deviates slightly from the self-signed certificate approach. My current client uses Active Directory Certificate Services (ADCS) to create and issue certificates. I won’t discuss ADCS in any detail because I’m not a security expert. However, there’s a useful guide here that will assist you in creating a code signing certificate for use with all your unsigned device drivers.

I exported our code signing certificate from ADCS as a pfx file, which importantly, forms part of a certificate chain with the root certificate (our code signing certificate is signed by the root certificate). The root certificate for the organisation is already in the Trusted Root store (for the computer….not the user) on all machines. If this root certificate didn’t exist, our new crtificate chain will not validate and hence our ‘signed’ driver would not appear as being signed when we install it.

The exported code signing certificate uses SHA-256 encryption.  Exporting certificates as SHA-256 is currently a security best practise. As a result of this, when we’re signing a driver’s .cat file the syntax is slightly different (ensure you download the latest version of signtool.exe before running this command line):

Now all you need to do is ensure that your code signing certificate is imported into the Trusted Publisher store  (for the computer….not the user) on every machine in your organisation.  But wait….

Even though we did this, when we installed the driver it appeared signed (yay) but we received a message saying the publisher wasn’t trusted (boo)!  After much debugging, it turned out that this patch (KB2921916) released from Microsoft was required on all machines and fixed the issue!

Before I wrap up, I should also mention a very nice article I found here explaining the driver signing process in more detail.

A Guide to Signing Un-signed Drivers (Part 2)

This post continues from part 1 of the driver signing series which can be found here.  Part 3 of the series can be found here.

It’s been a while since I looked at signing un-signed drivers I must admit. In fact, I’ve probably not signed one since my original post on AppDeploy (now ITNinja) back in 2010!  I’ve been caught up in ‘other worlds’ since then, but I’m finally back to write a second part to this original post (which incidentally I’ve modified and re-written here and you may need to reference this throughout this post).

Anyway, this second part is a small piece on how driving signing works (high level) and an issue that I’ve stumbled upon and resolved recently.

WHY SIGN A DRIVER?

It’s a way of ensuring that a driver package has not been tampered with since it was tested and approved.  In our self-signing example, you are testing and approving it!  It also means that non-administrative users will not get any security prompts when installing drivers for Plug and Play devices (depending upon your driver signing policy).

WHAT IS A CATALOG USED FOR?

A catalog file contains digital signatures that reference each file in your driver’s INF file (referenced by the CopyFiles directive…..read on), allowing the operating system to verify the integrity of every file.  If any files referenced by the driver INF file are changed after digitally signing the catalog file (including the INF itself!), the signature will be broken.

HOW IS THE CATALOG USED WHEN WE INSTALL A DRIVER?

The inf file looks for the catalog file that it is referencing and verifies the digital signature.  It also verifies the cryptographic checksum of every file that is recorded in the signed catalog file.  If any of this does not comply, the driver install will fail.

DEBUGGING A DRIVER INSTALL (WITH AN EXAMPLE)

I’m working on an un-signed Smart Card printer by IDP called Smart 50s.  Here is the original INF file content:

Since we’ve already generated a corporate certificate using my guide, all we really need to do here is sign the catalog file.  Occasionally we need to delete the vendor’s cat file and generate our own cat file.  I sometimes do this for peace of mind, to ensure that the cat file is up to date and contains all the correct file checksums referenced by the INF file.

So next I imported my certificate into the Trusted Root store (i need to do this before I can verify the digital signature), and verified the digital signature of my catalog file using SignTool.exe.  Everything reported a success.

Next (and as a quick test) I lumped a copy of DPInst.exe into the driver folder on my dev machine, and ran it interactively by double clicking it.  And then I gasped:

Unsigned driverHow can this be?  Signtool.exe verified the digital signature successfully?  So I delved into the driver log file which is located here:

C:\Windows\inf\setupapi.dev.log

And when I scrolled down to the bottom (incidentally deleting this file will regenerate a new one, which may be handy when debugging) I found this line:

This was interesting.  Take note of the exclamation marks at the very start – a single exclamation is a warning, and a triple exclamation mark is an error/failure   So I did a little Googling and stumbled upon this.  Specifically, it says:

PnP device installation considers the digital signature of a driver package to be invalid if any file in the driver package is altered after the driver package was signed. Such files include the INF file, the catalog file, and all files that are copied by INF CopyFiles directives.

I knew the INF and Catalog files hadn’t been modified since signing them, so it led me to the bit in bold.   Was UNIDRVUI.DLL being copied to the driver store by a CopyFiles directive?  It turns out it wasn’t!!  So this meant fixing a vendor’s INF file which I can assure you, isn’t much fun!  What’s important to note here is that even though Signtool.exe verified the digital signature of my catalog file, that does not mean to say that the catalog file contains all the required file checksums!

Here are the changes I made – unfortunately I won’t go in to how we modify INF files since it’s not a trivial task to explain.  Anyway:
1. Added a CopyFiles directive, pointing to a section called UNIFILES.INF difference 12. Created the UNIFILES section, and added all the files that we missing (it wasn’t just UNIDRVUI.DLL)INF difference 2

3. Added the files to the SourceDisksFiles.x86 section, so that they could be located on disk (they were in a sub folder called i386)
INF difference 3

I then deleted the cat file so I could re-generate it with all the new file checksums.  And I re-signed it with my certificate.  I then ran DPInst.exe and successfully got the following prompt!

Signed successfullyAt this point I thought it was good to go.  As you all probably know, Windows 7 and above come with some handy VBScript printing utilities located here:

C:\Windows\System32\Printing_Admin_Scripts\en-US

The scripts basically use WMI classes under the hood to add/configure printers and ports etc.  I wanted to run  quick test using the WMI approach instead of the PrintUI.dll approach since we can return exit codes, and I think there are issues returning exit codes via Rundll32 and PrintUI.dll (it tends to just print the error out to a dialog window as opposed to returning an exit code).

When we tried to install our driver, it returned an 2148467266 exit code.  So I checked inside setupapi.dev.log and found the following:

Assuming an untrusted signer?  That’s strange.  So I MOVED the certificate to the Trusted Publishers store.  And then I got this:

Fair enough.  I kind of expected that.  So i decided to put my certificate in BOTH the Trusted Publisher AND the Trusted Root stores.  And voila.  No error messages and a return code of 0!

I’ll probably end up using C:\Windows\System32\PnPutil.exe to install my driver above.  It has a handy command line switch (/i) that installs the driver on matching devices that are connected to the system (the WMI approach doesn’t seem to do this – although perhaps a little more research is needed surrounding this!).  In other words, when a user plugs in this device (without the drivers installed – they need to plug it in first to mount the Virtual Printer port) it will create an entry under Devices and Printers in the ‘Unspecified’ section.  Installing the driver and adding a printer via WMI works, but also leaves the ‘Unspecified’ device until the user logs off and logs back in (even after a print spooler stop and start).  PnPutil.exe seems to install the driver and then match it up to this unspecified device and moves it to the Printers and Faxes section.  That’s all….for now.

Create a Symbolic Link from a Custom Action

Creating a symbolic link can be achieved using the MKLINK internal command.  Internal commands are native to the windows command shell and are NOT executable files.  As such, we must call these commands via the windows command shell as follows:

Let’s pretend we have a physical folder in C:\Program Files\AlkaneSolutions but we want to create a symbolic link to it in the root of C:\ called ‘AlkaneSolutions’.  I would use the following MKLINK command:

From a custom action we should do 2 things:

1.  We cannot call MKLINK directly since it’s an internal command and not an executable.  So instead we call CMD.exe with the /c parameter (/c runs the command and then terminates the command prompt) and then pass the MKLINK command afterwards.

2.  We should not include any hardcoded paths, and instead try to use windows installer properties where possible.  Remembering to enclose any paths in quotes!

As such, and when scheduling the Custom Action to run in a deferred context just before InstallFinalize, our Custom Action should look similar to this:

MKLINK commandThe action ‘MKLINK’ is merely the name of our Custom Action.  The Type relates to the type of custom action and its execution options.  The Source of [SystemFolder] relates to the location of CMD.exe.  And the Target is the command we want to run.

 

Create a URL Shortcut using the IniFile table

With a Windows Installer there are a couple of ways we can create a URL shortcut, but I like to create a URL shortcut using the IniFile table.  In this example, we create a file called ‘Alkane App.url’ on the desktop.  It will look similar to this:

Alkane App Shortcut

 

 

 

If you opened the file in Notepad you would see it looks similar to this (depending upon the public properties we pass at install time):

And this is what the IniFile table looks like that creates it:

URL Shortcut IniFile table

A few pointers;  In the FileName column we should specify a short name|long name format (remember we’re adding all these entries to the same file name so they’re all identical).  The DirProperty does NOT require the square brackets (Example, [DesktopFolder] would be incorrect).  The [IPADDRESS] and [PORT] are public properties, which we specify on the install command line.  For example:

MSIEXEC /I AlkaneApp.msi IPADDRESS=”127.0.0.1″ PORT=”80″ /QB!

And the icon for this shortcut points to the Internet Explorer executable, and uses the embedded icon with an index of 0.

Also you should ensure that the Component_ points to a component which will definitely be installed (and removed).

Access a Windows Installer property in a Deferred Custom Action

Description:

This post describes how to access a Windows Installer property in a Deferred Custom Action.  Deferred, commit, and rollback custom actions can only access a limited number of built-in Windows Installer properties – CustomActionData, ProductCode, and UserSID.  In brief (since this has been discussed plenty of times before elsewhere) this is due to them being executed in a separate process (they spawn another MSIEXEC.exe process which is run in a System Account context – check Task Manager during an installation to see this).  To pass any Windows Installer property to a deferred Custom Action, we must pass it via the CustomActionData property.  In this example, we’ll pass the ProductName property during the installation of our product.

Step 1
Create a property. Call it ‘AlkaneCustomProperty’ and give it a default value of anything (we’re going to set this to our directory name in Step 2….).

Step 2
Create a SetProperty custom action (Type 51), call it ‘setAlkaneCustomProperty’, select your ‘AlkaneCustomProperty’ property, and under property value write ‘[ProductName]’. Execute this action as Immediate, before InstallInitialize with a condition of ‘NOT Installed’.

Step 3
Create another CA – this time a ‘Call VBScript from Embedded code’ (Type 38). It is IMPORTANT you call this the same name as your property you made earlier, so call it ‘AlkaneCustomProperty’. In your script, to retrieve the directory name use:

Schedule this CA as ‘Deferred in a System Context’ and put it anywhere between the standard actions ‘InstallInitialize’ and ‘InstallFinalize’.  Use a condition of ‘NOT Installed’.

Use VBScript to amend the the Hosts/Services or any other text file

Description:

This post shows how to use VBScript to amend the the Hosts/Services or any other text file.  It contains two scripts to add/remove lines of text.  This example adds to the C:\Windows\System32\drivers\etc\Services file.

Source:

N/A

Script:

Add to Services file

Remove from Services file

 

Compressing Files into an External .CAB using WiMakCab.vbs

This post describes the process of compressing files into an external .CAB using WiMakCab.vbs.  WiMakCab.vbs is part of the Windows SDK, and can be used to compress external files into a .CAB file.  We recently used this approach to compress external files for Silverlight as follows:

Step 1 – Download and extract Silverlight

The Silverlight download comes in the form of a self extracting executable.  We used 7Zip to extract the contents of the executable to a location called C:\SilverlightDownload, which gave us silverlight.msi and silverlight.7z.  We then extracted silverlight.7z to the same folder, which gave us a patch (.MSP) called Silverlight.msp.

Step 2 – Perform an administrative installation

We used the MSI to perform an administrative installation as follows:

 

Step 3 – Patch the administrative installation

We then patched the administrative install with silverlight.msp:

 

Step 4 – Compress files into an external .CAB

Copy WiMakCab.vbs and makecab.exe into the administrative installation folder (C:\SilverlightAdmin in our case).  We found that if we didn’t run it from the same location that the .CAB file was not created.  Run the following command (where Data1 is the name of your required.CAB file):

You should now see a file created called Data1.cab.  Delete everything except for Silverlight.MSI and Data1.CAB.  Done.

For more information on parameters (changing compression type, streaming the .CAB internally), please see here: http://msdn.microsoft.com/en-us/library/aa368616(v=vs.85).aspx

Note: On occasions I’ve had to remove the compressed bit from the file attributes to ensure the source files can be located.  This involves subtracting 8192 from the file attribute for each file that has it set.

Create a Nested Folder Structure using VBScript

Description:

The Filesystem Object cannot create a nested folder structure in a single invocation of the CreateFolder method.  For example, if we tried executing the following code it would return a ‘Path Not Found’ error unless c:\alkanesolutions\ already exists:

objFSO.CreateFolder “c:\alkanesolutions\test\”

The function below resolves this limitation.

Source:

Technet Forums

Script: