App-V 5 Package Conversion from App-V 4 to App-V 5

I’ve been converting a bunch of apps recently from App-V 4.6 format to App-V 5.1 format. I knew this could be done using PowerShell cmdlets, so rather than reinvent the wheel I used a great script written by Tim Mangan to do this for me. The problem I had was that our App-V 4.6 packages all had a specific naming convention that included the characters ‘AV46’…..or worse….didn’t have a consistent naming convention whatsoever! So it meant that when these packages were converted to App-V 5.1 they either still contained the characters ‘AV46’ (which looked stupid in my App-V 5.1 console) or were named inconsistently. To resolve this I needed to rename the App-V 4.6 package before converting to App-V 5.1.

Since the ConvertFrom-AppvLegacyPackage cmdlet doesn’t expose a way of naming the ‘output’ package, and I didn’t want to open and re-save each of my converted App-V 5.1 packages to merely change the package name, the only option I saw was to rename the App-V 4.6 package before I converted it! So that’s exactly what this script does!

Why is it written in VBScript and not PowerShell? Simply so we can drag a package folder onto the .vbs file and rename it. Otherwise to do the same for PowerShell would require hacking around in the registry.

App-V 5 Package Conversion from App-V 4 to App-V 5

Consider you have a folder containing the following App-V 4.6 package:

App-V 4.6 package

First you should grab the script below, and save it as (for example) RenameAV46.vbs.

You would then simply drag the parent package folder (Gateway_WinDip_2.2_32_AV46_R01) on to RenameAV46.vbs. It will then prompt you for a new package name, where you would specify the new package name (for example) ‘Gateway_WinDip_2.2_32_AV51_R01’ or similar.

The script renames the minimal amount required to prepare your App-V 4.6 package for App-V 5.1 conversion. For example, it will not rename the icons folder and re-point the OSD shortcut icons since this is not required for the conversion process to be successful.

Once you have renamed the package, it is then ready to run through Tim’s conversion script!

