Modifying PaperCut NG Client to install in the system context via Microsoft Intune


This post builds on my previous post about PaperCut NG Client. You may want to go read that post first to get some context.

PaperCut NG Client’s Windows Installer (MSI) file has had a bug for months and months, over several version releases, where it is not recognized by Intune as a system-installable app. From the product manual:

There is a known issue with the .msi file not allowing an Administrator to specify in Microsoft Intune which context an Administrator can install the application to.

This would be easy for the company to fix, but for whatever reason, it has not done so. To fix it yourself for your organization, continue reading!

The Cause

The Windows Installer file does not set the ALLUSERS property. For most MSI files, the ALLUSERS property should be set to 1 to specify a system-level installation. If the value is an empty string, then Windows Installer treats it as a per-user installation. Because this property is not even defined in the PaperCut NG installer, it is treated as if it were set to an empty string. The installer itself is coded in such a way that the files are written to per-computer locations anyway, so the installation works fine when run manually.

When you run the Microsoft Win32 Content Prep Tool to generate an INTUNEWIN file for upload into Intune, though, that tool notes the lack of the ALLUSERS property (just like Windows Installer itself would) and generates metadata in the INTUNEWIN file limiting the installer to per-user installations. That’s what causes the problem with Intune, and that is what you are manually changing when you follow the published workaround (described in a video on the same web page right below the notice of the bug).

The Solution

Normally, you can pass any property to a Windows Installer file on the command line at the time of installation. Unfortunately, the Win32 Content Prep Tool is not capable of accepting properties as parameters; it only reads what is built into the file. We can’t even make a transform file like last time because, again, a transform file is specified on the command line at the time of installation as a property parameter. To fix this issue, we must directly edit the MSI file.

The following steps assume that you have the environment described in my previous post set up. You don’t have to follow these steps exactly; for example, I am removing the original MSI file from the source and replacing it with a differently-named file, but you could leave both there if you wanted to.

  1. Move the MSI file to a new folder and make a working copy:
    md "%USERPROFILE%\Downloads\PCClient\Original MSI"

    move "%USERPROFILE%\Downloads\PCClient\win\pc-client-admin-deploy.msi" "%USERPROFILE%\Downloads\PCClient\Original MSI\"

    copy "%USERPROFILE%\Downloads\PCClient\Original MSI\pc-client-admin-deploy.msi" "%USERPROFILE%\Downloads\PCClient\Original MSI\pc-client-admin-temp.msi"
  2. If you made the transform file described in my previous post, I suggest that you move it as well:
    move "%USERPROFILE%\Downloads\PCClient\win\PCClientAutorun.mst" "%USERPROFILE%\Downloads\PCClient\Original MSI\"
  3. Run Orca.exe
  4. Open “%USERPROFILE%\Downloads\PCClient\Original MSI\pc-client-admin-temp.msi”.
  5. Since we’re editing the MSI file, we are defining a new package, so we must specify a new package code. Navigate to View menu > Summary Information…, and click New GUID to replace the package code. Then click OK.
  6. Select the Property table.
  7. Tables menu > Add Row…, and create a new row with these values:
    • Property: ALLUSERS
    • Value: 1

Optional: Merge the MST Settings

Now here is the optional part. Since we are creating a new MSI file anyway, there is no reason to keep depending on a transform file for other behavior. If you want the program to run automatically at user sign-in, and if you created the transform file as described in my previous post, you can apply the transform file the MSI file. Then you won’t need the transform file at installation time because its settings will be baked into the MSI itself.

  1. Transform menu > Apply Transform…, and choose the PCClientAutorun.mst file. You should see green bars beside the Component, FeatureComponents, Property, and Registry tables, indicating that changes are present.
  2. File menu > Save Transformed As…, and save the file with a new name, such as “pc-client-admin-myorg.msi” (replacing “myorg” with an abbreviation for your organization). Be sure not to overwrite the original file from the vendor, as that is your unchanged reference version.

Finishing Up

  1. If you skipped the optional steps above: File menu > Save, then close Orca, and rename the file to something without the word “temp” in it, such as “pc-client-admin-myorg.msi” (replacing “myorg” with an abbreviation for your organization).
  2. If your organization has a code-signing certificate, I recommend signing the new MSI file.
  3. Copy the new MSI into the folder with the rest of the installation files:
    copy "%USERPROFILE%\Downloads\PCClient\Original MSI\pc-client-admin-myorg.msi" "%USERPROFILE%\Downloads\PCClient\win\"

That’s it! You fixed the Intune issue by adding ALLUSERS=1, and you optionally integrated the transform file settings from the previous post directly into the new MSI. You should be able to upload the new MSI into Intune following the normal procedure.

Posts in this series:

  1. Transforming PaperCut NG Client installer to run the program automatically
  2. Modifying PaperCut NG Client to install in the system context via Microsoft Intune

Transforming PaperCut NG Client installer to run the program automatically


This is a quick demonstration of modifying application behavior at installation time when the app uses Windows Installer. It is not a deep dive but will include some links along the way for further study.

Well-behaved programs don’t force undesirable behavior on users. That’s why I’m normally opposed to programs setting themselves to run automatically without the user’s permission. I didn’t mention this in my earlier post, Providing a Great Software Deployment Experience, but let me add to my list of Guidelines for Great User Experience in that post that installers should let the user decide whether the program should automatically run at computer startup or user sign-in. This should be implemented as a Windows Installer property overridable on the command line so that IT staff can make that choice during unattended installation.

Here, I am focusing on an app whose installer does not configure it to run automatically. That’s good at first glance. An important characteristic of this app, though, is that if you have installed it, you probably want it running all the time. The app is the PaperCut NG Client, and it is the user-facing component of the PaperCut NG printing management system. Organizations implement this to providing accounting around printer costs, among other functions. The client notifies users of printing quota and prompts for approval of printouts, so that users are aware of how much they or their departments will be charged for each printout. If a user tries to print to a printer controlled by PaperCut NG, but they don’t have this app running, they will not be prompted for approval, and so the print job will never be sent to the printer. (Behavior may vary depending on configuration; I’m describing how it works with my organization’ configuration.) This will make users sad and very liable to call for support.

Therefore, IT staff want this app running all the time on any computer where it is installed. The problem is that this app’s installer does not provide a way to make it automatically run. At my organization, we work around this by using Group Policy to run the program as user sign-in:

  • Group Policy setting: User Configuration > Policies > Administrative Templates > System > Logon > Run these programs at user logon
  • Item: C:\Program Files\PaperCut NG Client\pc-client.exe –silent

This has the unfortunate effect of separating the “automatically run” behavior mandate by IT from the collection of computers where the software is installed. IT must ensure that, over time, both the policy and the app are always applied to the same set of computers. It would be better to have the behavior built into the installer, and that is the subject of the rest of this post.


I am not going to try to teach the Windows Installer system and file format here; whole books have been written about it, and it is documented extensively on Microsoft Learn. The minimum you need to understand here is that Windows Installer installs a set of features, and features are composed of components. Typically, every individual file or registry value needed by the app is defined as a separate component in the Windows Installer file, which always has an “msi” (Microsoft installer) extension.

The approach here will be to transform the vendor-supplied Windows Installer file so that it adds the command line above to one of the standard “Run” keys in the registry at installation time. I will do this by applying a transform file (*.mst) to it the installer file supplied by the vendor. This is a way to alter the behavior of the installer file without editing it directly. That makes the altered settings shareable and leaves the integrity of the vendor’s digitally signed installer file intact.

If you are building your own MSI from scratch (such as if you work at PaperCut), you should consider keeping the default of not running things automatically without the user’s consent, and you should provide a property settable at the command line or through the installer’s user interface so the user can override your default setting. Since I am not the vendor in this case, I am just going to make the change; if I don’t want the change, I won’t apply the transform file. A property would not provide additional value for me, since I have to make the effort of building a transform file already.

Gather Software and Tools

  1. Copy the client software from your organization’s PaperCut NG server. For example, if your PaperCut NG server is “papercutsvr”, and you want to work in your Downloads folder:
    Robocopy "\\papercutsvr\PCClient\win" "%USERPROFILE%\Downloads\PCClient\win" /E /J /DCOPY:DAT /XJ
  2. Install Orca, the Windows Installer database editor, using Windows Package Manager, from an elevated Command Prompt:
    winget install Orca

