Category: Deployment and Scripting

The curious case of the pinned Microsoft Edge shortcut

The curious case of the pinned Microsoft Edge shortcut

I really love the new Microsoft Edge browser! Most of all because we now have a modern browser which is supported by Microsoft in a server operating system, but also because we are now able to integrate our Microsoft Azure AD/Office 365 account with Edge, which among other things enables favorites and password sync.

UPDATE – 06-06-2020 (June 6th 2020): I did not do proper testing during my last update, rather embarrassing. This means, that you will still get a pinned taskbar Edge shortcut. It looks like Microsoft implemented a partial fix, which doesn’t pin Edge to the taskbar of the account installing Edge. Any other accounts logging in, will still get the pinned Edge shortcut on the taskbar. I uploaded a new screen recording, recorded on a non-domain joined Windows Server 2019 with the latest CU installed and using the latest version of Edge.
Solutions in this article are still valid!

UPDATE – 04-06-2020 (June 4th 2020): As of 83.0.478.44 stable Microsoft has now fixed the install/configuration process, so a pinned shortcut is no longer created. I have tested this in both Windows Server 2019 and Windows 10. However in Windows 10, if the legacy Edge browser is pinned to the taskbar before deploying the new Edge browser, it will be replaced with a shortcut to the new Edge browser.

It’s been a few months since my very first article on the Microsoft Edge browser, written during Citrix Summit 2020. As you’ll probably notice, this article is focused mainly on how to install Edge in a Citrix setup.

I have penned an additional Edge article where I focus on how to secure the browser using the Microsoft Security baseline GPO settings.

As you can see I have spent a great deal of time with Edge, and it has of course also become my first choice of internet browser. The are so many scenarios where Edge fits right in, so I also spend a great deal of time telling customers and colleagues about the fantastic use cases where Edge might provide new or better functionality or solve an issue in a Citrix VAD setup.

However as much as I like Edge, I have found that Edge is now doing stuff it shouldn’t be doing. To be specific, when launching Edge for the first time in Windows Server 2016/2019 (probably also 2012 R2) a pinned taskbar shortcut is created, for no apparent reason. It is well known that when installing Edge on an up to date Windows 10 machine, the so called “legacy Edge browser” is replaced, Microsoft published an article around the same time as the first stable release of Edge. This means that any legacy Edge browser shortcuts, are replaced with shortcuts to the new Edge app, however we do not have the legacy Edge browser in a server operating system. I have also seen that evene if I don’t have a pinned “legacy Edge” shortcut in the taskbar, a pinned shortcut to the new Edge browser i still created, not OK!

I have created a small screen recording to shown what is going on. To rule out any domain related configuration like group policy, scripts etc. I have conducted the test on a non-domain joined Windows Server 2019 with the latest cumulative update. I am of course installing the latest Microsoft Edge stable release.

Screenpresso.com does not endorse this recording or this blog, I simply forgot to register the application ūüôā

UPDATE – 06-06-2020: New screen recording uploaded showing the pinned Edge shortcut still appears with the latest Edge build v83.0.478.45

How is the pinned shortcut created?

During the installation of Edge an Active Setup registry key is created which launches a setup.exe file with a specific set of parameters.

This particular Active Setup is created during setup:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{9459C573-B17A-45AE-9F64-1857B5D58CEE}

From what I can see in Process Monitor, the setup.exe process actually doesn’t do very much, but it does create a registry value in HKCU\Software\Microsoft\Edge (even in a server OS) called TaskBarAutoPin.

The first time Edge is launched, and this value data is “1”, a pinned taskbar shortcut is created, and the value is deleted.

How to get rid of the pinned shortcut?

I started looking into the documentation a The Chromium Projects website, and I found an article describing how to create a master_preference file. I have used master_preferences before in Google Chrome and also with the earlier releases of Edge, to remove the Edge shortcut on the desktop. In the documentation a “do_not_create_taskbar_shortcut” setting is mentioned, however it only works in Windows 8 and older, which I confirmed to be true, it does not work in either Windows 10 or Windows Server 2019.

With the Edge stable version 81.0.416.32 , Microsoft introduced an MSI command line parameter the “DONOTCREATEDESKTOPSHORTCUT=TRUE” which does indeed work, it prevents the desktop shortcut from being created. Hoping that Microsoft had built in a “secret” command line parameter I had to try “DONOTCREATETASKBARSHORTCUT=TRUE”, unfortunately it did not work.

