I’ve been sitting on this for a little while, partly due to getting confirmation I wasn’t doing anything unsupported, partly because I haven’t had time and partly a couple of other reasons I won’t go in to!
The good news is I have finally found the time to write it up and I really hope that you find this of use, and I really hope it may be able to enchant some of you Full Infrastructure types over to the world of ConfigMgr for delivering your virtual applications, I also hope this will ease the experience for those that have already embraced the ConfigMgr way of life J
For those that do use ConfigMgr, you will probably be familiar with the problem; you may have even already used the SDK to achieve exactly what I am about to outline. But first of all a summary of the problem:
The problem is that a Virtual Application package has no concept of a program, at least not as far as the console goes. This is because all virtual application packages in ConfigMgr effectively have the same program. Using the GUID of the virtual application package, ConfigMgr publishes the file type associations and shortcuts to the client and then adds the package to the App-V Cache using SFTMIME. This behaviour is the same for every virtual application package, whether it’s a whole suite; made up of multiple applications like Office or if it’s a simple little utility with one application in the package.
One potentially appealing side effect of this removal of user notification is that the ConfigMgr client does not go through the user notification countdown, by default five minutes, instead the program will execute as soon as the policy dictates.
Unfortunately, because we are unable to access the programs of a Virtual Application Package through the console, we are unable to disable this notification on an individual basis. The only option the console affords is to use the site wide setting on the “Advertised Programs Client Agent” and disable program notification for all advertisements, both standard and virtual.
Now this, whilst being a valid option in theory, is not something most customers want to implement, because in an environment where standard software distribution, patching and or Operating System Deployment is being used alongside virtual application delivery this may cause more pain than good if users aren’t notified about upcoming installs and even worse reboots!
Now preventing reboots are one of the many reasons I’ve seen customers move to virtual applications, because it means that a new application can be deployed to a user without inconveniencing them in the middle of the working day. With traditional software distribution this becomes a trade-off between the user getting the new application in order to use it to work and not interrupting the working day.
But with virtual applications, if we don’t ever need to reboot and we want to avoid bothering the user with notifications; wouldn’t it be great if we could disable user notification, but only for virtual apps?!
Another manifestation of not being able to alter notification behaviour on virtual applications is the deployment time, especially in a hot-desking environment. By default the countdown is 5 minutes, you can change this on the advertisement, but the lowest you can change this setting to is 1 minute. So if a user logs on to a new machine, they will be prompted for each new application, or alternatively, wait for each countdown to reach zero and for the advertisement to fire. Either way waiting a minute for each app or clicking through notifications won’t make for the happiest of users!
So to the solution then!
As I mentioned there is no concept of a program in a virtual application package, as far as the console is concerned. If we dig a bit deeper, into the WMI of the server hosting my SMS PROVIDER we can see that the console is shielding the admin from the reality.
As you can see at the bottom of the list of instances there are 2 programs each with the ProgramName of [VirtualApplication] this is the default, hidden program within a virtual application I mentioned earlier. You will also see that each [Virtual Application] belongs to a different package (in this case Visio Viewer and the ConfigMgr SDK, from which I am working) and if we have a look at the data within those instances, we will see that they are pretty much identical, aside from the GUID and package ID!
There is nothing that stands out as the toggle switch for enabling and disabling notification, but according to the SDK documentation on TechNet ProgramFlags is the property of the SMS_ProgramClass that we need to interest ourselves with. Annoyingly, this a) doesn’t make much sense when looking at the value b) is responsible for a whole lot more than the notification settings. However, helpfully the property is well documented here: http://msdn.microsoft.com/en-us/library/cc144361.aspx and if we amend the value by 0x00000400 then we change the notification behaviour.
As you can see from the screenshot above, my virtual applications all get created with the ProgramFlags attribute set to 135307273 and within that is the HEX value to turn on notification. So if we subtract the value of 1024, which is 400 in HEX, then we turn off the notification. And to do so, we need to bring together a few more components from the SDK!
Using http://msdn.microsoft.com/en-us/library/cc145284.aspx connect to the site provider
Using http://msdn.microsoft.com/en-us/library/cc145701.aspx get the instance of the package and program from the SMS_Program Class
As per http://msdn.microsoft.com/en-us/library/cc144361.aspx setting the program flag to 1024 (Hex 400) less than its current value to set the flag to not display a countdown.
Use http://msdn.microsoft.com/en-us/library/cc145701.aspx to save the value in the Server WMI.
And below is my rough and ready example that simply sets the value to be 1024 less than the default value. This script is purely an example and is intended as a starting point to help the creation of a much more polished one. If for no other reason it would be rather time -consuming to run the script for each Virtual Application Package in your environment, updating the static values as you go.
Using this code I was able to reduce the deployment time of three Virtual Applications from over 3 minutes to just 9 seconds simply by removing the user prompting!
<codesnippet> Dim connection Dim computer Dim userName Dim userPassword Dim password 'Password object Dim prog 'On Error Resume Next computer = "svr-sccm" userName = "" userPassword = "" Set connection = Connect(computer,userName,userPassword) If Err.Number<>0 Then Wscript.Echo "Call to connect failed" End If Call SNIPPETMETHODNAME (connection, prog) Sub SNIPPETMETHODNAME(connection, prog) ' Get the specific advertisement instance to modify. Set prog = connection.Get("SMS_Program.PackageID='" & "CEN00065" & "'" & ",ProgramName='" & "[Virtual application]" & "'") ' Set the new property value. prog.ProgramFlags = "135308297" ' 135307273 = notification on, 135308297= notification off ' Save the program. prog.Put_ End Sub Function Connect(server, userName, userPassword) On Error Resume Next Dim net Dim localConnection Dim swbemLocator Dim swbemServices Dim providerLoc Dim location Set swbemLocator = CreateObject("WbemScripting.SWbemLocator") swbemLocator.Security_.AuthenticationLevel = 6 'Packet Privacy ' If the server is local, don't supply credentials. Set net = CreateObject("WScript.NetWork") If UCase(net.ComputerName) = UCase(server) Then localConnection = true userName = "" userPassword = "" server = "." End If ' Connect to the server. Set swbemServices= swbemLocator.ConnectServer _ (server, "root\sms",userName,userPassword) If Err.Number<>0 Then Wscript.Echo "Couldn't connect: " + Err.Description Connect = null Exit Function End If ' Determine where the provider is and connect. Set providerLoc = swbemServices.InstancesOf("SMS_ProviderLocation") For Each location In providerLoc If location.ProviderForLocalSite = True Then Set swbemServices = swbemLocator.ConnectServer _ (location.Machine, "root\sms\site_" + _ location.SiteCode,userName,userPassword) If Err.Number<>0 Then Wscript.Echo "Couldn't connect:" + Err.Description Connect = Null Exit Function End If Set Connect = swbemServices Exit Function End If Next Set Connect = null ' Failed to connect. End Function </codesnippet>
This post was contributed by Rob York, a Premier Field Engineer with Microsoft Premier Field Engineering, UK.