Create the Windows Installer Transform File

Follow these steps to build a windows Installer transform file that configures PaperCut NG Client to run automatically for all users.

NOTE: I plan to build on what I am doing here in a future post to address another issue with the PaperCut NG Client installer. Keep reading below to understand what I am doing and to create the transform file yourself, but be aware that I plan to provide the finished transform file with an additional bug fix next time. If you can wait, you can avoid the work.

  1. Run Orca.exe
  2. Open “%USERPROFILE%\Downloads\PCClient\win\pc-client-admin-deploy.msi”, and select the option “Open as read-only”. This prevents you from accidentally modifying the installer file provided by the vendor.
  3. Open Windows PowerShell (or the newer PowerShell—either one works for this), and use the New-Guid cmdlet to generate a new GUIDs for use as the identifier for our new component and as the identifier for our new registry value.

    The following will create the registry identifier in the same format as others in the MSI file:
    “reg$((New-Guid).ToString().ToUpper())” -replace ‘-‘

    The following will create the component GUID in the same format as other GUIDs in the PaperCut NG Client MSI file:
  4. In Orca, select Transform menu > New Transform.
  5. Select the Registry table.
  6. Tables menu > Add Row…, and create a new row with these values:
    • Registry: [Paste the registry identifier generated above.]
    • Root: 2
    • Key: SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    • Name: PaperCutNG
    • Value: "[APPLICATIONROOTDIRECTORY]pc-client.exe" --silent
    • Component_: RunAtSignIn
  7. Select the Component table.
  8. Tables menu > Add Row…, and create a new row with these values:
    • Component: RunAtSignIn
    • ComponentId: [Paste the component GUID generated above.]
    • Attributes: 260
    • Condition: [Leave blank.]
    • KeyPath: [Paste the registry identifier generated above.]
  9. Select the FeatureComponents table.
  10. Tables menu > Add Row…, and create a new row with these values:
    • Feature_: PCClient
    • Component_: RunAtSignIn
  11. Transform menu > Generate Transform, and save the transform file in the same folder as the MSI file as “PCClientAutorun.mst”.


Now, when deploying PaperCut NG Client, you must apply the transform file to get the autorun behavior. The command line with verbose logging will be:
msiexec /package pc-client-admin-deploy.msi /quiet /norestart TRANSFORMS=PCClientAutorun.mst /l*v "%TEMP%\PaperCutNGClientLog.txt"

Once this is installed across your organization, the PaperCut NG Client will run automatically at user sign-in wherever it is installed, and you can remove any existing measures to make that happen, such as Group Policy settings or logon scripts.

Next time, I’ll combine the modifications above with a bug-fix to allow the PaperCut NG Client to install in the system context when delivered via Microsoft Intune, and I will make my final transform file available for you to use so you don’t have to do most of the work described above.

Posts in this series:

  1. Transforming PaperCut NG Client installer to run the program automatically
  2. Modifying PaperCut NG Client to install in the system context via Microsoft Intune

<update date=”2023-12-08″>Added link to the second post in the series and struck the offer to supply an MST file.</update>

Enterprise Printing Introduction

Until now, I have focused all of my blog posts on deploying software. With this and subsequent posts, I use a broader definition of the word “deployment”. This is the first of a series of posts on deploying and managing printers in an enterprise.

Several of my coworkers and I were frustrated with inconsistent printer configurations, ad hoc printer deployment and management practices, and lack of printer driver management and deployment guidance in our organization. Online research yielded many results of how to implement specific technologies, but we found no big-picture guidance for managing printing in the enterprise. Over the course of about a year, we met biweekly on our own time to share research and experimental results, brainstorm, argue, and formulate a comprehensive enterprise printing service and strategy for our organization. We have implemented the service described in this blog series, and we offer this to the world as a model for enterprise printing implementation in any organization.

It was a privilege to collaborate with my colleagues Shaun Holmes, Matt Norton, and Branden Mazure on this project.

Problem and Goal

How do you deploy and manage printers? How do you provide users with connections to the printers that they need? How do you update printer software and drivers? How do you secure network printers?

These were some of the questions we faced as we began thinking about building and documenting an enterprise printing service for our organization. As we researched, we found a lot of vendor-specific documentation, a lot of which was not very good. We never found a comprehensive description of enterprise printing best practices, so we met and argued about it biweekly for a year, and this is the result.

Our goals:

  • Research and document high-quality enterprise printing guidance for use by ourselves and others to provide consistency and quality of service.
  • Build a system that we would want to use and which would provide as much flexibility and automation as possible.
  • Never think about printing again, except for when we want to.

Framework for Discussion

As we wrestled with the technical and human problems involved in enterprise printing, we arrived at the concept of “Enterprise Printing Competency” levels, or “EPC”. This is a framework where each idea builds and improves on the previous one, and if you stop at any point, you are better off than you were before.


“Enterprise Printing” refers to the management of network-connected printers using scripting or other tooling for automation, consistency, and reliability wherever possible. As examples, large departmental printers and multifunction copiers are in scope. Even a desktop printer used primarily by a single person is in scope if it is connected to the network. The following are not in scope:

  • Non-network-attached printers, such as a USB printer on a staff member’s desk.
  • Large printers or multifunction copiers without network connectivity.

To be clear, such out-of-scope devices would benefit from many of the practices described in this blog series, but I will make no effort to call these out. This is going to be a long series even with a narrow scope.

Many vendors would love to sell you their printer management products. In our organization, a large midwestern university, we use such a vendor solution to manage printers for student use, but we had no commercial solution for faculty and staff printers. The solution described here is for the latter case and uses capabilities already available in a Windows Server environment.

Continuum of Competency

The Enterprise Printing Competency (EPC) levels form a continuum. At the lowest level, EPC-0, all printer configuration and management is performed manually. Printing as an IT service is a high-maintenance, low-flexibility activity at EPC-0. As the EPC level of an organization increases, maintenance costs decrease and flexibility increases.

Illustration of Enterprise Printing Continuum of Competency

Here are the EPC levels shown above in table form for reference.

Enterprise Printing Competency (EPC) Levels
EPC Level Name
0 Manual Configuration
1 Names, Not Addresses
2 Secure Hardware
3 Print Servers
4 Deployment
5 High Availability, Part 1

The EPC continuum is open ended. We decided to stop at level 5 because we realized that it was all that was achievable in our organization at the time, but you can tell by the name that we imagined a future EPC-6 for further implementation of high availability (High Availability, Part 2).

Coming Up

In subsequent articles, I will describe each of the Enterprise Printing Competency levels in depth.

Posts in this series:

  1. Enterprise Printing Introduction

Deploying Microsoft .NET Framework 3.5 SP1 to Windows 10 Anniversary Update and Windows Server 2016 with System Center Configuration Manager

With the August 2016 release of Windows 10 version 1607 (“Anniversary Update”) and the initial release of Windows Server 2016 in October 2016, it is well past time to revisit last year’s entry on deploying the .NET Framework 3.5 SP1. Although Windows Server 2016 was released two months after its corresponding Windows 10 release, both have the same year-month version number of “1607”, and their build numbers are also identical: 14393. This is excellent news because it suggests that we may be able to use the same files for installing .NET 3.5 on both operating systems; indeed, investigation shows that the files found under sources\sxs on the installation media for Windows 10 v1607 64-bit and Windows Server 2016 are identical.

Please refer to my January 2016 entry on building the Configuration Manager application for .NET 3.5 SP1 if you need to start from scratch. Below, I will add to that Configuration Manager application.

Acquiring the Payload Files

Remember, nearly every Windows version has a different payload for NetFx3. We will have to locate all of the needed files and copy them to a file share for access by Configuration Manager. In this case, we’ll just add to what we built before.

On your application staging file share (wherever you put application source files for Configuration Manager to find), locate the folder structure for .NET 3.5 that you created before. Mine is \\fileserver\software$\Microsoft\.NET Framework 3.5 SP1. Under this folder, create a folder for each operating system version that we will be adding. Note that the 64-bit client OSes can share source files with their server counterparts; as mentioned above, I checked, and the NetFx3 files are the same for Windows Server 2016.

