Kae Travis

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

 

 

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

Leave a Reply