I reached out to a former colleague of mine who is now a program manager at Microsoft. We discussed this issue for quite some time, and it basically ended up with him recommending me to submit a so called Microsoft Edge User Voice where I should describe the issue. Someone had beat me to it, a User Voice for the issue had already been submitted here. Please cast your vote, we need to make Microsoft aware of this issue and hopefully make them change this unusual behavior of creating pinned taskbar shortcuts. Or at least give us a way to prevent the pinned taskbar shortcut from appearing, in both Windows Server and Windows 10.

I am a tenacious guy, so I managed to find 4 different ways to get rid of the pinned taskbar shortcut, take that Microsoft! Credit goes out to Trentent Tye, James Rankin and Nathan Sperry for providing inspiration and/Or information to a couple of the solutions described.

Solution 1:

Using one of my favorite applications, Citrix Workspace Environment Management, we are able to remove all pinned shortcuts in the taskbar during logon by simply checking a box:

This will delete the shortcut during logon, it works and it is a non-destructive way of removing the shortcut. It’s was not quite what I was looking for though, I wanted to flat out prevent the shortcut from ever appearing, this procedure also removes any other pinned shortcuts, that might not be desirable.

Solution 2:

Another favorite of mine is FSLogix. The App Masking feature in FSLogix can be used for a variety of different things, but in this particular case it can be used to hide the entire Active Setup registry key created by the Edge setup, so the setup.exe process is never even launched.

I have created a very simple hiding rule which hides the Edge Active Setup key. This procedure is non-destructive which means it doesn’t delete anything, so if something breaks you can remove the hiding rule and the Edge Active Setup key is back in business.

I have created a hiding rule via the FSLogix Rule Editor:

Create a new blank hiding rule

Provide the hiding rule with a name and click the New Rule button:

In the object name box put in the full key path to the Edge Active Setup key and specify that it is a Directory/Registry in object type and click OK.

Lastly we need to specify which users/groups this hiding rule is applied to. I have specified that Everyone should have this rule applied, but if you want to be a bit more granular in your approach, you might want to select one or more AD groups instead.
To configure the user/group assignment, right click the name of the hiding rule and select Manage Assignments:

Here you will be able to enable the Everyone group and specify other groups this rule should apply to.

Click OK. Your hiding rule is now ready.

The only thing left to do is to copy the hiding rules files to the C:\Program Files\FSLogix\Apps\Rules folder:

The Edge Active Setup key is now hidden for all users logging on to the server, hence it will not run the setup.exe process and we will not get the pinned taskbar icon, happy days!

Solution 3:

Really simple solution. Delete the Edge Active setup registry key entirely. This can of course be done manually via regedit or via PowerShell::
Remove-Item -Path “HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{9459C573-B17A-45AE-9F64-1857B5D58CEE}” -Force

This is a destructive solution, so if anything breaks, you will have to have some way back to the original state. You can incorporate this solution is a part of the Edge setup process.

Solution 4:

Also a fairly simple solution. Delete the TaskbarAutoPin value in registry. Again this can be done manually via regedit or via PowerShell:
Remove-ItemProperty -Path “HKCU:\Software\Microsoft\Edge” -Name “TaskbarAutoPin” -Force

However I will of course recommend using Citrix WEM to delete the TaskbarAutoPin value via a registry action:

Like solution 3, this is also a destructive solution, so if needed you will also have to have a way back if things go sideways.

So there you have it, leave it to a Citrix-guy to fix Microsoft’s mess. I do hope that Microsoft will provide us with a better and/or simpler solution to prevent the pinned taskbar shortcut from being created. In the meantime we now have a couple of different workarounds to remove the shortcut.

Installing FireFox

Installing FireFox

In this article I’ll show you how to install and configure FireFox in a non-persistent Session Host environment. By non-persistent I mean in a Citrix Virtual Apps and Desktop setup deployed either via Citrix Provisioning or via Citrix Machine Creation Services. However you should be able to use this guide in Microsoft RDS and VMware Horizon as well.

During my research and testing of FireFox I have of course become more familiar with the browser, and it is also currently my second choice of browser, my first choice is still Microsoft Edge. Until recently my second choice was actually Internet Explorer, but I am more and more often experiencing issue with different web sites when using IE, so it’s now down to third choice.