Folder Name Description
Win10.0.14393×86 Windows 10 Anniversary Update (32-bit)
Win10.0.14393×64 Windows 10 Anniversary Update and Windows Server 2016 (64-bit)

We are only adding two deployment types to our existing ConfigMgr application, but they will bring the total count of deployment types to 11.

Get your DVDs or ISOs ready; it’s time to copy the NetFx3 payload files to the folders you just created! Assuming that your Windows 10 v1607 32-bit installation media is available in drive D: (whether physical media or a mounted ISO), here is my preferred command to copy the files:

Robocopy "D:\sources\sxs" "\\fileserver\software$\Microsoft\.NET Framework 3.5 SP1\Win10.0.14393x86" /E /DCOPY:DAT /XJ

I prefer using Robocopy because it allows me to preserve the time stamps on any folders I am copying with the /DCOPY switch. Use a similar command to copy the NetFx3 content from the Windows 10 v1607 64-bit media to its folder in the folder structure we built above.

You can also get the files from the Features on Demand ISO available from the Microsoft Volume Licensing Service Center. In that case, use this command to copy the 32-bit Windows 10 Anniversary Update payload for NetFx3:

Robocopy D:\ "\\fileserver\software$\Microsoft\.NET Framework 3.5 SP1\Win10.0.14393x86"

Building the Configuration Manager Application

Windows 10 and Windows Server 2016 v1607

Previously, we built deployment types for Windows 10 v1507 and v1511, 64-bit and 32-bit. We need to add two more deployment types for Windows 10 v1607 (“Anniversary Update”) and Windows Server 2016. The properties for these new deployment types are very similar to those for the earlier versions of Windows 10. As usual, we must make appropriate changes to the Name, Content location, and Requirements properties. We’ll use the custom Global Condition from a previous post in the Requirements. For any properties omitted below, such as the detection logic, use the same values as with earlier versions of Windows 10.

Property Value
Deployment Type Properties – Windows 10 Anniversary Update (32-bit)
Name Feature Installation – Windows 10 Version 1607 (32-bit)
Content location \\fileserver\software$\Microsoft\.NET Framework 3.5 SP1\Win10.0.14393×86\
Installation program “%SystemRoot%\System32\Dism.exe” /Online /LogLevel:4 /Add-Package /PackagePath:”” /NoRestart /Quiet
Uninstall program “%SystemRoot%\System32\Dism.exe” /Online /LogLevel:4 /Remove-Capability /CapabilityName:NetFx3~~~~ /NoRestart /Quiet
Requirements Operating system
One of All Windows 10 (32-bit)
OS BuildNumber Equals 14393
Deployment Type Properties – Windows 10 Anniversary Update (64-bit)
Name Feature Installation – Windows 10 and Windows Server 2016 Version 1607 (64-bit)
Content location \\fileserver\software$\Microsoft\.NET Framework 3.5 SP1\Win10.0.14393×64\
Installation program Same as Windows 10 Anniversary Update (32-bit)
Uninstall program Same as Windows 10 Release (32-bit)
Requirements Operating system
One of All Windows 10 (64-bit), All Windows Server 2016 (64-bit)
OS BuildNumber Equals 14393

Coming Up

Next time, we’ll build a new Configuration Manager application for the Microsoft .NET Framework 4.6.2, which was also released with Windows 10 Anniversary Update.

Deploying Adobe Shockwave Player with System Center Configuration Manager

Welcome to part two of a five-part series on deploying runtimes and reader from Adobe with an app store-like experience using Microsoft System Center Configuration Manager. Today’s episode: Shockwave Player! As I prepared to write, I asked myself, “Does anyone use Shockwave anymore?” It turns out that the answer is pretty much a “no”, but I’m going to stick with my plan to cover Shockwave, Flash, AIR, and Acrobat Reader (in that order) for completeness. Also, Shockwave is the only one of the four that is actually packaged appropriately by the vendor for an acceptable user experience, so it makes sense to cover it first so we can focus on the plumbing of building the application package. Each of these programs receives frequent updates, and it can be quite a task to build new application packages every few weeks. As I have mentioned previously, there are vendors that will take care of this for you, and I encourage you to use one of them if you can afford it and if it makes sense in your organization. My approach here will be to show a do-it-yourself method for automating app package creation for these frequent updates using Windows PowerShell.


To follow along, you will need to have distribution rights from Adobe, PowerShell 5.0, and the Configuration Manager cmdlets. See my previous blog post for details. You may not technically need PowerShell 5.0, but that’s what I have. I’m not going to make any effort to ensure that what I’m doing works on previous versions, so to make sure everything below works for you, I suggest upgrading to version 5.0 or higher. You can check your version of PowerShell from a PowerShell prompt by displaying $PSVersionTable.PSVersion. Here’s the command and its output from my Windows 10 v1511 computer with PowerShell 5.0 installed:

PS C:\> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      0      10586  494

Using PowerShell for Packaging: First Iteration

Let’s begin by outlining the plan in comments. We’ll start with a simple, single-use script and then refine it later.

# Download the Shockwave installer from Adobe

# Extract the version information from the installer

# Save the installer to the appropriate location

# Extract the program icon

# Create the application object in Configuration Manager 


There are several ways to download a file from the web with PowerShell. I’m going to choose the simplest one (which may not be the “best” one, depending on your criteria): a built-in PowerShell cmdlet called Invoke-WebRequest. Start by clicking the Shockwave link you received from Adobe. In the Shockwave Player Distribution Downloads table, right-click the Download MSI Installer link, and choose Copy shortcut or its equivalent to copy it to the clipboard. Paste the URL into the PowerShell script and assign it to a variable. This will be important later. Basically, we’re going to use Invoke-WebRequest to download the file to a temporary folder. Unfortunately, things are never as easy as they sound. The download link provided by Adobe does not include a filename, but Invoke-WebRequest needs one in order to save the file. It is important (to me, at least) to use the real filename of the file rather than something arbitrary. Also, the link provided by Adobe redirects elsewhere, which complicates matters. Here is the somewhat scary-looking code, and an explanation follows.

# Download the Shockwave installer from Adobe

#$Uri = "[Shockwave-download-URI]"

# We don't know the installer's filename, so generate a temporary one until the file is downloaded 
# and we can get the filename from the WebResponseObject.
$tempOutFilename = [System.IO.Path]::GetRandomFileName()
$tempOutFilePath = "$env:TEMP\$tempOutFilename"

# Download the installer and save it to a temporary location and filename.
# The PassThru switch puts a WebResponseObject in the pipeline in addition to writing the file.
$response = Invoke-WebRequest -Uri $Uri -OutFile "$tempOutFilePath" -PassThru

# Get the filename from the WebResponseObject.
$outFilename = [System.IO.Path]::GetFileName($response.BaseResponse.ResponseUri.AbsoluteUri)

# If the target file already exists, delete it.
# If the file does not exist, Remove-Item returns an error, so ignore errors.
$outFilePath = "$env:TEMP\$outFilename"
Remove-Item -Path "$outFilePath" -Force -ErrorAction Ignore

# Rename the temporary file with its proper name.
Rename-Item -Path "$tempOutFilePath" -NewName $outFilename

# Remove zone identifier.
Unblock-File -Path "$outFilePath"

Obviously, replace the URI placeholder text with the appropriate download link from Adobe. Since that link does not include the filename, we generate one with a call into the .NET Framework’s System.IO.Path.GetRandomFilename() function. Next, we use Invoke-WebRequest to download the file to a temporary folder. The Invoke-WebRequest cmdlet puts its result on the pipeline as a WebResponseObject unless you pass the OutFile parameter, in which case it puts nothing on the pipeline. The PassThru switch overrides this behavior and puts the response object on the pipeline in addition to writing the output file. This object, which is captured by the response variable, contains the actual URI used to obtain the downloaded file after any redirects were followed. The System.IO.Path.GetFileName() function extracts just the filename from this URI. We delete any existing file with the same name in the temporary folder and then rename the downloaded file with the proper name. Finally, we remove the zone identifier from the downloaded file with Unblock-File in order to prevent security prompts when attempting to install the program later. For more information on this, see About URL Security Zones on TechNet. Scott Hanselman also has a great discussion of the zone identifier alternate data stream from 2007, but he doesn’t mention the PowerShell cmdlet we will use, so maybe it did not yet exist back then.

