## Deploying Office 2016 language packs (using PowerShell Admin Toolkit)

I need to deploy a language pack for one of our offices via ConfigMgr. I have no idea how to do this!

What they want is for the language to appear in this section of Office:

I don’t know much of Office so I didn’t even know where to start with. I found this official doc on deploying languages and that talked about modifying the config file in ProPlus.WW\Config.xml. I spent a lot of time trying to understand how to proceed with that and even downloaded the huge ISOs from VLSC but had no idea how to deploy them via ConfigMgr. That is, until I spoke to a colleague with more experience in this and realized that what I am really after is the Office 2016 Proofing Toolkit. You see, language packs are for the UI – the menus and all that – whereas if you are only interested in spell check and all that stuff what you need is the proofing tools. (In retrospect, the screenshot above says so – “dictionaries, grammar checking, and sorting” – but I didn’t notice that initially).

So first step, download the last ISO in the list below (Proofing Tools; 64-bit if that’s your case).

Extract it somewhere. It will have a bunch of files like this:

The proofkit.ww folder is your friend. Within that you will find folders for various languages. You can see this doc for a list of language identifiers and languages. In the root of that folder is a config.xml file with the following –

By default this file does nothing. Everything’s commented out as you can see. If you want to additional languages, you modify the config.xml first and then pass it to setup.exe via a command like setup /config \path\to\this\config.xml. The setup command is the setup.exe in the folder itself.

Here’s my config.xml file which enables two languages and disables everything else.

Step 2 would be to copy the setup.exe, setup.dll, proofkit.ww, and proofmui.en-us to your ConfigMgr content store to a folder of its own. It’s important to copy proofmui-en.us too. I had missed that initially and was getting “The language of this installation package is not supported by your system” errors when deploying. After that you’d make a new application which will run a command like setup.exe /config \path\to\this\config.xml. I am not going into the details of that. These two blog posts are excellent references: this & this.

At this point I was confused again, though. Everything I read about the proofing kit made it sound like a one time deal – as in you install all the languages you want, and you are done. What I couldn’t understand was how would I go about adding/ removing languages incrementally? What I mean is say I modified this file to add Spanish and Portugese as languages, and I deploy the application again … since all machines already have the proofing kit package installed, and it’s product code is already present in the detection methods, wouldn’t the deployment silently ignore?

To see why this doesn’t make sense to me, here are the typical instructions (based on above blog posts):

• Copy to content store
• Modify config.xml with the languages you are interested in
• Create a new ConfigMgr application. While creating you go for the MSI method and point it to the proofkit.ww\proofkitww.msi file. This will fill the MSI detection code etc. in ConfigMgr.
• After that edit the application you created, modify the content location to remove the proofkit.ww part (because we are now going to run setup.exe from the folder above it), and modify the installation program in the Programs tab to be setup.exe /config proofkit.ww\config.xml.

Notice how the uninstall program and detection method both have the MSI code of the MSI we targeted initially. So what do I do if I modify the config.xml file later and want to re-deploy the application? Since it will detect the MSI code of the previous deployment it won’t run at all; all I can do is uninstall the previous installation first and then re-install – but that’s going to interrupt users, right?

Speaking to my colleagues it seems the general approach is to include all languages you want upfront itself, then add some custom detection methods so you don’t depend on the MSI code above, and push out new languages if needed by creating new applications. I couldn’t find mention of something like this when I Googled (probably coz I wasn’t asking the right questions), so here goes what I did based on what I understood from others.

As before, create the application so we are at the screenshot stage above. As it stands the application will install and will detect that it has installed correctly if it finds the MSI product code. What I need to do is add something extra to this so I can re-deploy the application and it will notice that inspite of the MSI being installed it needs to re-install. First I played around with adding a batch file as a second deployment type after the MSI deployment type, having it add a registry registry. Something like this:

This adds a key called OfficeProofingKit2016 with value 1. Whenever I change my languages I can update the version to kick a new install. I added this as a detection to the batch file detection type, and made the MSI deployment type a dependency of it. The idea being that when I change languages and update the batch file and detection method with a new version, it will trigger a re-run of the batch file which will in turn cause the MSI deployment type to be re-run.