Unfortunately in Session Hosts, we do not have access to the Microsoft Edge, only Internet Explorer is available out of the box. Microsoft has decided that the Edge browser, among other in-box Universal Windows applications, are only available in the semi-annual releases of Windows.

For anyone caring a bit about privacy, it may also be that FireFox is becoming one of the last independent browsers out there, as Microsoft late last year announced that Edge is moving to the Chromium open source project.

This means that at some point two of the four major browsers (Edge, Google Chrome, FireFox and Internet Explorer) will be running on the Chromium core.

To get started you will need to pick a FireFox installer that suits your needs. Currently FireFox is being maintained in two tracks, the Regular Release and Extended Support Release (ESR).
The ESR edition of FireFox is not updated with new features, updates will only address security vulnerabilities. Updates to the Regular Release may contain feature additions and will also address security vulnerabilities. So going with the ESR edition, could mean less testing when the browser is updated, as any updates will not contain new features.

Mozilla has a release calendar for 2019 where you can track when a new Regular Version is released.

For this article I am using the latest ESR 64-bit edition of FireFox, which currently is version 60.5.0. You can find the latest ESR edition here:
https://www.mozilla.org/en-US/firefox/organizations/all/.

You will also need the Group Policy Administrative Templates for FireFox, they can be found at Mozillas GitHub repository here:
https//github.com/mozilla/policy-templates


Click “Clone or Download”. That triggers a download of a ZIP file which contains the ADMX and ADML files needed.

So let’s get started.

Installing FireFox manually is pretty straight forward, I will not provide an install guide here. I will instead show how to do an unattended install of FireFox.

To do an unattended install of FireFox via command line or a script, you will need an INI file, with a few options.

Here are the contents of the INI file I use:

[Install]
;The name of the directory where the application will be installed in the system's program files directory
InstallDirectoryName=Mozilla Firefox

;Create a shortcut for the application in the current user's QuickLaunch directory.
QuickLaunchShortcut=false

;Create a shortcut for the application on the desktop.
;This will create the shortcut in the All Users Desktop directory
;If that fails this will attempt to create the shortcuts in the current user's Start Menu directory.
DesktopShortcut=false

;Create shortcuts for the application in the Start Menu.
;This will create the shortcuts in the All Users Start Menu directory
;If that fails this will attempt to create the shortcuts in the current user's Start Menu directory.
StartMenuShortcuts=true

;The MozillaMaintenance service is used for silent updates and may be used for other maintenance related tasks.
;It is an optional component.
MaintenanceService=false

Additional information about the arguments can be found here:
https://wiki.mozilla.org/Installer:Command_Line_Arguments

An important thing to remember is to include the “MaintenanceService=false” in the INI file, this excludes the FireFox Maintenance Service from the install process.
According to Mozilla this service is used for silent updates and “other maintenance tasks” whatever that means. As we all know it’s usually not a good idea to do any kinds of updates or “other maintenace tasks” in a Session Host based setup, whether it’s non-persistent or not. A certain degree of application control is still needed.

To install FireFox unattended using the INI file, use the /INI=<full path to configuration INI file> install switch, like this:
“Firefox Setup 60.5.0esr.exe” /INI=”C:\Temp\FireFox-Unattend-INI.ini”

If you are using the INI file provided above, everything should go through smoothly and you should now have a shortcut to FireFox in the Start Menu only, and no Maintenance Service. To verify whether the Maintenance Service is installed or not, go the Services console. If you see a service called “Mozilla Maintenance Service”, the service is installed. You can either remove FireFox and do another install, or simply disable the service.

Now to the more exiting part, group policy. We are going to create a FireFox GPO which configures a few things that addresses general usability and a bit of security/privacy.

Import the ADMX and ADML into your Central Store, then you should be able to access the FireFox group policy settings.

As you can see, we have a few possibilities when it comes to managing the configuration of FireFox. I will not go through every single policy, I will however show you the GPO I have implemented. Just remember that some of the settings in this GPO might not apply to your environment, so read the policy descriptions, understand them, and test whatever policies you apply.

All policies are configured in User Configuration. I prefer this approach, as I am then able to do security filtering of users and/or groups, which enables users and/or groups to receive different group policy configurations.