Extracting Version Information

The download link and the file we downloaded does not contain any version information in the name, but we will need the version in order to make the Configuration Manager application. I have not found any built-in PowerShell cmdlets to extract version information from a Windows Installer (MSI) file, but fortunately, we have the Internet to help us!

I found a number of scripts in a number of places, but I chose to use the one from Nickolaj Andersen at because it was the simplest that suited my needs. Visit that link, follow the instructions there, and then come back here to continue. When you’re finished, you’ll have a Get-MSIFileInformation.ps1 file in the same folder as the script we are writing here.

Since we’re leveraging an outside script for most of the work here, our own version extraction code is quite short.

# Extract the version information from the installer

$newMsiVersion = .\Get-MSIFileInformation.ps1 -Path "$outFilePath" -Property ProductVersion

#Get-MSIFileInformation returns an array for the ProductVersion property. Convert it to System.Version via a string.
$newMsiVersion = [System.Version]([System.String]$newMsiVersion).Trim()

Unfortunately, the output of the Get-MSIFileInformation function is not of the type that we need, and it cannot be converted directly to a System.Version. To overcome this, we cast it to a string, remove the leading spaces with Trim(), and then cast the string to System.Version.

Saving the Installer to the Proper Location

Now that we’ve downloaded the installer and extracted the version number, it’s time to move it to its final location. This location should be wherever you normally save application installation files for use by Configuration Manager. We’ll supply the root folder, the manufacturer name, and the product name, and then the script will concatenate it all together to make a folder structure of “\\server\share\manufacturer\product ww.xx.yy.zz” for the installer.

# Save the installer to the appropriate location
$Destination = "\\server\share"
$Manufacturer = "Adobe"
$Product = "Shockwave Player"
$productNameAndVersion = "$Product $newMsiVersion"

$destFolder = "$Destination\$Manufacturer\$productNameAndVersion"
New-Item -Path $destFolder -Force -ItemType Directory
Move-Item -Path "$outFilePath" -Destination "$destFolder\$outFilename" -Force

Alert readers will have noticed my inconsistent capitalization of variable names. I did that on purpose because I am going to convert some of the variables to parameters later. Future parameters are in Pascal case; regular variables are in camel case.

Extracting the Program Icon

If you supply an icon file when creating a Configuration Manager application, Software Center will use that icon rather than the generic program icon. This looks more professional and makes Software Center seem more legitimate to the user as a real app store.

The cmdlet we will use later to create the ConfigMgr application accepts only image file formats; it does not accept EXEs, DLLs, or ICOs. How, then, does one extract the needed icons for use with this cmdlet? I would like to be able to extract the highest-quality icon from the EXE setup file, but unfortunately, there does not appear to be a built-in facility for doing so in .NET. I found some native code examples online, so I may revisit this in the future. In the meantime, we’ll make use of the System.Drawing.Icon class.

It takes a little bit of work to get the program icon out of a Windows Installer file. The methodology we will use is:

  1. Perform an Administrative Installation of the MSI in order to extract all of its files.
  2. Extract the desired icon from the main program file (EXE) and save it somewhere for use later.
  3. Delete the Administrative Installation files and folders.
# Extract the program icon