Option Explicit
Dim objFSO : Set objFSO = createobject("Scripting.FilesystemObject")
Dim objXMLDoc : Set objXMLDoc = CreateObject("Microsoft.XMLDOM") 
objXMLDoc.async = False 
Dim objXMLDoc2 : Set objXMLDoc2 = CreateObject("Microsoft.XMLDOM") 
objXMLDoc2.async = False 
Dim folderPath : folderPath = wscript.arguments(0)
Dim oldPackageName : oldPackageName = ""
Dim currentFilePath : currentFilePath = ""
Dim currentFileName : currentFileName = ""
Dim currentParentFilePath : currentParentFilePath = ""
Dim currentFileExtension: currentFileExtension = ""
Dim newFilePath : newFilePath = ""
Dim newFileName : newFileName = ""
Dim existingPATH : existingPATH = ""
Dim newPATH : newPATH = ""
Dim existingHREF : existingHREF = ""
Dim newHREF : newHREF = ""
Dim existingNAME : existingNAME = ""
Dim newNAME : newNAME = ""
Dim newPackage : newPackage = ""
Dim parentFolderPath : parentFolderPath = objFSO.GetParentFolderName(folderPath)
Const ForReading = 1
Const ForWriting = 2		
Public Function DecodeXml(TextToDecode)
'Take text that has been encoded for XML and change it to normal text
Dim Res
Res = Replace(Replace(Replace(Replace(TextToDecode, "&quot;", """"), "&gt;", ">"), "&lt;", "<"), "&amp;", "&")
DecodeXml = Res
End Function
Public Function EncodeXml(TextToEncode)
'Take text and change special chars so that it can be included in an XML file
Dim Res
Res = Replace(Replace(Replace(Replace(TextToEncode, "&", "&amp;"), ">", "&gt;"), "<", "&lt;"), """", "&quot;")
EncodeXml = Res
End Function
Function GetNewFilePath(existingFilePath, oldPackageName, newPackageName)	
'get new file name based on old file name, stripping out any version ("_!","_£" etc)	
Dim RegX : Set RegX = new RegExp
RegX.Pattern = "(" & oldPackageName & ")(_\d+)*"
RegX.Global = True
GetNewFilePath = RegX.Replace(existingFilePath, newPackageName)	
End Function
Sub RenameFile(currentFilePath, newFilePath)
If (currentFilePath <> newFilePath) Then
objFSO.MoveFile currentFilePath, newFilePath
currentFilePath = newFilePath		
End if			
End Sub
Dim newPackageName : newPackageName = InputBox("Enter new package name")
If (trim(newPackageName) = "") Then
MsgBox "The package name was blank - please populate.  Quitting."
wscript.quit
End If
Dim newPackagePath : newPackagePath = parentFolderPath & "\" & newPackageName
'rename package folder with new name
objFSO.MoveFolder folderPath, newPackagePath
Dim newPackagePathFolder : Set newPackagePathFolder = objFSO.GetFolder(newPackagePath)
Dim nodetext,folder,file
'get SPRJ (project) name
For Each file In newPackagePathFolder.Files
Select Case UCase(objFSO.GetExtensionName(file.Path))
Case "SPRJ"
oldPackageName = objFSO.GetBaseName(file.Path)
Exit For
End Select
Next
'iterate though package files
For Each file In newPackagePathFolder.Files
currentFilePath = file.Path
'We need to be careful of the encoding in the DEFAULTOSD element
Select Case UCase(objFSO.GetExtensionName(currentFilePath))
Case "MSI","XML"				
'just rename these file types
newFilePath = GetNewFilePath(currentFilePath, oldPackageName, newPackageName)	
RenameFile currentFilePath, newFilePath	
Case "SPRJ"		
objXMLDoc.load(currentFilePath)
If 0 <> objXMLDoc.ParseError Then
msgbox "SPRJ " & objXMLDoc.ParseError.Reason & " " & currentFilePath
Else		
'change PACKAGEFILE
Dim PackageFile : Set PackageFile = objXMLDoc.selectSingleNode(".//SEQUENCERPROJECT/PACKAGEFILE")
If Not PackageFile Is Nothing Then	  
existingPATH = PackageFile.getAttribute("Path")		
'we rename the SFT in here instead of in the SELECT...CASE statement in case there are multiple SFTs (messy package folder)
newFilePath = GetNewFilePath(newPackagePathFolder & "\" & existingPATH, oldPackageName, newPackageName)
RenameFile newPackagePathFolder & "\" & existingPATH, newFilePath				
newPATH = GetNewFilePath(existingPATH, oldPackageName, newPackageName)	
PackageFile.setAttribute "Path",newPATH
objXMLDoc.Save(currentFilePath)	
Else
Msgbox "cannot find PACKAGEFILE node"
end if
Set PackageFile = Nothing				
'the DEFAULTOSD node is actually encoded XML, so here we read it all in so we can parse the XML DOM and update CODEBASE HREF and PACKAGE NAME
Dim DefaultOSDNode : Set DefaultOSDNode = objXMLDoc.selectSingleNode(".//SEQUENCERPROJECT/DEFAULTOSD")
If Not DefaultOSDNode Is Nothing Then
'remember that the DEFAULTOSD node contains XML itself, so we re-load the contents into the XML parser
nodetext = DefaultOSDNode.text
objXMLDoc2.loadXML(nodetext)
If 0 <> objXMLDoc2.ParseError Then
msgbox "DEFAULTOSD CODEBASE " & objXMLDoc2.ParseError.Reason
Else
Dim CodebaseNode : Set CodebaseNode = objXMLDoc2.selectSingleNode(".//SOFTPKG/IMPLEMENTATION/CODEBASE")
If Not CodebaseNode Is Nothing Then	  
existingHREF = CodebaseNode.getAttribute("HREF")
newHREF = GetNewFilePath(existingHREF, oldPackageName, newPackageName)				
CodebaseNode.setAttribute "HREF",newHREF							
Else
Msgbox "cannot find CODEBASE node"
end if
Set CodebaseNode = Nothing	
Dim PackageNode : Set PackageNode = objXMLDoc2.selectSingleNode(".//SOFTPKG/PACKAGE")
If Not PackageNode Is Nothing Then
PackageNode.setAttribute "NAME",newPackageName							
Else
Msgbox "cannot find PACKAGE node"
end if
Set PackageNode = Nothing			
End If			
'set new value for DEFAULTOSD contents
DefaultOSDNode.text = objXMLDoc2.selectSingleNode(".//SOFTPKG/").xml
objXMLDoc.Save(currentFilePath)	
Else
Msgbox "cannot find DEFAULTOSD node"
End If					
Set DefaultOSDNode = Nothing	
End If	
newFilePath = GetNewFilePath(currentFilePath, oldPackageName, newPackageName)	
RenameFile currentFilePath, newFilePath
Case "OSD"
objXMLDoc.load(currentFilePath)
If 0 <> objXMLDoc.ParseError Then
msgbox "OSD " & objXMLDoc.ParseError.Reason & " " & currentFilePath
Else		
Set CodebaseNode = objXMLDoc.selectSingleNode(".//SOFTPKG/IMPLEMENTATION/CODEBASE")
If Not CodebaseNode Is Nothing Then	   
existingHREF = CodebaseNode.getAttribute("HREF")
newHREF = GetNewFilePath(existingHREF, oldPackageName, newPackageName)				
CodebaseNode.setAttribute "HREF",newHREF
objXMLDoc.Save(currentFilePath)	
Else
Msgbox "cannot find CODEBASE node"
end if
Set CodebaseNode = Nothing				
End If			
End Select	
Next
MsgBox "Done"
Set objXMLDoc = Nothing
Set objFSO = Nothing