That turned out to be a dead end coz 1) I am not entirely clear how multiple deployment types work and 2) I don’t think whatever logic I had in my head was correct anyways. When the MSI deployment type re-runs wouldn’t it see the product is already installed and just silently continue?! I dunno.

Fast forward. I took a bath, cleared my head, and started looking for ways in which I could just do both installation and tattooing in the same batch file. I didn’t want to go with batch files as they are outdated (plus there’s the thing with UNC paths etc). I didn’t want to do VBScript as that’s even more outdated :p and what I really should be doing is some PowerShell scripting to be really cool and do this like a pro. Which led me to the PowerShell App Deployment Toolkit (PSADT). Oh. My. God. Wow! What a thing.

The website’s a bit sparse on documentation but that’s coz you got to do download the toolkit and look at the Word doc in there and examples. Plus a bit of Googling to get you started with what others are doing. But boy, is PSADT something! Once you download the PSADT zip file and extract its contents there’s a toolkit folder with the following:

This folder is what you would copy over to the content store of whatever application you want to install. And into the “files” folder of this is where you’d copy all the application deployment stuff – the things you’d previously have copied into the content store.  You can install/ uninstall by invoking the Deploy-Application.ps1 file or you can simple run the Deploy-Application.exe file.

Notice I changed the deployment type to a script instead of MSI, as it previously was. The only program I have in that is the Deploy-Application.exe

And I changed the detection method to be the registry key I am interested in with the value I want.

That’s all. Now for the fun stuff, which is in the Deploy-Application.ps1 file.

At first glance that file looks complicated. That’s because there’s a lot of stuff in it, including comments and variables etc., but what we really need to concerting ourselves with is certain sections. That’s where you set some variables plus do things like install applications (via MSI or directly running an exe like I am doing here), do some post install stuff (which is what I wanted to do, the point for this whole exercise!), uninstall stuff etc. In fact, this is all I had to add to the file for my stuff:

That’s it! :) That takes care of running setup.exe with the config.xml file as an argument. Tattooing the registry. Informing users. And even undoing these changes when I want to uninstall.

I found the Word document that came with PSADT and this cheatsheet very handy to get me started.

Update: Forgot to mention. All the above steps only install the languages on user machines. To actually enable it you have to use GPOs. Additionally, if  you want to change keyboard layouts post-install that’s done via registry key. You can add it to PSADT deployment itself. The registry key is HKEY_CURRENT_USER\Keyboard Layout\Preload. Here’s a list of values.

## Enabling disabled Office add-ins automatically

So as I mentioned yesterday I have been thinking of using Task Scheduler to try and enable disabled Office add-ins automatically.

## The Problem

Here’s what happens. Every so often when users open Word, Outlook, Excel, etc they get a prompt like the one below:

We don’t know why they keep getting it, but ideally users should be clicking “NO” as we use all these add-ins and don’t want them disabled. But users being users they click “YES” intentionally or inadvertently and then call IT with complaints that their Word, Outlook, etc aren’t working as expected. Then we in IT have to do the boring task of going to their add-ins screen and enabling these items; followed by closing and opening Word, Outlook, whatever.

What I want to do here is (1) warn users when the above dialog box comes up, advising them not to click the “YES” button; and (2) if they do click “YES” then somehow enable the add-ins behind their back and get them to close and open the affected program.

I started off thinking I might need to do some fancy stuff to enable add-ins, but soon realized that they are all controlled by the registry. Nice!

• Add-ins can be installed for all users on the machine or just a specific user. So you have to look under both HKLM and HKCU. The two locations are: HKCU\Software\Microsoft\Office\(application)\Addins\ and HKLM\Software\Microsoft\Office\(application)\Addins\ (replace (application) with Word, Outlook, Excel, or PowerPoint). These two locations contain keys for each add-in installed for that particular application.Here’s a screen shot for the Outlook InterAction add-in for a user.
• The key thing in the registry keys above is the LoadBehavior entry. This can take many values – the default is a value of 3 which means the add-in is loaded automatically at startup and is currently loaded. If the value is 2 it means the add-in is loaded automatically at startup but is currently not loaded.
• My initial hunch was that LoadBehavior is what I must target. I thought when a user disables an add-in the LoadBehavior value of that add-in probably changes to 2, so all I need to do is switch it back to 3. But I was wrong (as I quickly figured after crashing Word a couple of times and choosing to disable add-ins).
• Then I discovered that add-ins which are disabled via a user dialog box as above don’t have their LoadBehavior value changed; rather they are set as disabled at another place in the registry. And that is under the HKCU hive, at HKCU\Software\Microsoft\Office\(version)\(application)\Resiliency\DisabledItems (replace (version) with 15.0 for Office 2013, 14.0 for Office 2010, 12.0 for Office 2007, 11.0 for Office 2003, you get the idea … and replace (application) with Word, Outlook, etc as before).