Here I block the access to the “about:config” page. This page contains a lot of very advanced features and settings, which probably isn’t a very good idea for a regular user to be messing around with.

Other noticeable policies are “Disable System Addon Updates”, which disables the update of System Addons, again we don’t want that in a Session Host based environment. The “Disable Update”, disables the update of FireFox itself.

“Tracking Protection” is enabled, and the user cannot disable it. This provides a security/privacy feature in FireFox which blocks content, cookies or scripts from collecting your browsing data across multiple sites. I recommend enabling the feature in a Session Host based environment, as it will reduce the CPU usage of the FireFox browser dramatically and provide some basic privacy when browsing the internet. A similar feature exists in Internet Explorer, which I have mentioned in another blog post.

The “Allow add-on install from website” is disabled, which prevents the user from installing add-ons to FireFox. We want control of the FireFox application, there are all kinds of add-ons doing all kinds of different things, we don’t want that on our Session Hosts.

The last part is the “Default Search Engine”. Here I configure Google as the default search provider, have you ever met a user that wanted another search provider than Google?
I also remove some built in search providers and essentially only allow Google and DuckDuckGo in the list of search providers and prevent manual addition of other search providers.

This concludes the guide. With this information you should be able to do an unattended setup of FireFox and configure a basic lockdown GPO to deliver a good user experience and prevent users from “messing thing up” for themselves, other users on the Session Host or the Session Host server.

Citrix Published Apps migration script

Citrix Published Apps migration script

Recently I was working on a XenApp and XenDesktop 7.9 upgrade project. The customer didn’t want to touch the existing 7.9 environment, as it was a production environment with around 1000 concurrent users from different parts of the world. Instead a new XenApp and XenDesktop 7.18 site was created and we had to create everything manually in the new site.

Fortunately, besides the published application, there really wasn’t much to be done. We had to create a couple of Machine Catalogs and a few Delivery Groups. However the customer had 50+ published applications and it would take quite a while to manually create those by hand.

As it turned out, the customer couldn’t wait for me to develop this script, so I actually didn’t test it out in that specific environment. However that didn’t stop me from finishing the script, as I expect more 7.x to 7.x or 7.x to 1808 and later migration projects in the future.

As I wasn’t able to find any useful tools from Citrix to help me migrate a 7.x site to another 7.x site, I decided to write my own script, with some inspiration from some older scripts I had used earlier.

The script can be found here:

#Requires -Version 3.0
<# ********************************************************************************************************************************* Name: Migrate-XAapps Author: Kasper Johansen Company: edgemo Contact: kjo@edgemo.com Last modified by: Kasper Johansen Last modified Date: 24-09-2018 Version 1.0 .SYNOPSIS Migrates published apps between Virtual Apps and Desktops sites. .DESCRIPTION This script migrates all published apps between Virtual Apps and Desktops sites. This script has been developed using inspiration from the XD7Export and XD7Import scripts from Peter Juncker at Atea Denmark. Credit goes out to Peter Juncker for the initial scripts. The script can export published applications from a Citrix XenApp and XeneDesktop and Citrix Virtual Apps and Desktops site. The script can import published applications to a Citrix XenApp and XeneDesktop and Citrix Virtual Apps and Desktops site. The script has been testet with: Citrix XenApp and XenDesktop 7.6 LTSR CU6 Citrix XenApp and XenDesktop 7.9 Citrix Virtual Apps and Desktops 1808 The most common information (icon information, user/group access information, commandline, commandline arguments and workdir) is exported to 3 different CSV files. The names of the CSV files are hardcoded, but the path to the CSV files is customizable. The specific CSV produced when exporting are: Icons.csv: Contains the binary icon information for all published applications. This file may grow large in size depending on the amount of published applications. Apps.csv: Contains all published applications property information. This is a 1 to 1 extraction with no filtering. Users: Contains the published applications UID and any Active Direcoty User/Group information. All 3 CSV files are needed for a successfull import! .PARAMETER DesktopGroupName The name of the Delivery Group to import/export published applications. If the Delivery Group name contains spaces if must be encased in double quotes! .PARAMETER CSVInput Specifies the path the CSV files. If not specified, the default path, which is the directory from where the script is executed, is selected. This parameter is only active when using the -Import switch. .PARAMETER CSVOutput Specifies the path the CSV files. If not specified, the default path, which is the directory from where the script is executed, is selected. This parameter is only active when using the -Export switch. .SWITCH Import Enables the import of published applications to a Citrix Virtual Apps and Desktop Site .SWITCH Export Enables the Export of published applications from a Citrix Virtual Apps and Desktop Site .PARAMETER LogDir Specifies the directory to store the transcription logfile. If not specified, the default $env:SystemRoot\Temp directory is selected. .EXAMPLES Export published applications: Migrate-XAapps -DesktopGroupName "XenApp" -Export Export published applications with custom CSV output path: Migrate-XAapps -DesktopGroupName "XenApp" -CSVOutput C:\CSVOutput -Export Import published applications: Migrate-XAapps -DesktopGroupName "XenApp" -Import Import published applications with custom CSV input path: Migrate-XAapps -DesktopGroupName "XenApp" -CSVInput C:\CSVInput -Import ********************************************************************************************************************************* #>
# Function parameters
Param(
    [Parameter(Mandatory = $true)]
    [string]$DesktopGroupName,
    [Parameter(ParameterSetName = "Import")]
    [string]$CSVInput = (Split-Path -parent $MyInvocation.MyCommand.Definition),
    [Parameter(ParameterSetName = "Export")]
    [string]$CSVOutput = (Split-Path -parent $MyInvocation.MyCommand.Definition),
    [Parameter(ParameterSetName = "Import", Mandatory)]
    [switch]$Import,
    [Parameter(ParameterSetName = "Export", Mandatory)]
    [switch]$Export,
    [string]$LogDir = "$env:SystemRoot\Temp"
    )

