The struggle is real, how we solved our AppV Outlook VSTO Add-in errors from a plugin.

Microsoft AppV 5 have been around the block for a long time and is still widely used by us and many organizations as the preferred virtual application delivery format, while we are waiting for MSIX to mature enough for us and developers to fully adapt to it.

Our AppV strategy also applies to the way we deploy MS Office plug-ins in our company, we always strive to deliver them virtually if possible. Most of the time Office Add-ins work right out of the box by creating the AppV package with the “Add-on or Plug-in” choice in the Sequencer, as a pre requirement our main Office version must also first be installed locally on the Sequencing VM image.

We standardize on the volume licensed version of Office 2019, but some users also have Microsoft 365 (formerly known as Office 365), both versions use C2R technology, and it seem to be much the same in terms of deployment to machines and Add-in integrations.

 

 

AppV and Office Add-ins have been working well since we found a list of passthrough paths on the Microsoft AppV forum years ago, and by changing load behavior to always load the plugins and forcing that with GPOs (not really AppV related). See some helpful tips from another Office Add-in troubleshooting guide.

But that was until we received a new Outlook Add-in called “Elements Drop” Add-in.

At first glimpse this Add-in simple, just a few files and Office registry keys that hooks it into Outlook. This enables the end-users to transfer selected emails into the vendor web system by dragging and dropping them from Outlook directly into Chrome or Edge browser.

As always, we tried a smoke test by installing the program on a standard imaged VM running Office 2019 our default AppV connection group (called “CG_Office”) and runvirtal keys, hooking it into our static “CG_Office_dummy“ AppV package so we do not have to change runvirtual GUIDS every time we change packages in this CG.

This did not work very well, starting Outlook would just throw an error message and the plugin was getting disabled in Outlook

 

Navn:

Fra: file:///C:/Program Files (x86)/Elements/Drop/Elements.DropOutlookAddin.vsto

 

************** Unntakstekst **************

System.Runtime.InteropServices.COMException (0x8007001F): En enhet koblet til systemet virker ikke. (Exception from HRESULT: 0x8007001F)

   ved System.Deployment.Internal.Isolation.IsolationInterop.GetUserStore(UInt32 Flags, IntPtr hToken, Guid& riid)

   ved System.Deployment.Internal.Isolation.IsolationInterop.GetUserStore()

   ved System.Deployment.Application.ComponentStore..ctor(ComponentStoreType storeType, SubscriptionStore subStore)

   ved System.Deployment.Application.SubscriptionStore..ctor(String deployPath, String tempPath, ComponentStoreType storeType)

   ved System.Deployment.Application.SubscriptionStore.get_CurrentUser()

   ved System.Deployment.Application.DeploymentManager..ctor(Uri deploymentSource, Boolean isUpdate, Boolean isConfirmed, DownloadOptions downloadOptions, AsyncOperation optionalAsyncOp)

   ved System.Deployment.Application.InPlaceHostingManager..ctor(Uri deploymentManifest, Boolean launchInHostProcess)

   ved Microsoft.VisualStudio.Tools.Applications.Deployment.IPHMProxy..ctor(Uri uri)

   ved Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.get_Proxy()

   ved Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.GetManifests(TimeSpan timeout)

   ved Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.InstallAddIn()

 

Unloading “CG_Office” from the computer and rerunning the MSI installer again without any virtual packages worked, so there was clearly something fishy going on when used together with AppV.

Googling this error message was a dead end, and at first we were fooled into thinking that the error message could come from errors in our plugin path syntax.

 

Now it was time to bring in the big guns and do some traces with Procmon.

After some traces I found that the native MSI install created a random named folder under the directory “%localappdata%\Apps\2.0” where Clickonce applications get installed every time we installed the plugin.

This folder was not being created in the AppV package, so we tried to just open the old package and creating it in there as a quick fix, but that did not work either.

So back to the drawing board, several google searches, and we finally found most of the answers in this 9 years old blog by Remko Weijnen.
The blogpost was discussing how to capture Clickonce applications, and it seems like this VSTO plugin for Outlook uses the same Clickonce installer technology. And most of it did apply in terms of where the folders were getting the random name string from.

It is named from the following user registry key:

HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0ComponentStore_RandomString” Type: “REG_SZ” Data: “Random string”

 

Using the AppV package together with Office 2019 our machine won’t create the ClickOnce application cache if it does not already exist, and the Add-in would just fail.

But if we deployed the same AppV package to a machine with Microsoft 365 Office everything was working as intended out of the box.

Our next failed attempt was just deleting the “%localappdata%\Apps\2.0\” folder and registry key on the target Office 2019 machine when it existed and replacing it with a fixed folder name and fixed regkey we took from the sequencer machine deployed with a simple script inside the AppV package running inside the CG_Office every time we had a VirtualEnvironment startup.