Each time an add-in is disabled, a REG_BINARY entry is created under HKCU\Software\Microsoft\Office\(version)\(application)\Resiliency\DisabledItems with a binary value. I didn’t experiment to see if there’s a one-to-one mapping between this entry and an add-in, and also whether the entry is same for an add-in across all machines; the important finding for me was that if I delete this entry, it enables the add-in. So all I really needed to do to see if there are disabled add-ins for a program is to just check this key, and if there are any entries I can delete them all to re-enable all the add-ins. Nice! This doesn’t require a PowerShell script really. Good old reg can do the trick too. So a batch file is more than sufficient.

Below is what I came up with:

I could probably make it shorter if I pick up more batch file scripting but this does the trick for me.

Let’s break it down for Outlook. I enumerate the registry key. The results of this are iterated over by a FOR loop. If the list isn’t empty – i.e. there are disabled add-ins – the loop exits and goes to a different section.

This section that the loop exits to simply deletes all entries under that key, shows a message to the user asking them to close and open Outlook, and goes up the batch file to check Word next.

Repeat and rinse for each application and there you have it! Like I said, easy peasy, quick and dirty!

Maybe I should improve the script later – I don’t know. An overhaul using PowerShell might be a good idea I think. Specifically, there are a few things I am already thinking of adding:

1. Currently the message box goes away if the user clicks OK. Would be nice if I could keep an eye out for whether they actually close the program later, and if not keep popping up reminders – maybe a ballon tip?
2. Would be nice if I could close the application for the user. I could do that in the batch file too via taskkill but I was wary of doing that lest it cause any corruptions. I wouldn’t want Outlook OST and PST files or Word templates getting corrupted because I closed the program. Maybe PowerShell has a more graceful way of shutting down an app? I don’t think so, but that could be my ignorance.
3. Currently I enable all add-ins. While that’s fine for our case maybe I should have a list of add-ins that are to be excluded from being enabled? Or only enable a whitelist of add-ins?

So that’s that. Next step is to find a way to trigger the batch file.

## Scheduled task triggers and Event Viewer

Each time the dialog box asking a user to disable an add-in appears, an entry is logged in Event Viewer. This looked like a promising way to hook on to that event and warn the user not to click “YES”. These entries are logged under “Application and Services Logs” > “Microsoft Office Alerts”.

The joy of discovering that was short lived though, as I realized the same sort of alerts are generated for many other Office related things: spell check notifications, connectivity to Exchange, etc.

All these alerts had the same source and ID and there was nothing for me to distinguish between them! Sure the data part was different, and while Event Viewer (and thus Task Scheduler) supports XPath for searching the Event Logs it has limitations in that I can’t do wildcard searches. Thus while I could do an XPath search for all events that have the exact error message in the first Event Log entry above, I can’t do an XPath search for all events that contain the text “Do you want to disable this add-in?”. This is a big limitation because now I will have to (a) find the exact message for each add-in and program, and (b) create XPath queries for each of these – eugh! That’s too much work for now (and not very elegant either!) so I decided to not pursue that route.

Once a user decides to enable or disable an add-in though, I found a different alert is generated for that. Under the “Application” log, from source “Microsoft Office 14” (since we have Office 2010), alerts with event ID 2001 are generated each time a user selects to disable an add-in (and alerts with event ID 2000 are generated when they choose not to disable).

That’s convenient, coz now I can create a task that is triggered on such events and whose action is to run the previous batch file. Nice!

## Putting it all together

End result is a task I can import as in the case of the laptop lid issue. Here’s the XML file of the task:

Once again, I install it for the users I want via a batch file like this:

## Not done yet!

I am not done yet though. It’s not practical installing it like this for each user in my domain. I chose the above approach just to get it installed for a few test users; next step is to roll it out via GPO to the whole domain. Stay tuned for a post on that later …!