# Add Citrix Broker Admin PowerShell snap-in
Write-Host "Adding Citrix Broker Admin PowerShell snap-in" -Verbose
Add-PSSnapin -Name Citrix.Broker.Admin.V2 -ErrorAction Stop

function Export-XAapps
    {
    param(
         $DesktopGroupName,
         $CSVOutput,
         $LogDir
        )

    # Start time measuring and transcription
    $LogPS = $LogDir + "\Export-XAapps.log"
    $startDTM = (Get-Date)
    Start-Transcript $LogPS

        # CSV path variables
        $IconsCSV = $CSVOutput + "\Icons.csv"
        $AppsCSV = $CSVOutput + "\Apps.csv"
        $UsersCSV = $CSVOutput + "\Users.csv"

        # Get DesktopGroup
        $DesktopGroup = Get-BrokerDesktopGroup -Name $DesktopGroupName
                
            If (!($DesktopGroup))
            {
                Write-Host "$DesktopGroup does not exist" -Verbose
                break
            }
            else
            {
                # Export published apps icon information
                Write-Host "Exporting published apps icon information" -Verbose
                If (Test-Path -Path $IconsCSV)
                {
                    Remove-Item -Path $IconsCSV
                }
                Get-BrokerIcon | Export-Csv $IconsCSV -Encoding "UTF8" -Verbose
                
                    # Export published apps 
                    Write-Host "Exporting published apps" -Verbose
                    If (Test-Path -Path $AppsCSV)
                    {
                        Remove-Item -Path $AppsCSV
                    }
                    Get-BrokerApplication -AssociatedDesktopGroupUID $DesktopGroup.UID | Export-Csv $AppsCSV -Encoding "UTF8" -NoTypeInformation -Verbose

                        # Export published apps groups/users
                        Write-Host "Exporting published apps groups/users access information" -Verbose
                        If (Test-Path -Path $UsersCSV)
                        {
                            Remove-Item -Path $UsersCSV
                        }
                        
                        $PublishedApps = Get-BrokerApplication -AssociatedDesktopGroupUID $DesktopGroup.UID
                        Add-Content $UsersCSV "UID,Username" -Encoding "UTF8" -Verbose
                        ForEach ($App in $PublishedApps)
                        {
                            
                            If ($App.AssociatedUserNames -gt "1")
                            {
                                $UserName = $App.AssociatedUserNames
                                ForEach ($user in $UserName)
                                {
                                    $UID = $App.UID
                                    $AppGroupUIDs = $App.AssociatedDesktopGroupUids
                                    $UserName = $user

                                    Add-Content -Path $UsersCSV "$UID,$UserName" -Encoding "UTF8"
                                }
                            }
                            else
                            {
                                $UID = $App.UID
                                $AppGroupUIDs = $App.AssociatedDesktopGroupUids
                                $UserName = $App.AssociatedUserNames
                                                        
                                Add-Content -Path $UsersCSV "$UID,$UserName" -Encoding "UTF8"
                            }
                        }
            }
                
    # End time measuring and transcription
    $EndDTM = (Get-Date)
    Write-Output "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose
    Stop-Transcript
    }

