If you have been to our session called App-V standalone compared to CM12 Integrated: The Good, The Bad and The Ugly at MMS 2015 , we have showed you that some things by default cannot be done in Configmgr .
We showed a strong business case around the Application model in CM12 SP1 and using App-V 5.0 to do user-based software targeting. As most people are doing App-V integration in Configuration Manager and exploring the possibilities , they ran into some challenges I believe are critical and needs to be solved in a certain way . What the correct way is , I leave that up to the smart engineering guy’s in Redmond .
One of the great promises of application virtualization is dynamic delivery of software to end-users; however delivering plug-ins or add-ons to installed (i.e. not virtualized) software has thus far been a stumbling block. Internet Explorer has been particularly challenging due to the inability to separate the browser from the OS in a supported manner. So using App-V to deploy plug-ins like Flash or Java has meant changing the user experience with virtualization or falling back to standard install methods. Since App-V 5.0 SP2 this is very good news though, with the ability to seamlessly run an installed application inside a specified virtual environment. This means that the Flash plug-in can be delivered as a virtual package and made available to Internet Explorer without resorting to hacks or changing the user experience by providing a special shortcut.
The only requirement for specific Virtual Extensions (like the flash add-in) is that the package needs to be published Globally… only it doesn’t work great when deploying all your virtualized apps to users with System Center Configuration Manager and App-V 5.x. The table below will explain in what cases you will have to use Global publishing.
Image may be NSFW.
Clik here to view.Image may be NSFW.
Clik here to view.
We can overcome that hurdle with a sort of workaround that we are not going to explain in absolute detail as every customer has specific needs. See the steps below as a guide to think outside the box.
Workaround :
1. We are going to create a scheduled task which triggers on a eventID action 1003 from the eventlog “Microsoft-AppV-Client/Operational”
The script to create the scheduled task :
param( [Parameter(ParameterSetName='Register')] [switch]$Register, [Parameter(ParameterSetName='UnRegister')] [switch]$UnRegister ) switch($PsCmdlet.ParameterSetName){ "Register"{ $Xml = Get-Content (Join-Path $PSScriptRoot "ScheduledTaskTemplate_Publish.xml") $hReplace = @{ _Date_=(Get-Date -Format s) _Author_="Publish_User2Global_1.0_EN" _WorkingDirectory_=$PSScriptRoot } foreach($key in $hReplace.Keys) { $Xml = $Xml -creplace $key, $hReplace.$key } Register-ScheduledTask -Xml ($Xml | Out-String) -TaskName "1_user_Publish_User2Global" -TaskPath "Microsoft\AppV\Publishing" -Force | Out-Null $Xml = Get-Content (Join-Path $PSScriptRoot "ScheduledTaskTemplate_UnPublish.xml") $hReplace = @{ _Date_=(Get-Date -Format s) _Author_="UnPublish_User2Global_1.0_EN" _WorkingDirectory_=$PSScriptRoot } foreach($key in $hReplace.Keys) { $Xml = $Xml -creplace $key, $hReplace.$key } #Register-ScheduledTask -Xml ($Xml | Out-String) -TaskName "1_user_UnPublish_User2Global" -TaskPath "Microsoft\AppV\Publishing" -Force | Out-Null } "UnRegister"{ Get-ScheduledTask -TaskPath "\Microsoft\AppV\Publishing\" -TaskName "1_user_Publish_User2Global" | Unregister-ScheduledTask -Confirm:$False | Out-Null #Get-ScheduledTask -TaskPath "\Microsoft\AppV\Publishing\" -TaskName "1_user_UnPublish_User2Global" | Unregister-ScheduledTask -Confirm:$False | Out-Null } }
The script is based on the following templates :
<?xml version="1.0" encoding="UTF-16"?> <Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Date>_Date_</Date> <Author>_Author_</Author> <URI>\Microsoft\AppV\Publishing\1_user_Publish_User2Global</URI> </RegistrationInfo> <Triggers> <EventTrigger> <Enabled>true</Enabled> <Subscription><QueryList><Query Id="0" Path="Microsoft-AppV-Client/Operational"><Select Path="Microsoft-AppV-Client/Operational">*[System[Provider[@Name='Microsoft-AppV-Client'] and EventID=1003]]</Select></Query></QueryList></Subscription> <ValueQueries> <Value name="ThePackageId">Event/EventData/Data[@Name='Package']</Value> <Value name="TheVersionId">Event/EventData/Data[@Name='Version']</Value> <Value name="UserSid">Event/System/Security/@UserID</Value> </ValueQueries> </EventTrigger> </Triggers> <Principals> <Principal id="Author"> <GroupId>S-1-5-18</GroupId> <RunLevel>LeastPrivilege</RunLevel> </Principal> </Principals> <Settings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <StartWhenAvailable>false</StartWhenAvailable> <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable> <IdleSettings> <StopOnIdleEnd>true</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <AllowStartOnDemand>false</AllowStartOnDemand> <Enabled>true</Enabled> <Hidden>true</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>P3D</ExecutionTimeLimit> <Priority>7</Priority> <RestartOnFailure> <Interval>PT1M</Interval> <Count>3</Count> </RestartOnFailure> </Settings> <Actions Context="Author"> <Exec> <Command>powershell.exe</Command> <Arguments>-NonInteractive -ExecutionPolicy RemoteSigned -WindowStyle Hidden -File User2Global.ps1 -Publish -PackageId $(ThePackageId) -VersionId $(TheVersionId) -UserSid $(UserSid)</Arguments> <WorkingDirectory>_WorkingDirectory_</WorkingDirectory> </Exec> </Actions> </Task>
2. When the scheduled task is triggered by event-ID action 1003 from the eventlog “Microsoft-AppV-Client/Operational” , we kick-off the following Powershell script (see below). It will unpublished the package from the user and will publish the package globally instead.
param( [Parameter(ParameterSetName='Publish')] [switch]$Publish, [Parameter(ParameterSetName='UnPublish')] [switch]$UnPublish, [guid]$PackageId, [guid]$VersionId, [string]$UserSid ) Function New-BurntToastNotification{ <# This function will show a BurnToastNotification #> [CmdletBinding(SupportsShouldProcess = $True)] Param ( [Parameter(Mandatory=$True)] $Text, [Parameter(Mandatory=$True)] $Title ) # create toast template TO xml [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null $toastXml = ([Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastImageAndText02)).GetXml() # message to show on toast $stringElements = $toastXml.GetElementsByTagName("text") | select -First 1 $stringElements.AppendChild($toastXml.CreateTextNode($Title)) > $null $stringElements = $toastXml.GetElementsByTagName("text") | select -Last 1 $stringElements.AppendChild($toastXml.CreateTextNode($Text)) > $null # image $imageElements = $toastXml.GetElementsByTagName("image") $imageElements[0].src = "file:///" + "$PSScriptRoot\appv.png" # convert from System.Xml.XmlDocument to Windows.Data.Xml.Dom.XmlDocument $windowsXml = New-Object Windows.Data.Xml.Dom.XmlDocument $windowsXml.LoadXml($toastXml.OuterXml) # send toast notification $toast = New-Object Windows.UI.Notifications.ToastNotification ($windowsXml) [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("App-V").Show($toast) } Import-Module "$env:ProgramFiles\Microsoft Application Virtualization\Client\AppvClient\AppvClient.psd1" $package = Get-AppVClientPackage -PackageId $PackageId -VersionId $VersionId -All switch($PsCmdlet.ParameterSetName) { "Publish" { try { Unpublish-AppvClientPackage $package -UserSID $UserSid if (! $package.IsPublishedGlobally) { Publish-AppVClientPackage $package -Global New-BurntToastNotification -Text "$($package.name)`nSuccesfully Published Globally." -Title "App-V User2Global" } } catch { New-BurntToastNotification -Text "Something went wrong while Publishing: `n$($package.name)." -Title "App-V User2Global" } } "UnPublish" { try { if (($package = Get-AppVClientPackage -PackageId $PackageId -VersionId $VersionId -All).IsPublishedGlobally) { $package | stop-AppVClientPackage -Global -ErrorAction SilentlyContinue | Unpublish-AppvClientPackage -Global New-BurntToastNotification -Text "$($package.name)`nSuccesfully UnPublished Globally." -Title "App-V User2Global" } } catch { New-BurntToastNotification -Text "Something went wrong while unpublishing: `n$($package.name)." -Title "App-V User2Global" } } }
You can choose how to deploy the script. You can create an App-V bubble or simply deploy this with Configmgr or GPO ….
Disclaimer : The script are delivered AS-IS and are not the complete solution to this story. It is an example on how to think outside the box and make a potential solution that will fit your specific company issue.
Hope it Helps ,
Kenny Buntinx & Roy Essers .