Upgrading and deploying AppV 5.0 client via SCCM 2012

If you want to deploy AppV 5.0 packages, a client is needed. In this article I will describe all the steps that are needed to install the latest AppV 5.0 client. When writing this article it is AppV 5.0 SP3 with hotfix 2.

This version is not available as a ‘complete’ version. First you will have to install AppV 5.0 SP3 client, followed by the hotfix. Fortunately you can ‘merge’ this 2 versions in one installer.

The technique

If you extract the AppV 5.0 SP3 installer, you will find 2 MSI files: one for 86 bits and one for 64 bits operating systems. These versions will be patched with the hotfix.

Step 1:: download the software

Download the AppV 5.0 SP3 (MDOP 2014 R2)

You can download MDOP 2014 R2 – which includes AppV 5.0 SP3 – from the Microsoft Volume Licensing Service Center.

Download AppV 5.0 SP3 hotfix 2

You can download Hotfix Package 2 for Microsoft Application Virtualization 5.0 Service Pack 3.
Once completed all the required steps, save the file 484280_intl_x64_zip.exe in the folder C:\AppV50SP3.

Step 2: extract the software

Extract the main installer

  1. Create the folder C:\AppV50SP3
  2. Copy appv_client_setup.exe to C:\AppV50SP3
  3. Extract the content via the command:
    C:\AppV50SP3\appv_client_setup.exe /layout C:\AppV50SP3
    
  4. There are 2 additionals MSI files in C:\AppV50SP3: for each platform one MSI installer.

Extract the hotfix 2

  1. Dubbleclick on C:\AppV50SP3\484280_intl_x64_zip.exe and extract to C:\AppV50SP3

    Extract the hotfix.

    Extract the hotfix.

  2. Extract the patches with the command:
    C:\AppV50SP3\AppV5.0SP3_Client_KB3060458.exe /layout C:\AppV50SP3
    

Create the patched MSI file for both x86 and x64 operating systems

This is done via an old technique: create an administrative installation point and patch that administrative installation point with the patch.

  1. Create an administrative installation point for the x86 bits client:
    msiexec /a "C:\AppV50SP3\appv_client_MSI_x86.msi" TARGETDIR=c:\AppV50SP3HF2_aip_x86
    

    The MSI (x86) after administrative install

    The MSI (x86) after administrative install.

  2. Create an administrative installation point for the x64 bits client:
    msiexec /a "C:\AppV50SP3\appv_client_MSI_x64.msi" TARGETDIR=c:\AppV50SP3HF2_aip_x64
    

    The MSI (x64) after administrative install.

    The MSI (x64) after administrative install.

  3. Patch the msi in the administrative installation point with the patch for the x86 bits client:
    msiexec /a "C:\AppV50SP3HF2_aip_x86\appv_client_MSI_x86.msi" /p "C:\AppV50SP3\appv_client_kb3060458_x86.msp"
    

    The MSI (x86) after patching the administrative install.

    The MSI (x86) after patching the administrative install.

  4. Patch the msi in the administrative installation point with the patch for the x64 bits client:
    msiexec /a "C:\AppV50SP3HF2_aip_x64\appv_client_MSI_x64.msi" /p "C:\AppV50SP3\appv_client_kb3060458_x64.msp"
    

    The MSI (x64) after patching the administrative install.

    The MSI (x64) after patching the administrative install.

  5. An overview of the commands:

    Summary of all the commands.

    Summary of all the commands.

Step 3: implement in SCCM 2012

Place the installation files on the software library

  1. Copy the content from C:\AppV50SP3HF2_aip_x86 to the share with all the packages: \\demo-sccm\SCCMPackages\All Applications\Microsoft_AppVClient_5.0SP3HF2_ENG_W7_1.0.0\x86

    Copy the installation files (x86) to the software library.

    Copy the installation files (x86) to the software library.

  2. Copy the content from C:\AppV50SP3HF2_aip_x64 to the share with all the packages: \\demo-sccm\SCCMPackages\All Applications\Microsoft_AppVClient_5.0SP3HF2_ENG_W7_1.0.0\x64

    Copy the installation files (x64) to the software library.

    Copy the installation files (x64) to the software library.

Create the software package

Create the SCCM 2012 applications as per screen prints below. The installation command line should at least contain ACCEPTEULA=1. I always add ENABLEPACKAGESCRIPTS=1 so you can add virtualized Click 2 Run packages later.Then there is no need to set this via GPO later.

Upg After creating the application and deployment types.

Upg After creating the application and deployment types.

Installation program (x86).

Installation program (x86).

Detection rule (x86)

Detection rule (x86)

Requirements (x86).

Requirements (x86).

Dependencies (x86).

Dependencies (x86).

Installation program (x64).

Installation program (x64).

Detection rule (x64).

Detection rule (x64).

Requirements (x64).

Requirements (x64).

Dependencies (x64).

Dependencies (x64).

Deployment of the application.

Deployment of the application.

The deployment collection.

The deployment collection.

The deployment is set as required.

The deployment is set as required.

Ignore the maintenance window for installations.

Ignore the maintenance window for installations.

Confirmation.

Confirmation.

Deploy the software and check on the client

Force the computers in the collection to download the computer policies.

Force the computers in the collection to download the computer policies.

The policy is applied on the client.

The policy is applied on the client.

And the new AppV client is installed.

And the new AppV client is installed.

The new client version.

The new client version.

The deep dive: more info about the upgrade

For whatever reason, Microsoft has decided not to change the ProductCode property. Thus all the AppV 5.0 SP3 packages share the same ProductCode.

If you open C:\AppV50SP3\appv_client_MSI_x86.msi and apply C:\AppV50SP3\appv_client_kb3060458_x86.msp you will see that only the ProductVersion is updated:

The patch does only update the ProductVersion (x86).

The patch does only update the ProductVersion (x86).

Although:

The PATCHNEWPACKAGECODE property is ignored (x86).

The PATCHNEWPACKAGECODE property is ignored (x86).

So if you want to update the AppV50SP3 client to AppV50SP3 with HF2 then you can do 2 thinks:

  • Uninstall the old AppV50SP3 client and install the new AppV50SP3HF2 client.
  • Apply only the patch. I have not tested this scenario.



Load all AppV 5.0 packages into the AppV Cache

After the migration from SCCM 2007 to SCCM 2012 some users had an issue with accessing their AppV 5.0 packages: the virtual package could not be found in the ccmcache. That was true, as the package had not been used before the SCCM 2007 to SCCM 2012 migration and after the migration the ccmcache was deleted. So the only solution was to mount all AppV 5.0 packages. That will download the virtual package from the ccmcache into the AppV 5.0 cache.

To do this, I created a vbscript that is run just before the SCCM 2007 to SCCM 2012 migration task sequence.

' ================================================================================================
' Mount all AppV packages
' Created by Willem-Jan Vroom
' Version history:
'
' 0.0.1
'    Initial version
'
' 
' ================================================================================================