function Import-XAapps
    {
    param(
        $DesktopGroupName,
        $CSVInput,
        $LogDir
        )
    # Start time measuring and transcription
    $LogPS = $LogDir + "\Import-XAapps.log"
    $startDTM = (Get-Date)
    Start-Transcript $LogPS

        # CSV path variables
        $IconsCSV = $CSVInput + "\Icons.csv"
        $AppsCSV = $CSVInput + "\Apps.csv"
        $UsersCSV = $CSVInput + "\Users.csv"

        # Get DesktopGroup
        $DesktopGroup = Get-BrokerDesktopGroup -Name $DesktopGroupName
                
            If (!($DesktopGroup))
            {
                Write-Host "$DesktopGroup does not exist" -Verbose
                break
            }
            else
            {
                # Import published apps icon information
                import-csv -path $AppsCSV|ForEach-Object {
                    
                    $AppApplicationName = $_.ApplicationName
	                $AppApplicationType=$_.ApplicationType
	                $AppBrowserName=$_.BrowserName
	                $AppClientFolder=$_.ClientFolder
	                $AppCommandLineArguments=$_.CommandLineArguments
	                $AppCommandLineExecutable=$_.CommandLineExecutable
	                $AppCpuPriorityLevel=$_.CpuPriorityLevel
	                $AppDescription=$_.Description
	                $AppEnabled=$_.Enabled -as [bool]
	                $AppIconFromClient=$_.IconFromClient -as [bool]
	                $AppIconUid=$_.IconUid
	                $AppName=$_.Name
	                $AppPublishedName=$_.PublishedName
	                $AppSecureCmdLineArgumentsEnabled=$_.SecureCmdLineArgumentsEnabled -as [bool]
	                $AppShortcutAddedToDesktop=$_.ShortcutAddedToDesktop -as [bool]
	                $AppShortcutAddedToStartMenu=$_.ShortcutAddedToStartMenu -as [bool]
	                $AppStartMenuFolder=$_.StartMenuFolder
	                $AppUUID=$_.UUID
	                $AppUid=$_.Uid
	                $AppUserFilterEnabled=$_.UserFilterEnabled
	                $AppVisible=$_.Visible -as [bool]
	                $AppWaitForPrinterCreation=$_.WaitForPrinterCreation -as [bool]
	                $AppWorkingDirectory=$_.WorkingDirectory
                
                    # Import icon information
                    $IconData = Import-Csv $IconsCSV | Where-Object {$_.UID -eq $AppIconUid}
                    
                    # Import user/group access information
                    $UserAccess = import-csv -path $UsersCSV | Where-Object {$_.UID -eq $AppUid}

                    # Create icons
                    $IconID = New-BrokerIcon -EncodedIconData $IconData.EncodedIconData

                        If (Get-BrokerApplication | Where { $_.Name -eq $AppName })
                        {
                            Write-Host "$AppName already exists!" -Verbose
                            Write-Host
                        }
                        else
                        {
                            Write-Host "Importing $AppName" -Verbose
                            Write-Host "Importing icon for $AppName" -Verbose

                            New-BrokerApplication -Name $AppName -ApplicationType $AppApplicationType -ClientFolder $AppClientFolder -CommandLineArguments $AppCommandLineArguments -CommandLineExecutable $AppCommandLineExecutable -CpuPriorityLevel $AppCpuPriorityLevel -Description $AppDescription -DesktopGroup $DesktopGroup -Enabled $AppEnabled -IconUid $IconID.UID -Priority 0 -PublishedName $AppPublishedName -SecureCmdLineArgumentsEnabled $AppSecureCmdLineArgumentsEnabled -StartMenuFolder $AppStartMenuFolder -ShortcutAddedToDesktop $AppShortcutAddedToDesktop -ShortcutAddedToStartMenu $AppShortcutAddedToStartMenu -UserFilterEnabled $False -Visible $AppVisible -WaitForPrinterCreation $AppWaitForPrinterCreation -WorkingDirectory $AppWorkingDirectory -Verbose
                            
                            If ($AppUserFilterEnabled -eq "True")
                            {
                                Set-BrokerApplication -Name $AppName -UserFilterEnabled $True -Verbose
                                Add-BrokerApplication -Name $AppName -DesktopGroup $DesktopGroup -Verbose
                                                                    
                                    $UserAccess | ForEach-Object {
                                    Write-Host "Importing user/group access for $AppName" -Verbose
                                    Write-Host "Configuring AD Group/user:" $_.Username -Verbose
                                    Write-Host

                                        ForEach ($user in $_.Username)
                                        {
                                            Add-BrokerUser -Name $user -Application $AppName -Verbose -ErrorAction SilentlyContinue
                                        }
                                    }
                            }
                            else
                            {
                                Set-BrokerApplication -Name $AppName -UserFilterEnabled $False -Verbose
                                Add-BrokerApplication -Name $AppName -DesktopGroup $DesktopGroup -Verbose
                            }

                        }                
                }
                
            }
                
    # End time measuring and transcription
    $EndDTM = (Get-Date)
    Write-Output "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose
    Stop-Transcript
    }