$administrativeInstallFolder = New-Item -Path "$env:TEMP" -Name ([System.IO.Path]::GetRandomFileName()) -ItemType Directory
$administrativeInstallArguments = @("/a", "`"$destPath`"", "/passive", "/norestart", "TARGETDIR=`"$administrativeInstallFolder`"")

Start-Process -FilePath "$env:SystemRoot\System32\msiexec.exe" -ArgumentList $administrativeInstallArguments -Wait

$pathToExe = "$administrativeInstallFolder\System32\Adobe\Shockwave 12\SwInit.exe"
$iconFolder = New-Item -Path "$env:TEMP" -Name ([System.IO.Path]::GetRandomFileName()) -ItemType Directory

$exeIcon = [System.Drawing.Icon][System.Drawing.Icon]::ExtractAssociatedIcon($pathToExe)
$extractedIconFilename = [System.IO.Path]::GetFileNameWithoutExtension([System.IO.Path]::GetRandomFileName())+".png"    #Remove generated filename extensions and add PNG.
$exeIcon.ToBitmap().Save("$env:TEMP\$extractedIconFilename", [System.Drawing.Imaging.ImageFormat]::Png)

Remove-Item -Path $administrativeInstallFolder -Recurse -Force

This section of code leaves us with a PNG file of Shockwave’s main program icon saved in the temporary folder with the name stored in the $extractedIconFilename variable.

Creating the Configuration Manager Application

With all of the requisite pieces prepared, it is time to create the application object. We’ll use splatting to improve the readability of the code. The ConfigurationManager PowerShell module (one of the prerequisites) contains the needed cmdlets.

Application Object

# Create the application object in Configuration Manager

Import-Module ConfigurationManager

# For clarity, prepare all arguments for the Configuration Manager cmdlets in advance via splatting.
$description = "Over 450 million Internet-enabled desktops have Adobe Shockwave Player installed. These users have access to some of the best content the Web has to offer - including dazzling 3D games and entertainment, interactive product demonstrations, and online learning applications. Shockwave Player displays Web content that has been created using Adobe Director."
$appParams = @{
                Name = $productNameAndVersion;
                AutoInstall = $true;            # General Information tab: "Allow this application to be installed from the Install Application task sequence action without being deployed"
                Description = $description;
                IconLocationFile = "$env:TEMP\$extractedIconFilename"
                IsFeatured = $false;            # "Application Catalog tab: Display this as a featured app and highlight it in the company portal"
                LocalizedApplicationDescription = $description;
                LocalizedApplicationName = $appName;
                Owner = $env:USERNAME;          # Replace this with something more descriptive if desired, such as "FirstName LastName (".
                Publisher = $Manufacturer;
                ReleaseDate = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0);
                SoftwareVersion = $newMsiVersion;
                SupportContact = $env:USERNAME

$ConfigurationManagerApplicationLocation = "CM1:\Applications\Free" #Replace with script parameter later
Set-Location -Path $ConfigurationManagerApplicationLocation

$cmApp = New-CMApplication @appParams
Move-CMObject -FolderPath $ConfigurationManagerApplicationLocation -InputObject $cmApp

Remove-Item -Path "$env:TEMP\$extractedIconFilename" -Force

All the parameters that we care about for New-CMApplication are included in the $appParams variable. The ConfigurationManager module’s cmdlets require use of a special PSDrive in order to function, so you should substitute your site name for “CM1” and your preferred location for the application object for “Applications\Free” in the $ConfigurationManagerApplicationLocation variable. Unfortunately, regardless of the current directory, the New-CMApplication cmdlet creates application objects in the Applications folder only, so we must use the Move-CMObject cmdlet to put it where we want it. Finally, we use Remote-Item to delete the extracted icon file.

All of this code creates an application object and puts it in the desired location, but so far, it doesn’t actually install any software. To do that, we must add a deployment type.

Deployment Type

We’ll use splatting again to simplify the code; all of the parameters that we care about for the deployment-type-creation cmdlet are included in $dtParams.

$installCommand = "msiexec /package ""$outFilename"" /quiet /norestart"

$dtParams = @{
                InputObject = $cmApp;
                ContentLocation = $destPath;
                InstallCommand = $installCommand;
                DeploymentTypeName = "$newMsiProductName - Windows Installer (*.msi file)"; # Match what ConfigMgr Console would name it by default
                LogonRequirementType = "WhetherOrNotUserLoggedOn";
                UserInteractionMode = "Hidden";
                InstallationBehaviorType = "InstallForSystem"
Add-CMMsiDeploymentType @dtParams

The installation command is a standard Windows Installer command line that specifies no user interface and blocks any requested computer restart requests. MsiExec.exe will, however, return a special value (1641 or 3010) if a restart is needed, and since we didn’t override the return values, the defaults in Configuration Manager will honor this and cause Software Center to notify the user. (In a task sequence, the Configuration Manager client will restart the computer, if needed, and then continue with the next task sequence item.)

We specify the application object created earlier as the InputObject so that the cmdlet knows which one should get this new deployment type. We specify the full path and filename of the MSI file to the ContentLocation field so that the cmdlet knows which MSI file to read, but content location in the resulting deployment type that we create only contains the path. Because we are supplying an MSI file to an MSI-specific cmdlet, the cmdlet figures out the uninstallation command and detection logic on its own, so we need not specify these items. The values for the LogonRequirementType, UserInteractionMode, and InstallationBehaviorType fields are standard for non-interactive installations that are intended for use from Software Center or in a task sequence.

Coming Up

That’s it for now. You can run this script at any time to get the latest Shockwave Player downloaded and imported into Configuration Manager.

Now, this script leaves room for improvement. Here are some to-do items for the future:

  • Refactor the code into several functions.
  • Parameterize to add flexibility.
  • Generalize the code to make it work for other, similarly-distributed applications.
  • Rewrite the icon-extraction code to get a higher-resolution icon, if available.

I’m going to tackle these items in future posts in this series. In addition, once this blog series is finished, I plan to post the final code on GitHub to facilitate easier usage than copying and pasting from numerous code snippets.

Next time, we’ll take a look at Adobe Flash Player.

Deploying Adobe Runtimes and Reader: Introduction

Last time, I presented my views on what the software deployment experience ought to be like for users and described some rules or principles for software installation programs to provide that experience. I want to flesh out those principles with some small, focused examples. This five-post series will present deployment of the free runtimes and readers from Adobe, using System Center Configuration Manager’s Software Center application to provide the app store experience. We’ll be working with AIR, Flash, Shockwave, and Acrobat Reader DC.

Obtain Distribution Rights from Adobe

Adobe packages its free players differently for consumers and businesses. This is unfortunate because all installers for desktop Windows applications should be packaged as Windows Installer (MSI) files, period. The good news is that the business versions of three out of four of these Adobe programs are packaged as Windows Installer files. The bad news is that they are not publicly available; you have to ask for them.

To get the needed files, you must obtain distribution rights from Adobe. You will also have to create an Adobe ID in order to complete the distribution agreement. The following pages describe the availability of distribution rights for their respective products.

Clicking the “Apply” button on any of these pages will prompt you to sign in with an Adobe ID. After signing in, the Adobe Runtimes / Reader Distribution License Agreement page will be displayed. You can select all four products from this page and apply for licenses for all of them at once.

It usually takes at least 24 hours for the distribution request to be processed. You will receive an approval e-mail with a link to the installer for each product. I will not be revealing the links I received in this blog series as that would be a violation of the agreement. You must obtain distribution rights directly from Adobe in order to get the download links and follow along with this blog series.

Obtain Configuration Manager PowerShell Cmdlets from Microsoft (Optional)

I’m planning to use PowerShell in my examples in this series. There is entirely too much clicking involved in building application packages in Configuration Manager. Using PowerShell will alleviate the wrist strain of clicking, and the scripts we write for building these Adobe packages will be reusable for Adobe’s frequent updates to its products.

I’ll be using PowerShell 5.0, so if you are on a version of Windows lower than 10 (where PowerShell 5.0 is built in), be sure to upgrade by installing Windows Management Framework 5.0.

You will also need the System Center Configuration Manager Cmdlet Library, which is available from the Microsoft Download Center. Be sure to install the latest version.

Coming Up

Next time, we’ll examine the behavior of Adobe Shockwave and its installer. This is the simplest installer of the four, so it is a good place to get started and to get our feet wet with the Configuration Manager PowerShell cmdlets. In later posts, we’ll cover the other three programs, going in order of increasing complexity.

Providing a Great Software Deployment Experience

What is the ideal software delivery experience? Apple figured it out initially with the iPhone and later with other products, and Microsoft followed suit beginning with Windows 8. The App Store and the Windows Store are curated, safe spaces from which to purchase and download applications, and these stores provide fantastic user experiences. (Other platforms have package management systems with varying features and capability, but I have no experience with those, and my focus is on Windows software deployment.)

With an app store, an application and all of its updates come from one place. Because all of the apps available there go through a validation process, users can feel confident that they are not downloading malware. The apps install without prompting the user for information, and they work immediately. If an app requires configuration, it prompts the user and can save the configuration to a cloud storage location so that the app is immediately usable upon whichever device the user runs it. Software just works, and users can quickly get to the business of using the software instead of installing and configuring it.

The Desktop Difference

Contrast this with the installation and usage experience for traditional desktop applications. I’m going to focus on software for the Windows operating system for the rest of this post. Here are some typical steps to installing and using software.

  1. Find the desired software somewhere on the Internet and buy it. If it is free, hope that you were not tricked into downloading malware instead of the software you wanted.
  2. Run the installer. This is probably an executable program that must be run with administrative credentials, so you are basically giving complete control of your computer over to the setup program.
  3. Answer configuration questions asked by the setup program. You may not be confident in your answers or may not have any idea how to answer some of them.
  4. Restart your computer and then spend 20 minutes re-opening all of your programs and browser tabs.
  5. Notice that the installer has put one or more icons not only on your Start menu, but also on the desktop and on the taskbar.
  6. Further notice that the notification area shows that the new program is already running, even though you didn’t specify this.
  7. Run the new program, and answer additional configuration questions asked by the program. Again, you may not know the answers to these questions.
  8. Take a tour of new features!
  9. Dismiss a “Did you know…” pop-up message or maybe a new feature advertisement pane.
  10. Actually use the program.
  11. Realize that you also need the program on another computer, and begin the whole process again.

This may seem extreme, but all of the above behaviors are commonplace. If you decide to uninstall a program, you may have to go through these steps.

  1. Uninstall the application.
  2. Specify options for removal. Should all components be removed? Should data be removed? You don’t really want to uninstall the program, do you?
  3. Complete a survey about why you uninstalled the application.
  4. Restart the computer and then spend 20 minutes re-opening all of your programs and browser tabs.
  5. Discover that some components of the application are still installed but that there is no way to uninstall them through standard procedures.

Here is a concrete example that I observed and recorded in early 2015. There is one particular program that nearly everyone in my organization wants that, when it installs, puts shortcuts on the Start menu, on the desktop, and on the taskbar. Then, even if you delete the desktop and taskbar icons, when another user runs the program, it recreates those icons in that user’s profile. It even uses (or at least did so in early 2015) an undocumented feature of Windows Setup to insert itself into the first-logon experience so that it can create these icons before the user has ever decided to use the program, causing a two-second delay in the first logon experience. Then, when a user actually wants to run the program, the first thing it does is try to take over being the default handler for its particular file type. When the program actually opens, it displays a tab with a tour of new features and tries to get the user to create an account with the manufacturer. This entire experience is bad enough for regular users, but it is truly horrible for lab or classroom environments in a school or university because every single user logon is probably that user’s first time logging onto a given machine. What is this malware, you ask? It’s Google Chrome.

It didn’t have to be this way. Microsoft has published application user experience guidelines for years and years, and it has also had a “Designed for Windows” logo program for software since the Windows XP days (2001) and perhaps even before that. Unfortunately, these guidelines and programs seem to have been largely ignored by software vendors and their customers. I have some ideas about why this happened and thus why software distribution is in such a sorry state today, but my purpose here is not to assign blame; rather, I want to discuss the problems and arrive at some principles to guide the creation of solutions. I think the Apple App Store and the Microsoft Windows Store are reactions to the resistance of independent software vendors to write good software; these app stores codify into “law” the kinds of behaviors that have always been prescribed by user experience and logo program guidelines and make them non-optional, since the operating vendor acts as the gatekeeper for what appears in the store.

The installation, usage, and uninstallation steps listed above are disastrous for large-scale rollouts of software in an organization. It is disturbing to consider the amount of money spent on wages to employees that are not actually doing any work because they are struggling with bad software. If something goes wrong, they will hopefully call the organization’s help desk for assistance; this may reduce downtime, but it requires that another employee be on the other end of the telephone line to help with the issue. If your organization’s IT and top management are even mildly interested in data security and keeping support costs low, most users will not have administrative access on their machines and will thus not even be able to install software themselves. This leaves the deployment to the IT staff using any number of deployment tools available on the market, but there is still a lot of work required to deploy software in a way that mitigates the behaviors described above. In organizations with hundreds or thousands of client computers, manual installation of software expensive and error prone, so we must rely upon software deployment tools. There are numerous deployment and package management systems available, but they cannot help fix the fundamental problems built into software vendors’ setup programs by design. That task falls to the IT professional.

Guidelines for Great User Experience

My goal is to make the desktop application installation and usage experience as close to the idealized app store experience as possible. To guide the work toward that goal, some reference documentation and some specific principles are helpful.

Microsoft provides some great documentation on the proper behavior of Windows applications throughout their entire life cycle—installation, use, and uninstallation. See the following resources at the Windows Dev Center for the most recent versions of the Windows application design and certification guidelines:

Everything written by Rob Mensching or anyone else on the WiX Toolset team is also fantastic source material for the way installers ought to work. With that knowledge, we must then set about the task of bending the software to our will, as the tagline of this blog suggests, by fixing or working around the terrible installers published by software vendors, so that we can provide the app store experience to users.

Here is my list of guiding principles with explanations.

  1. The software must be able to be installed silently—that is, without any user prompts. This provides that app store-like experience of one-click installation. It also makes it possible for IT administrators to deploy software without user involvement.
  2. The software must be able to be installed without forcing the computer to restart. A forced restart could cause data loss, and that’s obviously unacceptable.
  3. Eliminate all first-run experiences. This one is sometimes difficult. Many programs want to interrogate the user the first time they run, but this is incredibly frustrating for the user if the application is updated often or in public computing spaces where a user may never sign into the same computer twice (thus getting the first-run experience every time).
  4. Don’t ask the user questions he/she cannot answer. This is a special case of first-run experiences, but it bears mentioning separately. In my observation, there is often a clear mismatch between the level of understanding a software developer expects a user to have about a piece of software and the level of understanding that the user actually has. Many applications ask users questions that they just don’t know how to answer.
  5. As a consequence of the previous four principles, provide any required configuration information either in the application deployment process itself (preferred if possible) or through an outside mechanism like Group Policy or Group Policy Preferences.
  6. Don’t allow an application to overwrite user preferences.
  7. Don’t allow an application to put icons on the desktop or the taskbar. This is a special case of user preferences, since these locations are intended to be for the user to customize. The only appropriate place for an application to put a shortcut is on the Start menu.

Some applications will easily work within these principles. If an application is packaged as a Windows Installer package, you’re already in pretty good shape. Unfortunately, many are provided as setup executables, and these require a variety of techniques to tame. Future posts will focus on individual applications that are common to many organizations—specifically, free readers, players, and browsers—and how to package them in System Center Configuration Manager so that the user experience is as much like an app store as possible.

An Easier Way

There are commercial products available to take care of free apps. I know people that subscribe to one of these services, and they are very happy with it. There are several reasons why an organization may not be able to do this though. An organization that only needs one or two apps covered by one of these auto-updater programs might have trouble justifying the cost for so little benefit. There may be concerns about performance or the additional management burden of another agent program running on every computer in the organization. There may also be security concerns, legitimate or not, that result in blocking such a subscription.

In any case, free readers, players, and browsers are useful for exploring the ideas described above in the context of a specific deployment tool (Configuration Manager) and practicing the techniques needed to achieve the goal of an app store-like application experience. Then when an important, paid-for, poorly-behaved app comes along, the principles and methods needed to fix it will be well understood.

Deploying Microsoft Office 2016: Building the Task Sequence in System Center Configuration Manager for Reliable Deployment

It’s time to wrap up this series on Office 2016 deployment. We’ve built several prerequisite application packages, some Global Conditions, and the Office application package itself. Because Microsoft recommends not installing multiple versions of Office together and because Office Setup cannot remove all components of previous versions, we built a Configuration Manager package with all of the OffScrub scripts from Microsoft Product Support Services to allow reliable removal of previous versions.

The application package we built last time brought everything together except the Offscrub package. That application package is useful for an operating system deployment task sequence or to device collections where you know that no member device has a version of Office already installed. To have reliable installations of Office 2016 with no previous versions, we need to add one more component: a task sequence.

Building the Configuration Manager Task Sequence

Create a custom task sequence. Do not specify a boot image. Assuming that you are installing multiple Office programs, here is a suggested name and description:

Name Office Family 2016 (32-bit) [Remove existing]
Description Removes previous versions of Office programs and then installs Office, Project, and Visio 2016 and all of their prerequisites.

You will have to give some careful thought to the content of these fields; both of them have rather short length limitations that prevent more accurate descriptions than what is shown above.

Right-click the newly-created task sequence, and click Edit. Now I will describe each step you should add to the task sequence.

Step 1: Start Software Center after restart

Type Run Command Line
Name Start Software Center after restart
Description Software Center must be running in order for progress to be displayed. The intrinsic “start” command of cmd.exe must be used; otherwise, Software Center will start on sign-in, but the desktop will not be loaded until it is closed.
Command line "%SystemRoot%\System32\reg.exe" add "HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce" /v "!SoftwareCenterForOffice2016TS" /t REG_SZ /d "\"%SystemRoot%\System32\cmd.exe\" /C \"start \"Starting Software Center...\" \"%SystemRoot%\CCM\SCClient.exe\" softwarecenter:\"" /f /reg:64
Disable 64-bit file system redirection Checked

This step ensures that Software Center is restarted automatically the next time someone signs in. This is important to show status to the user in case the task sequence is being run. The exclamation point prefix on the RunOnce registry value defers deletion of the value until after the command has completed successfully. That means that the command will not be deleted if it fails, and it will therefore by tried again the next time the RunOnce key is evaluated.

Step 2: Restart the computer

Type Restart Computer
Name Restart Computer
Description The “/Force” switch is being passed to all of the OffScrub scripts. This kills running Office programs and will thus cause data loss of any unsaved files. Restart to prevent this from happening.
Specify what to run after restart The currently installed default operating system
Notify the user before restarting Checked
Notification message Microsoft Office 2016 will be installed, and old versions of Office will be removed. The computer must restart to continue. Please save your work and close all programs. This upgrade process requires multiple restarts. You may sign into the computer after it restarts in order to view progress, but do not attempt use any programs until this process is complete.

As the description says, the OffScrub scripts will all forcibly terminate any running Office application without prompting the user to save data. If a user runs this task sequence manually, this delayed restart step informs the user what is happening and gives him or her time to save data.

Step 3: Remove old versions of Office

Type Group
Name OffScrub
Description Remove old versions of Microsoft Office.

We’ll call all of the OffScrub scripts from inside this group.

Step 3a: Remove Office 2003

Type Install Package
Name Remove Office 2003
Description Runs OffScrub03 script from Microsoft Support.
Install a single software package Selected
Package Microsoft OffScrub
Program OffScrub03

Step 3b: Remove Office 2007

Add a step to remove Office 2007 just like the one for Office 2003, replacing property values as appropriate.

Steps 3c and 3d: Remove Office 2010

Add a step to remove Office 2010 just like the one for Office 2003, replacing property values as appropriate. Then, make a copy of it so that there are two identical steps that remove Office 2010. Make the following changes:

  • Change the description of the first one to:
    Runs OffScrub10 script from Microsoft Support and continues on errors. OffScrub10 uses non-zero exit codes for informational reporting, which are interpreted by ConfigMgr to be errors.
  • Set the first one to Continue on error (on the Options tab).
  • Change the name of the second one to:
    Remove Office 2010 (retry).
  • Change the description of the second one to:
    Runs OffScrub10 script from Microsoft Support again and fails on errors. OffScrub10 uses non-zero exit codes for informational reporting, which are interpreted by ConfigMgr to be errors.
  • Add a condition to the second one (on the Options tab):
    Task Sequence Variable _SMSTSLastActionSucceeded equals “false”

Microsoft was consistent in the return values for all of the OffScrub scripts except for the one for Office 2010. In this one, some non-error conditions are reported back via the script’s exit code, and unfortunately there is no way to specify success values for ConfigMgr package programs. The approach I chose was to run the script once ignoring errors, and then run it again, if needed, failing on errors (thus causing the task sequence to stop).

If the first run of the script is successful and returns 0 (zero), the task sequence will record “true” in the _SMSTSLastActionSucceeded variable, and the second run of the script will be skipped due to the condition.

If the first run of the script is successful and returns a non-zero informational value, the task sequence will record “false” in the _SMSTSLastActionSucceeded variable, and the second run of the script will be executed, but it will have nothing to do and so will finish quickly, returning 0 (zero) because it has no special information to report.

If the first run of the script fails and returns a non-zero failure value, the task sequence will record “false” in the _SMSTSLastActionSucceeded variable, and the second run of the script will be executed. Assuming the script runs into the same problem that it did during the previous try, it will fail again, but this time the task sequence engine will see the failure and stop the task sequence.

Step 3e: Remove Office 2013

Add a step to remove Office 2013 just like the one for Office 2003, replacing property values as appropriate.

Step 3f: Remove Office 2016

Add a step to remove Office 2016 just like the one for Office 2003, replacing property values as appropriate.

Step 3g: Remove Office Click-to-run

Add a step to remove Office Click-to-run just like the one for Office 2003, replacing property values as appropriate.


Back outside of the OffScrub group, we’re ready to start installing software. The instructions below install all of the Office prerequisites as separate task sequence steps. This provides better feedback to the user as to what is happening and should make it easier to follow along in the logs if something goes awry.

New Install Application steps have a Retry this step if computer unexpectedly restarts checkbox checked and the number of times to retry set to 2 on the options tab. Leave these default settings for all Install Application steps added below.

Step 4: Install .NET 3.5 SP1

Type Install Application
Name Install .NET 3.5 SP1
Description Leave blank.
Install the following applications Add the .NET Framework 3.5 SP1 application package that we created earlier as the only item in the list.

Step 5: Start Software Center after restart

Copy the Start Software Center after restart step from the top of the task sequence and paste it here.

In my testing, installing the .NET Framework 4.x required a restart for completion, so we’ll set up Software Center to start again after that installation and restart is complete. At the very end of the task sequence, we’ll delete this registry value if it is still present. This would be the case if the computer already had .NET 4.5.2 or higher installed prior to running this task sequence.

Step 6: Install .NET 4.5.2 or higher

Type Install Application
Name Install .NET 4.5.2 or higher
Description Leave blank.
Install the following applications Add the .NET Framework 4.5.2 or higher application package that we created earlier as the only item in the list.

Step 7: Install Report Viewer 2008

Type Install Application
Name Install Report Viewer 2008
Description Microsoft Report Viewer 2008 is required for Database Compare 2016, which is a companion program to Access 2016.
Install the following applications Add the Microsoft Report Viewer Redistributable 2008 (KB971119) application package that we created earlier as the only item in the list.

Step 8: Install Office Professional Plus 2016 (32-bit)

Type Install Application
Name Install .NET 3.5 SP1
Description Leave blank.
Install the following applications Add the Microsoft Office Professional Plus 2016 (32-bit) application package that we created earlier as the only item in the list.

Steps 9 and 10: Install Visio and Project

Add Install Application steps for the Visio and Project application packages that we created earlier. These will be much like the Office installation step above.

Step 11: Install Software Updates

Type Install Software Updates
Name Install Software Updates
Description Leave blank.
Install software updates assigned to the destination computer All Software Updates

Step 12: Remove RunOnce value to start Software Center

Properties tab
Type Run Command Line
Name Remove RunOnce value to start Software Center
Description If the OS was fully patched (including having .NET 4.5.2 or higher installed) prior to running this task sequence, no restarts may have been triggered since the last “Start Software Center after restart” step, so remove the registry value if it is present.
Command line "%SystemRoot%\System32\reg.exe" delete "HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce" /v "!SoftwareCenterForOffice2016TS" /f /reg:64
Disable 64-bit file system redirection Checked
Options tab
Success codes 0 1

That’s the number zero, followed by a space, followed by the number one.

Continue on error Checked

The description field contents pretty much explains what this is doing. Note the changes to the Options tab, though. If reg.exe deletes the value successfully, it returns 0 (zero). If the value is not there, though, it returns 1. Since we just want to run the command and consider it successful no matter what, we need to set 0 and 1 as valid success codes as shown above. As insurance that some other unknown error condition won’t cause the task sequence to register as a failure, we also check the Continue on error box.


That’s it! Running this task sequence will ensure that target machines have exactly one version of Microsoft Office—Office 2016—and that all of its prerequisites are present. You will want to think carefully about how you deploy it. If your users are conditioned to sign out at the end of each work day, you may be able to deploy the task sequence as required for a specific time overnight without many problems. If users typically leave their computers turned on and signed in, with unsaved data open in various applications, you may want to just deploy the task sequence as “Available”, and then notify users via e-mail that they can run the task sequence themselves from Software Center. Running it manually will give users the warning that the computer will be restarted and give them time to save their data.

Be advised that in my testing, this task sequence took a minimum of 30 minutes to run and typically took quite a bit longer; just installing the updates takes a while. If users will run the task sequence themselves, I suggest advising them to begin the task sequence before going to lunch or before leaving for the day. If you know that your environment doesn’t have certain versions of Office, you could disable the corresponding OffScrub step(s) in order to save time. For example, I don’t think there are any Office 2003 installations remaining in my organization, so I disabled that step. Further, we no longer have a site license for Project, so I removed it. With those changes, here is what my task sequence looks like this:

Picture of Task Sequence Editor window


Deploying Microsoft Office 2016: Building the Application Package in System Center Configuration Manager

It’s been a long process, but it’s finally time to build the Application objects in System Center Configuration Manager for Microsoft Office and its sibling programs. There is just one bit of housekeeping to take care of first. One of my rules for a Configuration Manager Application is that it must have an uninstallation command. This provides Software Center with the ability to remove it, thus giving users an “app store” experience. That takes a little bit of work, and so we’ll do that first. Then we’ll walk through the Application-building process. Next time, we’ll use our new Applications along with our Offscrub package to build a task sequence for deployment.

Silent Uninstallation

As we did in the Customizing Setup post, we will consult the Office 2013 documentation to help us. The Setup command-line options reference for Office 2013 on TechNet has a helpful section describing uninstallation. Basically we need to use a custom config.xml file to instruct the setup program to perform a quiet uninstallation. This documentation doesn’t mention it, but because Configuration Manager Applications must not initiate a reboot, I’m going to add the SETUP_REBOOT property with a value of “Never” in order to be certain that the uninstallation process will not restart the computer unexpectedly. (You may recall that we added this property to the customization file for installation, but we don’t have a customization file for uninstallation.) To do that, we’ll use the Setting element of config.xml.

Open your favorite text editor, and save the following text as UTF-8. I named my file “Config-ProPlus2016-Silent-Uninstall-2016-02-22.xml” in the root of my deployment folder: \\fileserver\software$\Microsoft\Office Professional Plus 2016 (32-bit).

<Configuration Product="ProPlus">
    <Display Level="None" CompletionNotice="No" SuppressModal="Yes" AcceptEula="Yes" />
    <Setting Id="SETUP_REBOOT" Value="Never" />

You can quickly create the needed files for other products in the Office family by changing the Product attribute of the Configuration element. Open the config.xml file located inside each product’s folder to obtain the appropriate value for that product. For example, for Visio Professional, look at the vispro.ww\config.xml file, and find that the Product attribute must be “VisPro”.

<Configuration Product="VisPro">

Warning: Don’t change the existing config.xml files in the installation source. Office Setup uses these files during installation, so our uninstallation settings must be saved elsewhere.

Building the Configuration Manager Application

Building the Configuration Manager Application for Office is a two-pass process. First, we’ll point ConfigMgr to the product MSI so that as many properties as possible populate automatically. Then we’ll go back and edit the Application to add our uninstallation command, prerequisite applications, and system requirements.

  1. In Configuration Manager Console, in the Software Library workspace, navigate to Overview > Application Management > Applications.
  2. In the ribbon, click Create Application. The Application Wizard will appear.
  3. On the General – Specify settings for this application page, select Automatically detect information about this application from installation files, and choose Windows Installer (*.msi file) as the Type.
  4. In the Location box, type the network path to the specific product’s MSI file under your installation source. For example, the MSI file for 32-bit Office Professional Plus is located in the proplus.ww folder. In my installation source, it is
    \\fileserver\software$\Microsoft\Office Professional Plus 2016 (32-bit)\proplus.ww\proplusww.msi
  5. Click Next, and then click Next again to begin customization.
  6. Fill out the Specify information about this application page. This is where we supply Office Setup with our Office Customization Tool settings as well as our uninstallation settings. Although Office has a Windows Installer-based setup process, using setup.exe is required. Run setup /? to see all of the options. Keeping in mind that our example is 32-bit Office Professional Plus 2016, here are the settings.
    Name Microsoft Office Professional Plus 2016 (32-bit)
    Publisher Microsoft
    Software version 2016 (32-bit)
    Installation program setup.exe /adminfile "OCT-ProPlus2016-x86-Silent-Install-2016-02-22.MSP" /config "proplus.ww\config.xml"
    Run installation program as 32-bit process on 64-bit clients. Checked
    Install behavior Install for system

    Because we combined multiple products into one installation source, Office Setup does not automatically know which product we want to install. The /config switch and its argument provide this information to Setup so that the user is not prompted.

  7. Click Next, and verify that the settings are correct.
  8. Click Close to exit the wizard.

Double-click the newly-created Application object to open it. Now we’ll change additional settings that weren’t available in the wizard.

  1. On the General tab, check the Allow this application to be installed from the Install Application task sequence action without being deployed.
  2. On the Application Catalog tab, next to the Icon label, click Browse… Navigate to the Office installation source folder, and choose setup.exe. Select its only icon as the icon for this Application. Although this setting is on the Application Catalog tab, the icon will also appear in Software Center. This adds a level of professionalism to the Application package and makes Software Center seem more like a well-put-together app store.
  3. On the Deployment Types tab, select the deployment type and click Edit.
  4. On the Content tab, in the Content location box, remove the specific product folder from the path. In this case, that means deleting proplus.ww so that the path is \\fileserver\software$\Microsoft\Office Professional Plus 2016 (32-bit)\. (Configuration Manager used the longer path because we initially pointed it to the MSI file, but we really need the whole folder structure.)
  5. On the Programs tab, type the following into the Uninstall program text box:
    setup.exe /uninstall ProPlus /config "Config-ProPlus2016-Silent-Uninstall-2016-02-22.xml"
  6. On the Requirements tab, add the system requirements we obtained in the Overview and Prerequisites.
    Requirement Type Operator Values
    CPU speed Greater than or equal to 1000 MHz
    Total physical memory Greater than or equal to 2000 MB
    Free Disk Space of system drive Greater than or equal to 3000 MB
    Operating system One of Windows 7 SP1 (64-bit), Windows 7 SP1 (32-bit), Windows Server 2008 R2 SP1 (64-bit), All Windows 8 (64-bit), All Windows 8 (32-bit), Windows Server 2012, All Windows 8.1 (64-bit), All Windows 8.1 (32-bit), Windows Server 2012 R2, Windows 10
    OS Installation Type Not equal to Server Core
    Internet Explorer Version Begins with 11.
    (Note that the period is included in the value: “11.”)
  7. On the Dependencies tab, add a dependency group with the name .NET Framework 3.5, and add the 32-bit deployment types from the Microsoft .NET Framework 3.5 Application package that we created earlier. That should be nine deployment types: two each (32-bit and 64-bit) for Windows 10 v1511, 10 Release, 8.1/2012 R2, and 8/Server 2012; and one for all bitnesses of Windows 7/Server 2008 R2.
  8. Add a dependency group with the name .NET Framework 4.x, and add both deployment types from the Microsoft .NET Framework 4.5.2 or higher application package that we created earlier.
  9. Add a dependency group with the name Report Viewer, and add the single deployment type for the Microsoft Report Viewer Redistributable 2008 Application that we created earlier.
  10. Click OK until you have dismissed the Application’s Properties window.

Congratulations! Now you have an Office 2016 application package suitable for deploying during operating system deployment with a task sequence. Unfortunately, all the work we have done up to this point is still not quite enough to have a reliable deployment of Office on existing computers with a previous version of Office already installed. Do not–I repeat, DO NOT–deploy this application package to your whole company. If you do, you will have a bad time. Why? See my previous post on removing old versions for the answer. For now, you can go ahead and use this application in new deployments, but you’ll have to tune in next time to get the solution for existing installations.

Other Programs in the Office Family

You can follow the same general procedure to package the other Microsoft Office-family products we included in our source folder structure. Make a separate Configuration Manager Application for Visio and Project Standard. Include all of the same system requirements and dependencies except for Report Viewer which can be omitted.

Coming Up

The next post is the last one in the series on deploying Microsoft Office 2016. In it, I will explain how to use everything we’ve built to provide a reliable delivery of Office 2016 in your organization regardless of whether an existing Office installation is present.

<update date=”2017-07-11″>Corrected HTML encoding errors in code samples.</update>

Deploying Microsoft Report Viewer Redistributable 2008 with System Center Configuration Manager

Microsoft Office 2016 has a prerequisite that is not mentioned in the system requirements. If you want to use the Database Compare 2016 program to compare Microsoft Access databases, you must have the Report Viewer Redistributable 2008 installed, or you will get a most unhelpful error message.

On you application staging file share (wherever you put application source files for Configuration Manager to find), create a folder for Microsoft Report Viewer Redistributable 2008 with Service Pack 1. Mine will be \\fileserver\software$\Microsoft\Report Viewer 2008 SP1 GDIPLUS.DLL Security Update (KB971119).

Download the executable installer from the Microsoft Download Center, and then extract its content into the folder you just created: Report Viewer Redistributable 2008 Service Pack 1 GDIPLUS.DLL Security Update. Using the folder path I stated above, run the following command at an elevated command prompt: ReportViewer.exe /x:"\\fileserver\software$\Microsoft\Report Viewer 2008 SP1 GDIPLUS.DLL Security Update (KB971119)".

Property Value
Application Properties
Name Microsoft Report Viewer Redistributable 2008 (KB971119)
Publisher Microsoft
Version 2008 (KB971119)
Deployment Type Properties
Name Microsoft Report Viewer Redistributable 2008 (KB971119) – Windows Installer (*.msi file)
Technology Windows Installer (*.msi file)
Content location \\fileserver\software$\Microsoft\Report Viewer 2008 SP1 GDIPLUS.DLL Security Update (KB971119)
Installation program install.exe /q /l “%TEMP%\reportviewer2008KB971119installationlog.txt”
Uninstall program msiexec /x {CED243AB-C7BA-3D42-9609-14EF5A6FC601} /q
Detection method MSI Product Code: {CED243AB-C7BA-3D42-9609-14EF5A6FC601}
Installation behavior Installation behavior: Install for system
Logon requirement: Whether or not a user is logged on
Installation program visibility: Hidden
Configuration Manager behavior: Determine behavior based on return codes
Requirements None
Dependencies .NET 2.0 SP2 (See below for details.)

Note that although the extracted files are still installed with an executable, deep down, the installer is actually an MSI. I was able to find the MSI’s product code and create an MSI deployment type using that information. For now, I’ll leave it as an exercise for the reader to figure out how to do this, but I may revisit the topic in the future. In any case, I provided the product code above, so you don’t need to go searching for it.

Report Viewer requires .NET 2.0. Since .NET 2.0 is basically a sub-component of .NET 3.5, and since .NET 3.5 SP1 is the minimum supported .NET version on all of our supported platforms except for Windows 7, the most economical way to proceed is to just reuse the .NET Framework 3.5 application package that we already built as a dependency (prerequisite) for this application package. On the Dependencies tab, click Add…, and give the new dependency the name .NET 2.0 SP2. Then (still in the Add Dependency dialog window) click Add… and select all nine of the deployment types from the .NET Framework 3.5 application package.

Coming Up

Now we have all of the prerequisite application packages built and our custom installation settings defined. Next time, we’ll put everything together to build a set of Configuration Manager Applications for 32-bit and 64-bit versions of Office, Project, and Visio!