' ------------------------------------------------------------------------------------------------
' Declare the most variables. 
' ------------------------------------------------------------------------------------------------

  Option Explicit

  Dim objShell                          : set objShell                      = WScript.CreateObject("WScript.Shell")
  Dim objLogFileFSO                     : Set objLogFileFSO                 = CreateObject("Scripting.FileSystemObject")
  Dim objFSO                            : Set objFSO                        = CreateObject("Scripting.FileSystemObject")
  Dim objProcessEnv                     : Set objProcessEnv                 = objShell.Environment("PROCESS")
  Dim objWMIService                     : Set objWMIService                 = GetObject("winmgmts:\\.\root\cimv2")
  Dim fn_objWMIService                  : Set fn_objWMIService              = GetObject("winmgmts:\\.\root\cimv2")
  Dim objReg                            : Set objReg                        = GetObject("winmgmts:\\.\root\default:StdRegProv")
  Dim objLogFile
  Dim CurrentDir                        : CurrentDir                        = Left(Wscript.ScriptFullname, InstrRev(Wscript.ScriptFullname, "\"))
                                          CurrentDir                        = Left(CurrentDir,len(CurrentDir)-1)
  Dim strcomputerName                   : strcomputerName                   = objProcessEnv("COMPUTERNAME")
  Dim strLogLocation                    : strLogLocation                    = "C:\WINDOWS\system32\Logfiles"
  Dim strOutputFile                     : strOutputFile                     = strLogLocation & "\" & strcomputerName & "_Mount_All_AppV_Packages_" & Replace(FormatDateTime(Now(), 2),"/","-") & ".log"
  Dim strArchitecture                   : strArchitecture                   = ""
  Dim strCurrentUser                    : strCurrentUser                    = ""
  Dim strCurrentUserSID                 : strCurrentUserSID                 = "" 
  Dim strOS                             : strOS                             = ""
  Dim strCommand                        : strCommand                        = ""
  Dim strLine                           : strLine                           = ""
  Dim strQuery                          : strQuery                          = ""
  Dim strCommonDesktop                  : strCommonDesktop                  = ""
  Dim strArray                          : strArray                          = ""  
  Dim strAppDataFolder                  : strAppDataFolder                  = ""
  Dim strProcess                        : strProcess                        = ""
  Dim strLanguage                       : strLanguage                       = ""
  Dim strInstallLanguage                : strInstallLanguage                = ""
  Dim strDetectUserUILanguage           : strDetectUserUILanguage           = ""
  Dim strValue                          : strValue                          = ""
  Dim strKeyPath                        : strKeyPath                        = ""
  Dim strValueName                      : strValueName                      = ""
  Dim dwValue                           : dwValue                           = 0

  Dim arrFileNamesToKill                : arrFileNamesToKill                = Array("doesnotexists.exe")
  Dim objFileNameToKill

  Dim arrArguments
  Dim arrLanguage
  Dim strDNSDomain                      : strDNSDomain                      = CreateObject("ADSystemInfo").DomainShortName
  Dim valCounter
  Dim valResult 
  Dim valReturnCode

  Dim colProcess, objProcess 
  Dim valOSBuildNumber
  Dim objSubfolder
  Dim colItems, objItem, Subfolder
  Dim colSoftware, objSoftware
  Dim arrValues


  Const ForWriting           = 2
  Const ForReading           = 1
  Const ForAppending         = 8
  Const OverWriteFiles       = True
  const HKEY_CURRENT_USER    = &H80000001
  const HKEY_LOCAL_MACHINE   = &H80000002
  Const HKEY_USERS           = &H80000003 

' ------------------------------------------------------------------------------------------------
' Create the log location (if not exists)
' Open the logfile.  
' ------------------------------------------------------------------------------------------------

  CreateFolderStructure(strLogLocation)
  OpenLogFile()
  WriteToLog "- ACTION: script started."
  WriteToLog " "

' ------------------------------------------------------------------------------------------------
' Detect the current OS.  
' ------------------------------------------------------------------------------------------------

  Set colItems = objWMIService.ExecQuery("Select Caption,BuildNumber from Win32_OperatingSystem")
  For Each objItem in colItems
      strOS            = objItem.Caption
      valOSBuildNumber = objItem.BuildNumber
  next

' ------------------------------------------------------------------------------------------------
' Find the currently logged on userid.
' And translate it to the users SID.
' ------------------------------------------------------------------------------------------------

  Set colProcess = objWMIService.ExecQuery("Select * from Win32_Process where Name = 'explorer.exe'")
  For Each objProcess in colProcess
      valReturnCode = objProcess.GetOwner(strCurrentUser)
      if valReturnCode <> 0 Then strCurrentUser = "Unable to find the username!"
  Next

  strCurrentUser = Ucase(strDNSDomain) & "\" & strCurrentUser

  strCurrentUserSID = GetSIDFromUser(strCurrentUser)

' ------------------------------------------------------------------------------------------------
' Detect the current processor architecture.  
' ------------------------------------------------------------------------------------------------

  if objFSO.FolderExists(objShell.ExpandEnvironmentStrings("%windir%") & "\SysWOW64\Config") then  
     strArchitecture = "x64"
       else
     strArchitecture = "x86"
  end if

' ------------------------------------------------------------------------------------------------
' Detect the current User Interface MUI.  
' ------------------------------------------------------------------------------------------------

  strDetectUserUILanguage = DetectUserUILanguage

  strInstallLanguage = DetectUserUILanguage


  WriteToLog("########## Details regarding operating system and logged on user     ##########")
  WriteToLog("Found Operating System:       " & strOS)
  WriteToLog("Found architecture:           " & strArchitecture)
  WriteToLog("Logged on userid:             " & strCurrentUser)
  WriteToLog("Logged on user SID:           " & strCurrentUserSID)
  WriteToLog("User MUI Language:            " & DetectUserUILanguage)
  WriteToLog("########## End details regarding operating system and logged on user ##########")
  WriteToLog(" ")

  WriteToLog("########## Mount all AppV 5.0 packages into the AppV Cache and       ##########")

' ------------------------------------------------------------------------------------------------
' Start the installation
' ------------------------------------------------------------------------------------------------ 

  EnablePackageScriptsViaRegistry

  strCommand = "powershell -ExecutionPolicy Bypass import-module 'C:\Program Files\Microsoft Application Virtualization\Client\AppvClient\AppvClient.psd1'; Mount-AppvClientPackage -Name * -verbose"
  WriteToLog("Running command: " & strCommand)
  valReturnCode = objShell.Run(strCommand,6,True)
  WriteToLog("Result: " & valReturnCode)

  WriteToLog("########## End Mounting all AppV 5.0 packages.                       ##########")
  WriteToLog(" ")
  CloseLogFile()
  wscript.quit 0


Sub OpenLogFile() 

' ------------------------------------------------------------------------------------------------
' Subroutine: OpenLogFile() 
' The name of the logfile is mentinoed in the variabele strOutputFile.
' ------------------------------------------------------------------------------------------------

  If objLogFileFSO.FileExists(strOutputFile) Then
     Set objLogFile = objLogFileFSO.OpenTextFile(strOutputFile, ForWriting)
         Else
     Set objLogFile = objLogFileFSO.CreateTextFile(strOutputFile)
  End If

End Sub

Sub CloseLogFile()

' ------------------------------------------------------------------------------------------------
' Subroutine: CloseLogFile()
' Close the log file.
' ------------------------------------------------------------------------------------------------

  WriteToLog "- ACTION: script ended."
  objLogFile.Close
  Set objLogfileFSO = Nothing

End Sub

Function WriteToLog(sLogMessage)

' ------------------------------------------------------------------------------------------------
' Function: WriteToLog(sLogMessage)
' Writes an entry 'sLogMessage' in the logfile.
' ------------------------------------------------------------------------------------------------

  if instr(sLogMessage, "- ACTION: ") = 0 then sLogMessage = "          " & sLogMessage
  objLogFile.WriteLine("Time: " & now & "  " & sLogMessage)

End Function

Function GetSIDFromUser(UserName)

' ------------------------------------------------------------------------------------------------
' Function: GetSIDFromUser(UserName)
' Gets the SID from the give username.
' We use the registry to avoid an empty result if run under the SYSTEM account.
' ------------------------------------------------------------------------------------------------

  Dim DomainName, Result, WMIUser

  If InStr(UserName, "\") > 0 Then
    DomainName = Mid(UserName, 1, InStr(UserName, "\") - 1)
    UserName = Mid(UserName, InStr(UserName, "\") + 1)
  Else
    DomainName = CreateObject("WScript.Network").UserDomain
  End If

  On Error Resume Next
  Set WMIUser = GetObject("winmgmts:{impersonationlevel=impersonate}!" _
    & "/root/cimv2:Win32_UserAccount.Domain='" & DomainName & "'" _
    & ",Name='" & UserName & "'")
  If Err.Number = 0 Then
    Result = WMIUser.SID
  Else
    Result = ""
  End If
  On Error GoTo 0

  GetSIDFromUser = Result

End Function

Sub CreateFolderStructure(strFolderNameToBeCreated)

' ------------------------------------------------------------------------------------------------
' Subroutine: CreateFolderStructure(strFolderNameToBeCreated)
' Creates the map as mentioned in strFolderNameToBeCreated.
' ------------------------------------------------------------------------------------------------

  Dim arrFoldersTMP : arrFoldersTMP = split (strFolderNameToBeCreated,"\")
  Dim strFolder  : strFolder  = ""
  Dim objFolderTMP
 
  For Each objFolderTMP in arrFoldersTMP
      strFolder = strFolder & objFolderTMP
      If NOT objFSO.FolderExists(strFolder) Then
             objFSO.CreateFolder(strFolder)
      end If
      strFolder = strFolder & "\"
  Next
 
End Sub

Function DetectUserUILanguage

' ------------------------------------------------------------------------------------------------
' Function: DetectUserUILanguage
' Detects the User Interface Language 
' Modified by Willem-Jan Vroom d.d 12 Feb 14: also detects Czech, Finnish, Hungarian, Polish,
' Russian, Slovak, Slovian and Turkish languages on Windows 7.
' ------------------------------------------------------------------------------------------------
  
  if instr(lcase(strOS),"windows xp") > 0 then
     strKeyPath               = strCurrentUserSID & "\Control Panel\Desktop"
     strValueName             = "MultiUILanguageId"
     strLanguage              = "eng"
     objReg.GetStringvalue HKEY_USERS,strKeyPath,strValueName,strValue
     if NOT IsEmpty(strValue) Then
        strValue = UCase(right(strValue,4))
        if strValue = "040C" then strLanguage = "fra"
        if strValue = "0410" then strLanguage = "ita"
        if strValue = "0407" then strLanguage = "ger"
        if strValue = "040A" then strLanguage = "spa"
        if strValue = "0C0A" then strLanguage = "spa"
     end if
      else
     strKeyPath               = strCurrentUserSID & "\Control Panel\Desktop"
     strValueName             = "PreferredUILanguages"
     strLanguage              = "eng"
     objReg.GetMultiStringValue HKEY_USERS,strKeyPath,strValueName,arrValues
     if not IsNull(arrValues) Then
        strValue=arrValues(0)
        if NOT IsEmpty(strValue) then
           strValue = lcase(left(strValue,2))
           if strValue = "fr" then strLanguage = "fra"
           if strValue = "it" then strLanguage = "ita"
           if strValue = "de" then strLanguage = "ger"
           if strValue = "es" then strLanguage = "spa"
           if strValue = "cs" then strLanguage = "cze"
           if strValue = "fi" then strLanguage = "fin"
           if strValue = "hu" then strLanguage = "hun"
           if strValue = "pl" then strLanguage = "pol"
           if strValue = "ru" then strLanguage = "rus"
           if strValue = "sk" then strLanguage = "sky"
           if strValue = "sl" then strLanguage = "slv"
           if strValue = "sv" then strLanguage = "swe"
           if strValue = "tr" then strLanguage = "tur"
        end if
     end if
     if strLanguage = "eng" then
        strKeyPath               = ".DEFAULT\Control Panel\Desktop\MuiCached"
        strValueName             = "MachinePreferredUILanguages"
        objReg.GetMultiStringValue HKEY_USERS,strKeyPath,strValueName,arrValues
        if not IsNull(arrValues) Then
           strValue=arrValues(0)
           if NOT IsEmpty(strValue) then
              strValue = lcase(left(strValue,2))
              if strValue = "fr" then strLanguage = "fra"
              if strValue = "it" then strLanguage = "ita"
              if strValue = "de" then strLanguage = "ger"
              if strValue = "es" then strLanguage = "spa"
              if strValue = "cs" then strLanguage = "cze"
              if strValue = "fi" then strLanguage = "fin"
              if strValue = "hu" then strLanguage = "hun"
              if strValue = "pl" then strLanguage = "pol"
              if strValue = "ru" then strLanguage = "rus"
              if strValue = "sk" then strLanguage = "sky"
              if strValue = "sl" then strLanguage = "slv"
              if strValue = "sv" then strLanguage = "swe"
              if strValue = "tr" then strLanguage = "tur"
           end if
        end if
     end if     
  end if

  DetectUserUILanguage = strLanguage
End Function

Function fnKillProcess(strProcessName)

' ------------------------------------------------------------------------------------------------
' Function: fnKillProcess(strProcessName)
' Terminates the given processname.
' ------------------------------------------------------------------------------------------------

  Set colProcess = fn_objWMIService.ExecQuery ("Select * From Win32_Process")
  For Each objProcess In colProcess
    If Instr(LCase(objProcess.Name),LCase(strProcessName)) > 0 Then
       objShell.Run "TASKKILL /F /T /IM " & objProcess.Name, 0, False
       objProcess.Terminate()
       WriteToLog("Terminating application: " & objProcess.Name)
    End If
  Next

End Function

Function fnCheckIsMSIInstalled(strMSIName)

  ' -----------------------------------------------------------------------------------------------------------------
  ' Function: fnCheckIsMSIInstalled(strMSIName)
  ' Checks if the MSI given in strMSIName has been installed.
  ' strMSIName = "\\server\share\path\to\install.msi"
  ' This script is based on the example in 
  ' http://www.pcreview.co.uk/forums/getting-property-info-via-vbscript-text-file-t1544137.html
  ' -----------------------------------------------------------------------------------------------------------------

  Dim fn_objFSO    : Set fn_objFSO = CreateObject("Scripting.FileSystemObject")
  Dim fn_objWI     : Set fn_objWI  = CreateObject("WindowsInstaller.Installer")
 
  Dim fn_objReg    : Set fn_objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
  Dim strKeyPath   : strKeyPath    = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
  Dim strValueName : strValueName  = "InstallDate"

  ' -----------------------------------------------------------------------------------------------------------------
  ' check if the file exists and that the given file is a MSI
  ' -----------------------------------------------------------------------------------------------------------------

  If NOT fn_objFSO.FileExists(strMSIName) then
     ' --------------------------------------------------------------------------------------------------------------
     ' Leave the function and clean up the mess.
     ' --------------------------------------------------------------------------------------------------------------
     fnCheckIsMSIInstalled = False
     Set fn_objFSO     = Nothing
     Set fn_objWI      = Nothing
     Set fn_objReg     = Nothing
     Exit Function
  End If
  If lcase(right(strMSIName,3)) <> "msi" then
     ' --------------------------------------------------------------------------------------------------------------
     ' Leave the function and clean up the mess.
     ' --------------------------------------------------------------------------------------------------------------
     fnCheckIsMSIInstalled = False
     Set fn_objFSO     = Nothing
     Set fn_objWI      = Nothing
     Set fn_objReg     = Nothing
     Exit Function
  End If

  ' -----------------------------------------------------------------------------------------------------------------
  ' Find the property 'ProductCode' in the given MSI
  ' -----------------------------------------------------------------------------------------------------------------

  Dim fn_objDB     : Set fn_objDB   = fn_objWI.OpenDatabase(strMSIName,2)
  Dim fn_objView   : Set fn_objView = fn_objDB.OpenView("Select `Value` From Property WHERE `Property` ='ProductCode'")
  fn_objView.Execute
  Dim fn_objRec    : Set fn_objRec  = fn_objView.Fetch
  If fn_objRec is Nothing Then
     ' --------------------------------------------------------------------------------------------------------------
     ' Leave the function and clean up the mess.
     ' --------------------------------------------------------------------------------------------------------------
     fnCheckIsMSIInstalled = False
     Set fn_objFSO     = Nothing
     Set fn_objWI      = Nothing
     Set fn_objReg     = Nothing
     Set fn_objDB      = Nothing
     Set fn_objView    = Nothing
     Set fn_objRec     = Nothing
     Exit Function
  End If
  Dim strProductCode : strProductCode = fn_objRec.StringData(1)

  ' -----------------------------------------------------------------------------------------------------------------
  ' Check that the key InstallDate in the hive HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{ProductCode} 
  ' exists
  ' -----------------------------------------------------------------------------------------------------------------

  strKeyPath = strKeyPath & strProductCode
  fn_objReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
  if IsNull(strValue) then 
     fnCheckIsMSIInstalled = False
       else
     fnCheckIsMSIInstalled = True
  end if
  
  Set fn_objFSO     = Nothing
  Set fn_objWI      = Nothing
  Set fn_objReg     = Nothing
  Set fn_objDB      = Nothing
  Set fn_objView    = Nothing
  Set fn_objRec     = Nothing
  
End Function

Function KeyExists(Key, KeyPath)

' ------------------------------------------------------------------------------------------------
' Function: KeyExists(Key, KeyPath)
' Checks to see if the 'Key' in 'KeyPath' exists.
' ------------------------------------------------------------------------------------------------

  Dim arrSubKeys
  Dim i
  Dim regReadResult : regReadResult = objReg.EnumKey(HKEY_LOCAL_MACHINE, KeyPath, arrSubKeys)
  
  	
  KeyExists = False
    
  If regReadResult = 0 And IsArray(arrSubKeys) Then
     For i = 0 To UBound(arrSubKeys)
         If InStr(arrSubKeys(i), Key) <> 0 Then
       	    KeyExists = True
    	    i = UBound(arrSubKeys)
	 End If
     Next	
  End If
    
End Function

Function ValueExists(Key, KeyPath)

' ------------------------------------------------------------------------------------------------
' Function: ValueExists(Key, KeyPath)
' Checks to see if the value 'Key' in 'KeyPath' exists.
' ------------------------------------------------------------------------------------------------

  Dim arrSubValues
  Dim i
  Dim regReadResult : regReadResult = objReg.EnumValues(HKEY_LOCAL_MACHINE, KeyPath, arrSubValues)

  	
  ValueExists = False
    
  If regReadResult = 0 And IsArray(arrSubValues) Then
     For i = 0 To UBound(arrSubValues)
         If InStr(arrSubValues(i), Key) <> 0 Then
    	    ValueExists = True
    	    i = UBound(arrSubValues)
         End If
     Next	
  End If

End Function


Sub EnablePackageScriptsViaRegistry

' ------------------------------------------------------------------------------------------------
' Set 'EnablePackageScripts' via the registry. 
' ------------------------------------------------------------------------------------------------

  WriteToLog("########## Modify 'EnablePackageScripts' via the registry.            ##########")

  strKeyPath   = "SOFTWARE\Microsoft\AppV\Client\Scripting"
  strValueName = "EnablePackageScripts"
  objReg.SetDWordValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,1
  wscript.sleep 1000
  objReg.GetDWordValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,dwValue
  WriteToLog("The key HKEY_LOCAL_MACHINE\" & strKeyPath)
  WriteToLog("   Value: " & strValueName & " has the value: " & dwValue)

  WriteToLog("########## End modifying 'EnablePackageScripts' via the registry.     ##########")

End Sub

After the




Load all AppV 4.6 packages into the AppV Cache

After the migration from SCCM 2007 to SCCM 2012 some users had an issue with accessing their AppV 4.6 packages. They received the following error:

Error message that AppV 46 cannot be found in ccmcache.

Error message that AppV 46 cannot be found in ccmcache.


What happens. During the client migration the ccmcache is cleared. So if an AppV 4.6 package has not been started before the migration, the content could not be found after starting the package after the migration.
That has been solved by creating a vbscript that is run before the SCCM 2007 client is migrated to SCCM 2012. In short: for each AppV 4.6 application the virtual package is loaded into the AppV Cache.

' ================================================================================================
' Load all the AppV 4.6 Packages again
' Created by Willem-Jan Vroom
' (c) Canon Europe B.V.
' Version history:
'
' v0.0.1:
'   Initial version
'
' v0.0.2:
'   Add functionality:
'     - Unlocks the AppV 4.6 package if it is in use
'     - For each entry a log file is created. 
' ================================================================================================

' ------------------------------------------------------------------------------------------------
' Declare the most variables. 
' ------------------------------------------------------------------------------------------------

  Option Explicit

  Dim objShell               : set objShell         = WScript.CreateObject("WScript.Shell")
  Dim objNetWork             : set objNetWork       = Wscript.CreateObject("WScript.Network")
  Dim objLogFileFSO          : Set objLogFileFSO    = CreateObject("Scripting.FileSystemObject")
  Dim objFSO                 : Set objFSO           = CreateObject("Scripting.FileSystemObject")
  Dim objProcessEnv          : Set objProcessEnv    = objShell.Environment("PROCESS")
  Dim objWMIService          : Set objWMIService    = GetObject("winmgmts:\\.\root\cimv2")
  Dim objReg                 : Set objReg           = GetObject("winmgmts:\\.\root\default:StdRegProv")
  Dim objLogFile
  Dim colListOfServices
  Dim objService                
  Dim strCurrentDir          : strCurrentDir        = Left(Wscript.ScriptFullname, InstrRev(Wscript.ScriptFullname, "\"))
                               strCurrentDir        = Left(strCurrentDir,len(strCurrentDir)-1)
  Dim strCommand             : strCommand           = ""
  Dim strLogLocation         : strLogLocation       = "C:\WINDOWS\system32\Logfiles"
  Dim strcomputerName        : strcomputerName      = objProcessEnv("COMPUTERNAME")
  Dim strOutputFile          : strOutputFile        = strLogLocation & "\" & strcomputerName & "_ReinstallAllAppV46Packages_" & Replace(FormatDateTime(Now(), 2),"/","-") & ".log"
  Dim strOS                  : strOS                = ""
  Dim strKeyPath             : strKeyPath           = ""
  Dim strArchitecture        : strArchitecture      = "x86"
  Dim strWindir              : strWinDir            = objShell.ExpandEnvironmentStrings("%WinDir%")

  Dim valOSBuildNumber, valResult
  Dim objItem, colItems
  Dim arrSubKeys, objSubKey
  Dim strProcess

  Const ForWriting           = 2
  Const ForReading           = 1
  Const ForAppending         = 8
  Const OverWriteFiles       = True
  const HKEY_CURRENT_USER    = &H80000001
  const HKEY_LOCAL_MACHINE   = &H80000002
  Const HKEY_USERS           = &H80000003 

' ------------------------------------------------------------------------------------------------
' Detect the current OS architecture.  
' ------------------------------------------------------------------------------------------------

  if objFSO.FolderExists(strWindir & "\syswow64") Then
     strArchitecture = "x64"
  end if

' ------------------------------------------------------------------------------------------------
' Create the log location (if not exists)
' Open the logfile.  
' ------------------------------------------------------------------------------------------------

  CreateFolderStructure(strLogLocation)
  OpenLogFile()
  WriteToLog "- ACTION: script started."

' ------------------------------------------------------------------------------------------------
' Detect the current OS.  
' ------------------------------------------------------------------------------------------------

  Set colItems = objWMIService.ExecQuery("Select Caption,BuildNumber from Win32_OperatingSystem")
  For Each objItem in colItems
      strOS            = objItem.Caption
      valOSBuildNumber = objItem.BuildNumber
  Next

  WriteToLog("########## Details regarding operating system and logged on user        ##########")
  WriteToLog("Found Operating System:    " & strOS)
  WriteToLog("Found OS architecture:     " & strArchitecture)
  WriteToLog("Wscript engine:            " & wscript.FullName)
  WriteToLog("########## End details regarding operating system and logged on user    ##########")
  WriteToLog(" ")

' ------------------------------------------------------------------------------------------------
' Kill all the processes that belongs to the virtual applications
' The location of the packages are:
' on x86:
'  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SoftGrid\4.5\Client\Applications
' 
' on x64:
'  HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\SoftGrid\4.5\Client\Applications
' ------------------------------------------------------------------------------------------------

  if strArchitecture = "x64" then
     strKeyPath = "SOFTWARE\Wow6432Node\Microsoft\SoftGrid\4.5\Client\Applications"
      else
     strKeyPath = "SOFTWARE\Microsoft\SoftGrid\4.5\Client\Applications"
  end if

  WriteToLog ("---------------------------------------------------------------------------------")
  WriteToLog ("Closing all applications that belongs to an AppV 4.6 package.")

  objReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys
  if IsArray(arrSubKeys) Then
     For Each objSubKey in arrSubKeys
         KillProcessFromAllvirtualPackages(strKeyPath & "\" & objSubKey)
     Next
     else 
    WriteToLog("No AppV 4.6 packages have been found.")
  end if
  WriteToLog ("---------------------------------------------------------------------------------")
  WriteToLog (" ")


' ------------------------------------------------------------------------------------------------
' Load the App-V 4.6 packages. 
' The location of the packages are:
' on x86:
'  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SoftGrid\4.5\Client\Packages
' 
' on x64:
'  HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\SoftGrid\4.5\Client\Packages
' ------------------------------------------------------------------------------------------------

  if strArchitecture = "x64" then
     strKeyPath = "SOFTWARE\Wow6432Node\Microsoft\SoftGrid\4.5\Client\Packages"
      else
     strKeyPath = "SOFTWARE\Microsoft\SoftGrid\4.5\Client\Packages"
  end if

  objReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubKeys
  if IsArray(arrSubKeys) Then
     For Each objSubKey in arrSubKeys
         LoadAppV46Package(strKeyPath & "\" & objSubKey)
     Next
     else 
    WriteToLog("No AppV 4.6 packages have been found. Thus quitting.")
  end if

  CloseLogFile()


Sub OpenLogFile() 

' ------------------------------------------------------------------------------------------------
' Subroutine: OpenLogFile() 
' The name of the logfile is mentinoed in the variabele strOutputFile.
' ------------------------------------------------------------------------------------------------

  If objLogFileFSO.FileExists(strOutputFile) Then
     Set objLogFile = objLogFileFSO.OpenTextFile(strOutputFile, ForWriting)
         Else
     Set objLogFile = objLogFileFSO.CreateTextFile(strOutputFile)
  End If

End Sub


Function WriteToLog(sLogMessage)

' ------------------------------------------------------------------------------------------------
' Function: WriteToLog(sLogMessage)
' Writes an entry 'sLogMessage' in the logfile.
' ------------------------------------------------------------------------------------------------

  if instr(sLogMessage, "- ACTION: ") = 0 then sLogMessage = "          " & sLogMessage
  objLogFile.WriteLine("Time: " & now & "  " & sLogMessage)

End Function

Sub CloseLogFile()

' ------------------------------------------------------------------------------------------------
' Subroutine: CloseLogFile()
' Close the log file.
' ------------------------------------------------------------------------------------------------
  WriteToLog("########## End repairing all the AppV Packages.                         ##########")
  WriteToLog("- ACTION: script ended.")           
  objLogFile.Close
  Set objLogfileFSO = Nothing

End Sub


Sub CreateFolderStructure(strFolderNameToBeCreated)

' ------------------------------------------------------------------------------------------------
' Subroutine: CreateFolderStructure(strFolderNameToBeCreated)
' Creates the map as mentioned in strFolderNameToBeCreated.
' ------------------------------------------------------------------------------------------------

  Dim arrFoldersTMP : arrFoldersTMP = split (strFolderNameToBeCreated,"\")
  Dim strFolder     : strFolder     = ""
  Dim objFolderTMP

  For Each objFolderTMP in arrFoldersTMP
      strFolder = strFolder & objFolderTMP
      If NOT objFSO.FolderExists(strFolder) Then
             objFSO.CreateFolder(strFolder)
      end If
      strFolder = strFolder & "\"
  Next

End Sub

Sub KillProcessFromAllvirtualPackages(key)

' ------------------------------------------------------------------------------------------------
' Subroutine: LoadAppV46Package(key)
' ------------------------------------------------------------------------------------------------

  Dim strProcessNameToKill : objReg.GetStringValue HKEY_LOCAL_MACHINE, key, "AppPath", strProcessNameToKill

  if not IsNull(strProcessNameToKill) Then

     Dim numFirstChar : numFirstChar = len(left(strProcessNameToKill, InstrRev(strProcessNameToKill, "\")))
     Dim numLastChar  : numLastChar  = len(strProcessNameToKill)

     call fnKillProcess(mid(strProcessNameToKill,numFirstChar+1,numLastChar))
  end if

End Sub



Sub LoadAppV46Package(key)

' ------------------------------------------------------------------------------------------------
' Subroutine: LoadAppV46Package(key)
' ------------------------------------------------------------------------------------------------

  Dim strSoftGridPackageName  : objReg.GetStringValue HKEY_LOCAL_MACHINE, key, "Name",        strSoftGridPackageName
  Dim strSoftGridSFTName      : objReg.GetStringValue HKEY_LOCAL_MACHINE, key, "OverrideURL", strSoftGridSFTName
  Dim strCommand


  WriteToLog ("---------------------------------------------------------------------------------")
  WriteToLog ("Processing SCCM AppV Package: " & strSoftGridPackageName & ".")

  

  strCommand = "sftmime unlock package:" & strSoftGridPackageName & " /LOG c:\windows\system32\logfiles\Unlock_AppV46Package_" & strSoftGridPackageName & ".log"
  WriteToLog ("Running command: " & ucase(strCommand))

  On Error Resume Next
  objShell.Run strCommand,6,True
  If Err.Number <> 0 Then
     WriteToLog("The following error occurred: " & Err.Description)
  end if
  On Error Goto 0
  
  On Error Resume Next
  strCommand = "sftmime unload package:" & strSoftGridPackageName & " /LOG c:\windows\system32\logfiles\Unload_AppV46Package_" & strSoftGridPackageName & ".log"
  WriteToLog ("Running command: " & ucase(strCommand))
  objShell.Run strCommand,6,True
  If Err.Number <> 0 Then
     WriteToLog("The following error occurred: " & Err.Description)
  end if
  On Error Goto 0

  On Error Resume Next
  strCommand = "sftmime load package:" & strSoftGridPackageName & " /sftpath "
  strCommand = strCommand & chr(34) & strSoftGridSFTName & chr(34) & " /LOG c:\windows\system32\logfiles\Load_AppV46Package_" & strSoftGridPackageName & ".log"
  WriteToLog ("Running command: " & ucase(strCommand))
  objShell.Run strCommand,6,True
  If Err.Number <> 0 Then
     WriteToLog("The following error occurred: " & Err.Description)
  end if
  On Error Goto 0


  On Error Goto 0

  WriteToLog ("End processing SCCM AppV Package: " & strSoftGridPackageName & ".")
  WriteToLog ("---------------------------------------------------------------------------------")
  WriteToLog (" ")
  

End Sub

Function fnKillProcess(strProcessName)

' ------------------------------------------------------------------------------------------------
' Function: fnKillProcess(strProcessName)
' Terminates the given processname.
' ------------------------------------------------------------------------------------------------

  Dim colProcess
  Dim objProcess

  Set colProcess = objWMIService.ExecQuery ("Select * From Win32_Process")
  For Each objProcess In colProcess
    If Instr(LCase(objProcess.Name),LCase(strProcessName)) > 0 Then
       objShell.Run "TASKKILL /F /T /IM " & objProcess.Name, 0, False
       objProcess.Terminate()
       WriteToLog("Terminating application: " & objProcess.Name)
    End If
  Next

End Function

Sub CheckProcess(strProcess)
' ------------------------------------------------------------------------------------------------
' Subroutine: CheckProcess(strProces)
' checks if a process is running. The subroutine is left when the process is not running
' anymore.
' ------------------------------------------------------------------------------------------------

  Dim blnProcessFound    : blnProcessFound = True
  Dim intLoopNotFound    : intLoopNotFound = 0
  Dim MINLoopCount       : MINLoopCount    = 3
  Dim objSWbemServices
  Dim colSWbemObjectSet
  Dim objSWbemObject
  Dim strCmdLine
  
  strProcess = ucase(strProcess)
  
  Do While (blnProcessFound And intLoopNotFound < 3)
    blnProcessFound = False
    WScript.Sleep 3000
    Set objSWbemServices = GetObject("winmgmts:\\.\root\cimv2")
    Set colSWbemObjectSet = objSWbemServices.InstancesOf("Win32_Process")
    For Each objSWbemObject In colSWbemObjectSet
        If (ucase(objSWbemObject.Name) = strProcess) And  (strCmdLine = "" Or strCmdLine = objSWbemObject.CommandLine) then
            blnProcessFound = true
                    intLoopNotFound = 0
        End If
    Next
    If Not blnProcessFound Then intLoopNotFound = intLoopNotFound + 1
    Set colSWbemObjectSet = Nothing
    Set objSWbemServices  = Nothing
  Loop

End Sub

Now the user can start the application without issues:

 Successfull start.

Successfull start.




Uninstall AppV 5.0 package automatically if a computer is removed from a device based collection in SCCM 2012

In my article Uninstall AppV 5.0 package automatically if an user is removed from a user based collection in SCCM 2012 I described how an application is removed if an user is removed from an user based collection.
In this article I will describe how an application is uninstalled if a computer is removed from a device based collection.

Create the computer based uninstall query

On page 30 in the document Managing AppV5 with Configuration Manager 2012SP1 it is described how a computer based uninstall collection is made.

The uninstall query.

The uninstall query.

The query is:

select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client
from
SMS_R_System inner join SMS_G_System_AppClientState on SMS_G_System_AppClientState.MachineName = SMS_R_System.Name
where 
SMS_G_System_AppClientState.ComplianceState = "1"
and 
SMS_G_System_AppClientState.AppName ="Mozilla_Firefox_24_DUT_WIN7"

Create the uninstall deployment

The application ‘Mozilla_Firefox_24_DUT_WIN7’ has both an install and uninstall deployment.

The application has both an install and uninstall deployment.

The application has both an install and uninstall deployment.




Uninstall AppV 5.0 package automatically if an user is removed from a user based collection in SCCM 2012

With SCCM 2007 you had the option to automatic uninstall virtual applications. In the package you selected ‘Remove this package from clients when it is no longer advertised’. If the user was no longer member of the collection the virtual application was removed.

SCCM 2007 Remove this package from clients when it is no longer advertised.

SCCM 2007 Remove this package from clients when it is no longer advertised.

With SCCM 2012 this feature has been discontinued.

In SCCM 2012 the trick is to create a collection that contains all the users that are no longer member of the group that belongs to the application.

In this example the application ‘Demo_MoreShortcuts_1.0_ENG – TEST’ will be removed by the users who are no longer member of the Active Directory group ‘APPL – Demo_TST’

The start position

The shortcut is visible for the user:

Application is visible in Start Menu.

Application is visible in Start Menu.

Create a query for the user based collection

Query to find the users who are no longer entitled to use this application.

Query to find the users who are no longer entitled to use this application.

The query:

select SMS_R_USER.ResourceID,SMS_R_USER.ResourceType,SMS_R_USER.Name,SMS_R_USER.UniqueUserName,SMS_R_USER.WindowsNTDomain
from 
SMS_R_User inner join SMS_G_System_AppClientState on SMS_R_USER.UniqueUserName = SMS_G_System_AppClientState.UserName
where
SMS_G_System_AppClientState.AppName = "Demo_MoreShortcuts_1.0_ENG - TEST" 
and
G_System_AppClientState.ComplianceState = 1 and SMS_R_USER.UniqueUserName not in 
(select distinct SMS_R_USER.UniqueUserName 
from 
SMS_R_User 
where
UserGroupName = "DEMOFOREST\\APPL - Demo_TST")

The most important parts are:

  1. SMS_G_System_AppClientState.AppName = “Demo_MoreShortcuts_1.0_ENG – TEST” and G_System_AppClientState.ComplianceState = 1
    Query is based on the Application Name in CM12.

    Query is based on the Application Name in CM12.


    More information can be found at SMS_G_System_AppClientState Server WMI Class
  2. SMS_R_USER.UniqueUserName not in (select distinct SMS_R_USER.UniqueUserName from SMS_R_User where UserGroupName = “DEMOFOREST\\APPL – Demo_TST”)

The query does not return any users:

The query does not give any results.

The query does not give any results.

The application has both a install and uninstall deployment attached to it.

The application has both an install and uninstall deployment.

The application has both an install and uninstall deployment.

User management

Remove the user from the group and perform all client actions on the client.

Remove the user from the group.

Remove the user from the group.

After a while the user who was member of the group is now visible in the collection:

After a while the removed user is visible in the collection.

After a while the removed user is visible in the collection.

If you install Configuration Manager Support Center on a server, you can open both the AppIntentEval.log and the AppEnforce.log. It shows as a ProhibitedApplication in the AppIntentEval.log.

The AppIntentEval log and AppEnforce log (1 of 2).

The AppIntentEval log and AppEnforce log (1 of 2).

The AppIntentEval log and AppEnforce log (2 of 2).

The AppIntentEval log and AppEnforce log (2 of 2).

The virtual application has been uninstalled.




Deployment Visio 2013 and Project 2013 as AppV 5.0 package created with Click to Run

Office 2013 – and its components – can only be made available as an App-V 5.0 package with Click to Run. The required steps – including streaming to the client with the App-V 5.0 Management Console – are described in this article.

Step 1: Download Office Deployment Tool for Click to Run

  1. Download Office Deployment Tool for Click-to-Run.
  2. Run the downloaded ‘officedeploymenttool.exe’. It will extract the setup.exe together with an example xml file.

Step 2: make the download.xml file

  1. This file contains all the settings which applications should be downloaded. More information can be found at Reference for Click-to-Run configuration.xml file.

    In this example the content is:

    
    
     
        
          
          
          
        
        
          
          
          
        
      
    
    

    [warning]Of course the share should be present.[/warning]
    In this example Visio and Project will be downloaded in English, Czech and Dutch.

  2. Create a batch file with the following content:
    "%~dp0setup.exe" /download "%~dp0download.xml"
    pause
    
  3. Run the script to download the files:
    Run 'download.cmd' as admin.

    Run ‘download.cmd’ as admin.

  4. After a while all the files are downloaded:
    All files have been downloaded.

    All files have been downloaded.

Step 3: make the package.xml files

For both Visio and Project a package xml file will be made. That is needed as Visio and Project have a different package id. That package id is defined in the property PACKAGEGUID in the packager.xml file.

  1. The file for Visio:
    
     
        
          
          
          
        
      
    
      
      
      
      
      
      
    
    
  2. The file for Project:
    
     
        
          
          
          
        
      
    
      
      
      
      
      
      
    
    
  3. The package guids can be created with this powershell command:
    Powershell command: [guid]::newguid()

    Powershell command: [guid]::newguid()

  4. Create the packager.cmd to create the packages for both Visio and Project:
    "%~dp0setup.exe" /packager "%~dp0packager_visio.xml" %~dp0AppV50Packages
    "%~dp0setup.exe" /packager "%~dp0packager_project.xml" %~dp0AppV50Packages
    pause
    
  5. Run the script to create the packages:
    07 Run packager cmd as administrator7
  6. You can view the progress:
    View progress.

    View progress.

  7. Ready:
    10 Finished
  8. If you open ‘ProjectStdRetail_cs-cz_en-us_nl-nl_x86_DeploymentConfig.xml’ there are references to the Czech language:
    11 The deployment config contains references to cz

Step 4: Modify the packages in the sequencer

If needed you can modify the packages in the sequencer. At least App-V 5.0 SP2 sequencer is needed.

In this scenario the packages are modified to change the names.

  1. Open the project .appv file with the sequencer:
    Open the project appv file with the sequencer.

    Open the project appv file with the sequencer.


    Edit package.

    Edit package.

  2. Edit:
    14 Edit
  3. The final result. [important]Please be aware that the first language that is mentioned, is ‘cs-cz’ for Czech. That is why all the shortcuts have a Czech description. I do not know if this is by design or that is a bug…
    You should expect that en-en should be default, as that language is set as the first language in the ‘packager_project.xml’ file.
    15 The results cz as mentioned first[/important]
  4. Modify both the package name and description:
    16 Modify package name and description
  5. And save the package:
    17 Save the package
    18 Check the file name
    19 Wait

Step 5: Import Visio and Project

  1. Import Project 2013 in AppV 5.0 using the Application Virtualization Console
  2. Edit the AD access:
    20 Edit AD access
  3. Unselect the applications you do not need:
    24 Unselect all the applications you do not need
  4. Publish the application
  5. And do the same for Visio (not documented)

Step 6: Test on the client

  1. Log in on a client.
  2. After a short while both Visio and Project are visible in the Start Menu:
    25 After a while the applications are available on the client
  3. Start Word:
    25 After a while the applications are available on the client
  4. You have the option to insert both a Project and Visio object in Word:
    27 Option to insert Project document
    28 Option to insert Visio drawing
  5. And work with it:
    29 Visio

Step 7: Remove Project and Visio

  • Remove the group from the application in the Application Virtualization Console.
  • It might take a longer time if the application is in use:
    30 Visio is still in use
    You see that in the event viewer.

    You see that in the event viewer.


    But Visio is removed after reboot.

    But Visio is removed after reboot.

  • If you start Word, the options for inserting a Project or Visio object are not available anymore:
    33 Options to insert Project and Visio objects are gone



  • Hotfix Package 5 for Microsoft Application Virtualization 5.0 SP2

    A couple of weeks after the release of Hotfix Package 4 for Microsoft Application Virtualization 5.0 SP2, a new hotfix pack has been released.

    More information can be found at http://support.microsoft.com/kb/2963211/en-gb.

    A summary of the changes:

    Issue 1: Connection groups cannot support both user-published and global-published packages

    App-V 5.0 SP2 does not let you create user-entitled connection groups that contain both user-published and global-published packages.
    With this hotfix release, App-V 5.0 SP2 supports creating user-entitled connection groups that contain user-published and global-published packages by using Windows PowerShell.
    [notice]Note Connection groups that contain user and global packages are currently not supported through the App-V server.[/notice]

    Issue 2: Enabling user-publishing in the Administrator context through Windows PowerShell

    This hotfix release enables user-publishing to be done in the Administrator context through PowerShell cmdlets.

    Issue 3: Deprecation of PackageStoreAccessControl support in App-V 5.0 SP2

    Effective immediately, the PackageStoreAccessControl (PSAC) setting that was introduced in App-V 5.0 SP2 is being deprecated in both single-user and multiuser environments.

    The PSAC setting has been unsupported in multiuser environments since the first hotfix package for App-V 5.0 SP2, but PSAC deployment in single-user environments was supported until now. If you deployed PSAC to single-user environments, remove the configuration option from any deployments.




    Error: The application Failed to Launch (0X0DF01625-00000534)

    When preparing the content for my article User Environment Variables in App-V 5.0 with SP1, SP2 and SP2 Hotfix 4 I got this error:

    The application Failed to Launch (0X0DF01625-00000534)

    The application Failed to Launch (0X0DF01625-00000534)


    On my search I found this solution: Error Running Scripts (5.0 SP2). The weird this is that the script worked like a charm in SP1 but in SP2 it crashes. And all the C++ 2010 runtime modules where in place.

    So I ended up adding my computer in a domain. And all the issues where solved… I really have no idea why this worked for me. Same computer, the only difference was adding it to a domain…




    User Environment Variables in App-V 5.0 with SP1, SP2 and SP2 Hotfix 4

    Dan Gough wrote an excellent article named: User Environment Variables in App-V 5 Scripts. To summarize: it is about the fact that environment variables are not shown correctly in AppV 5.0.
    However: the question is: is this still the case? Time to investigate!

    To test this, I re-used an old package: Firefox 24. It does not need any startup-scripts, but it is an ideal candidate for testing.

    I have done the following:

    1. I created a VB script with the following content:
      ' ===========================================================================
      ' Example of environment variables when running as a script.
      ' ===========================================================================
      
        Option Explicit
        
        Dim objShell             : set objShell        = CreateObject("WScript.Shell")
        Dim strText              : strText             = ""
        Dim strUserShellFolders  : strUserShellFolders = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
        Dim strShellFolders      : strShellFolders     = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
        Dim strVolatileEnv       : strVolatileEnv      = "HKCU\Volatile Environment"
        
        strText = strText & "Displaying the various variables when running scripts in AppV 5.0." & vbCrlf
        On Error Resume Next
        strText = strText & "AppV 5.0 Client version:   " & objShell.RegRead("HKLM\SOFTWARE\Microsoft\AppV\Client\Version")
        On Error Goto 0
        strText = strText & vbCrlf & vbCrlf
        
        
        ' Start with environment variables
        strText = strText & "Environment variables:" & vbCrlf
        strText = strText & " - APPDATA:       " & objShell.ExpandEnvironmentStrings("%APPDATA%") & vbCrlf
        strText = strText & " - LOCALAPPDATA:  " & objShell.ExpandEnvironmentStrings("%LOCALAPPDATA%") & vbCrlf
        strText = strText & " - USERNAME:      " & objShell.ExpandEnvironmentStrings("%USERNAME%") & vbCrlf
        strText = strText & " - USERPROFILE:   " & objShell.ExpandEnvironmentStrings("%USERPROFILE%") & vbCrlf & vbCrlf
        
        ' Use HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
        strText = strText & "Use " & strUserShellFolders & ":" & vbCrlf
        strText = strText & " - AppData:       " & objShell.RegRead(strUserShellFolders & "\Appdata") & vbCrlf
        strText = strText & " - Local AppData: " & objShell.RegRead(strUserShellFolders & "\Local Appdata") & vbCrlf
        strText = strText & " - Desktop:       " & objShell.RegRead(strUserShellFolders & "\Desktop") & vbCrlf & vbCrlf
        
        ' Use HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
        strText = strText & "Use " & strShellFolders & ":" & vbCrlf
        strText = strText & " - AppData:       " & objShell.RegRead(strShellFolders & "\Appdata") & vbCrlf
        strText = strText & " - Local AppData: " & objShell.RegRead(strShellFolders & "\Local Appdata") & vbCrlf
        strText = strText & " - Desktop:       " & objShell.RegRead(strShellFolders & "\Desktop") & vbCrlf & vbCrlf
        
        ' Use HKEY_CURRENT_USER\Volatile Environment
        strText = strText & "Use " & strVolatileEnv & ":" & vbCrlf
        strText = strText & " - APPDATA:       " & objShell.RegRead(strVolatileEnv & "\APPDATA") & vbCrlf
        strText = strText & " - LOCALAPPDATA:  " & objShell.RegRead(strVolatileEnv & "\LOCALAPPDATA") & vbCrlf
        strText = strText & " - USERNAME:      " & objShell.RegRead(strVolatileEnv & "\USERNAME") & vbCrlf
        strText = strText & " - USERPROFILE:   " & objShell.RegRead(strVolatileEnv & "\USERPROFILE") & vbCrlf
        
        msgbox strText,,"Results from environment variables"
      
    2. Modified the package by adding the file in the scripts folder:
      Add the vbscript in sequencer

      Add the vbscript in sequencer

    3. Installed AppV 5.0 with SP1 on a client
    4. Logged in with an account with standard user rights.
    5. Started PowerShell as admin and installed Firefox. Also I enabled packaging scripts:
      Powershell commands to add the package.

      Powershell commands to add the package.

    6. Started Firefox:
      The environment variables are shown incorrect,

      The environment variables are shown incorrect,

    7. Upgraded the client to SP2:
      Install the client.

      Install the client.


      Reboot the computer.

      Reboot the computer.

    8. Started Firefox:
      The environment variables are shown correctly,

      The environment variables are shown correctly,

    9. Upgraded the client to SP2 with HF4:
      Install the client.

      Install the client.


      Reboot the computer.

      Reboot the computer.

    10. Started Firefox:
      The environment variables are shown correctly,

      The environment variables are shown correctly,

    To summarize: if you want to use scripts and environment variables are needed, then use at least SP2. If you cannot upgrade the client, then use the HKCU\Volatile Environment.




    Hotfix Package 4 for Microsoft Application Virtualization 5.0 SP2

    Hotfix package 4 for AppV 5.0 with SP2 includes improvements. With this hotfix package, the Application Virtualization 5.0 SP2 contains a new sequencer setting that, when it’s applied to a virtual application package, provisions the package with write access to any files and folders in the virtual environment.

    More information can be found at KB2956985.

    Some prints:

    The biggest change in the sequencer: now it is possible to allow virtual applications full write access to the VFS.

    The biggest change in the sequencer: now it is possible to allow virtual applications full write access to the VFS.

    Help -> About.

    Help -> About.

    The version number 5.0.3400.0.

    The version number 5.0.3400.0.

    The files that are included in the hotfix. An upgrade is not supported, the old version has to be removed prior to installing the hotfix.

    The files that are included in the hotfix.