function Migrate-XAapps ($DesktopGroupName,$CSVInput,$CSVOutput,$LogDir,$Import,$Export)
    {
        If ($Export)
        {
            Export-XAapps -DesktopGroupName $DesktopGroupName -CSVOutput $CSVOutput -LogDir $LogDir
        }
            If ($Import)
            {
                Import-XAapps -DesktopGroupName $DesktopGroupName -CSVInput $CSVInput -LogDir $LogDir
            }
    }

Migrate-XAapps $DesktopGroupName $CSVInput $CSVOutput $LogDir $Import $Export

Copy the code above and save it to file called Migrate-XAapps.ps1. The script contains basic information on usage and also examples of the different switches and paramaters that can be used.

Let me know if you experience any issues. As mentioned in the script, I have tested the code on XenApp and XenDesktop 7.6 LTSR CU6, XenApp and XenDesktop 7.9 and Citrix Virtual Apps and Desktops 1808 and I haven’t run into any issues, however I have probably not covered every possible published application scenario out there.

Installing Foxit Reader

Installing Foxit Reader

A few weeks ago I came across blog post by Carl Webster on a guide on how to install Adobe Acrobat Reader DC. This guide is very detailed and if you are in need of performing an unattended deployment of Adobe Acrobat Reader DC, this is probably the only guide you will need.

However there are other PDF viewers out there, better viewers in my opinion. Adobe Acrobat Reader DC, and versions before DC (11.x, 10.x, 9.x), has become bloated with features most users will never need, especially the online features are almost useless, at least from my point of view. My point of view is of course based on how the application behaves in a non-persistent and/or multi-user environment and general functionallity.

This guide I will show you how to install an alternative PDF Viewer from Foxit. With Foxit Reader you will, in my opinion, get a better performing and less bloated PDF Viewer, compared to Adobe Acrobat Reader DC and it’s just as easy, or maybe easier, to deploy and customize compared to Adobe Acrobat Reader DC.

To get started you will obviously need the Foxit Reader source files. To get those, go to the Foxit website https://www.foxitsoftware.com/

Go to the Log In box and either log in, if you have an account or create a new account. The account is needed to be able to get the Foxit Reader MSI installer, the XML Editor, the Foxit Customization Tool and the Group Policy administrative templates.

Once logged in, go to the download section and click Free Software

Here you will need the Enterprise Packaging which is either an MSI or, depending on the language selected, an ISO with an MSI.

 

Select the language needed, amount of users and make sure to select the MSI package type. As mentioned, depending on your selected language, you may not be able to select the MSI package type, only EXE or ISO is available. In that case select ISO, it will have en MSI package that we can extract and use going forward.

Once past the image verification, you will get to the actual download site. The MSI package download will automatically prompt you to save the file, if not, go ahead and download it manually.

You will need the MSI package, the XML Editor and the Foxit Customization Tool.

So, this it how it should look like, when you have all the needed components:

How to install using an MSI transforms file

Next, extract the FoxitCustomizationTool.zip file, this is used to create an MSI transforms file with pre-configured setup settings.

Fire up the Foxit Customization Tool