At first that seemed to work ok during our first testing, and we were starting to deploy this solution to a few users, but sadly we discovered that we had another critical ClickOnce web application in use. That application was started from an URL inside another program. When ElementsDrop was deployed using our script that application would fail because it created double random named folders inside the “%localappdata%\apps\2.0” folder and changing the registry key. This other application is critical, so the problem had to be solved fast by removing the directory “%localappdata%\Apps\2.0” on the affected machines as a workaround and removing this package with an older one without the Add-in.

Next up we decided to try and isolate the random named folder and registry key inside our AppV package.

This seemed to work as intended if the folder “%localappdata%\assembly“ existed on the target machine before starting Outlook.exe, so we scripted that into the package.

But this resulted in a new download of the earlier critical ClickOnce application every time it was started, filling up the disk with lots of junk, so, this was not a great solution.

Also, when using this solution, Outlook was writing data into “%localappdata%\Microsoft\AppV\Client\VFS\BFAC0614-B8DF-CC47-B081-52919A0C30C6\Local AppData\Apps\2.0". So, we had to remove the assembly folder from inside the VE of our Office CG if Outlook had been started before the assembly folder had been created locally, and then create it into the local filesystem. This PowerShell script is a simple one, just remember to change the VFS\GUID\ to the one you have on your own machines.

if (Test-Path "$env:LOCALAPPDATA\Microsoft\AppV\Client\VFS\BFAC0614-B8DF-CC47-B081-52919A0C30C6\Local AppData\assembly\") {Remove-Item "$env:LOCALAPPDATA\Microsoft\AppV\Client\VFS\BFAC0614-B8DF-CC47-B081-52919A0C30C6\Local AppData\assembly\" -Recurse -Force -EA 0}

 

if (!(Test-Path "$env:LOCALAPPDATA\assembly\")) { New-Item "$env:LOCALAPPDATA\assembly\" -Itemtype directory -Force -EA 0}

 

 

 

How we got this resolved:

In our last and successful package attempt I decided to use KISS, and I removed the SideBySide regkey from the package.

Just remove:

HKEY_CURRENT_USER\Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0

 

 And then I let native Windows sort out the random string with a passtrough path by going to the regkey:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AppV\Subsystem\VirtualRegistry

The I just add the following string Inside the passthrough path.

HKEY_CURRENT_USER\SOFTWARE\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0

 

Next, I removed all traces of the “%LOCALAPPDATA%” folder and subfolders.

So now Windows would just fix the folders and naming by itself.

 

So, to make sure this always worked I scripted a check if the SideBySide keys existed in the HKCU path described over, I also decided to add the check and removal of the virtual Assembly folder if another plugin should ever make it’s way into that folder.

function Get-ScriptDirectory {

       [OutputType([string])]

       param ()

       if ($null -ne $hostinvocation) {

             Split-Path $hostinvocation.MyCommand.path

       } else {

             Split-Path $script:MyInvocation.MyCommand.Path

       }

}

[string]$ScriptDirectory = Get-ScriptDirectory

$regkey = "HKCU:\\Software\Classes\Software\Microsoft\Windows\CurrentVersion\Deployment\SideBySide\2.0"

$name = "ComponentStore_RandomString"

$regfile = $ScriptDirectory + "\SideBySide.reg"

$args = "/s " + $ScriptDirectory

[bool]$exists = Test-Path -Path $regkey

if ($exists) {

       if (!((Get-ItemProperty $regkey).PSObject.Properties.Name -contains $name)) {

             $exists = $false

       }

}

if (!$exists) {

 

       Start-Process -filepath "$env:WINDIR\system32\reg.exe" -Argumentlist @("import", "$regfile") -WindowStyle Hidden

}

 

if (Test-Path "$env:LOCALAPPDATA\Microsoft\AppV\Client\VFS\BFAC0614-B8DF-CC47-B081-52919A0C30C6\Local AppData\assembly\") {Remove-Item "$env:LOCALAPPDATA\Microsoft\AppV\Client\VFS\BFAC0614-B8DF-CC47-B081-52919A0C30C6\Local AppData\assembly\" -Recurse -Force -EA 0}

 

if (!(Test-Path "$env:LOCALAPPDATA\assembly\")) { New-Item "$env:LOCALAPPDATA\assembly\" -Itemtype directory -Force -EA 0}

 

 

 

 

 

I compiled this PowerShell script into an signed .EXE file that runs under the “UserStartVirtualEnvironment” event. This way we won’t bother our users with scripts flickering over the screen every time it is started.

 

 

Hope this may come handy for others out there 😊

1 comment:

  1. If you also want to make the connectiongroup into a dynamic variable you can use the following ps script: #$a = ((Get-AppvClientConnectionGroup -name 'Cg_office' ).GroupId.Guid);$b = "$env:localappdata\Microsoft\AppV\Client\VFS\$a\folder\";if (Test-Path $b) {Remove-Item $b -Recurse -Force -EA 0}

    ReplyDelete