Go to File and click Open and select the FoxitReader93_enu_Setup.msi file

Once opened, this is where the good stuff is..

From here on, I will show you how I usually configures the transforms file. The settings shown may not reflect your needs, so consider what you select and/or deselect.

I always disable the Auto Update feature, in non-persistent setups this is recommended.

In the Features pane you can choose which features of Foxit Reader to install or not to install.

This installs the bare minimum features, which allows you to open PDF files in either the Foxit Reader application or within browser windows.

I usually remove any unwanted shortcuts, in this case the Foxit Reader desktop shortcut and the Activate Plugins Start Menu shortcut.

Now all you have to do is save the configuration to an MST file.

Go to File and click Save-As, provide a name for your new MST file and save it in the same directory as the FoxitReader93_enu_setup.msi.

You are now able to deploy Foxit Reader unattended via MDT, SCCM, Altiris, PowerShell etc. using this command line:

msiexec /I¬†FoxitReader93_enu_setup.msi /qb TRANSFORMS=”FoxitReader93_enu_Setup_FCT.mst”¬†ALLUSERS=1

How to install using command line parameters only

If you for some reason don’t want to use a transforms file, a wide range of command line parameters are available when using the MSI installer.

This command line should provide you with the same result as the transforms install method described above:

msiexec /I¬†FoxitReader93_enu_setup.msi /qb ADDLOCAL=”FX_PDFVIEWER” MAKEDEFAULT=1 VIEW_IN_BROWSER=1 DESKTOP_SHORTCUT=0 AUTO_UPDATE=0 NOTINSTALLUPDATE=1¬†ALLUSERS=1

The Foxit Reader Deployment and Configuration guide describes a few additional command line parameters. The guide can be found on the Foxit Reader download site.

This covers the deployment of the Foxit Reader. Now, we are going to look a bit closer at what’s possible with the XML Editor.

Foxit Reader UI Customization

The XML Editor is needed to customize the graphical user interface of Foxit Reader. This means that you can hide certain parts of the application that may not be relevant for your users to access. I will show a few examples here, but there are a lot of different areas of the UI in Foxit Reader that can be hidden, so it’s really just a matter of picking out the parts that suit your needs.

I’ll usually hide the Help and the Share tabs. The Help tab isn’t really providing any useful information to user and the Share tab makes it possible to integrate with Evernote, OneNote and Sharepoint which may not be available.

To make these changes to the UI you will need an XML file, which you create using the XML Editor.

Open the XML Editor, it should look like this:

Make sure to click the Interface button, and select Foxit Reader. Also in the version box, make sure to type in the correct version of Foxit Reader.

Next go to the Ribbon Set tab. In here you will see a lot of different check boxes, each representing either a feature or a tab to hide. As mentioned, I want to hide the Help and Share tabs, this is done simply by checking the corresponding boxes:

Next click Export and save the XML file:

The XML goes into the¬†C:\Program Files (x86)\Foxit Software\Foxit Reader\ProfStore folder, just overwrite the existing profstore.xml file, as it’s a default XML containing the default out-of-the box configuration.

Look at this nice and clean UI:

You can download a pre-configured sample of profstore.xml file here. Be sure to review the customizations, before production usage.

Deployment script examples

The profstore.xml should be copied as a part of the deployment process. I have provided a couple of examples on how to create either a batch script or a PowerShell script to deploy Foxit Reader and copy the profstore.xml file.

Batch/CMD:

msiexec /I¬†FoxitReader93_enu_setup.msi /qb TRANSFORMS=”FoxitReader93_enu_Setup_FCT.mst” ALLUSERS=1

copy profstore.xml “C:\Program Files (x86)\Foxit Software\Foxit Reader\ProfStore” /Y

PowerShell:

Start-Process -Wait¬†FoxitReader93_enu_setup.msi -Argumentlist “/qb¬†TRANSFORMS=`”FoxitReader93_enu_Setup_FCT.mst`” ALLUSERS=1″

Copy-Item profstore.xml -Destination “C:\Program Files (x86)\Foxit Software\Foxit Reader\ProfStore” -Force

This concludes the guide.

We are now able to get the source files to Foxit Reader and make UI custumizations and deploy it. Now, there is no excuse, start testing Foxit Reader! I am sure you’ll agrre with me that Foxit Reader can easily take on Adobe Acrobat Reader.