Create Short File Names

Description:

This script will create short file names (8.3 format) for the File table and the IniFile table of a Windows Installer.

Usage

CScript.exe {Script} {MSI}

Script

'set up log file
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

'create a name/path for log file
Dim MSIPath : Set MSIPath = fso.GetFile(WScript.Arguments(0))  
Dim logFile : logFile = Left(MSIPath.Path, InStrRev(MSIPath.Path, ".") - 1) & ".log"

Dim objLogFile : Set objLogFile = fso.OpenTextFile(logFile, ForAppending, True)

WriteLog "Creating Short Filenames"
WriteLog "Processing: " & MSIPath.Name

'create 2 constants - one for when we want to just query the MSI (read) and one for when we want to make changes (write)

Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
Const msiViewModifyReplace = 4

'create WindowsInstaller.Installer object
Dim oInstaller : Set oInstaller = CreateObject("WindowsInstaller.Installer")

'open the MSI (the first argument supplied to the vbscript)
Dim oDatabase : Set oDatabase = oInstaller.OpenDatabase(WScript.Arguments(0),msiOpenDatabaseModeTransact) 

Dim extension : extension = ""
Dim filename : filename = ""
Dim tempfilename : tempfilename = ""
Dim filenameNoExtension : filenameNoExtension = ""
Dim sfncount : sfncount = 1	'a count which increments the sfn version
Const msiViewModifyUpdate  = 2
Dim fileView, fileRecord, filenameArray, i, fnView, fnRecord, tableRecord, tableView, tableName

Dim ranhexa, ranhexb, ranhexc, ranhexd

Dim sql : sql = "SELECT * FROM _Columns WHERE Name = 'FileName'"	

Set tableView= oDatabase.OpenView(sql) 
tableView.Execute
Set tableRecord = tableView.Fetch

While Not tableRecord Is Nothing

	tableName = tableRecord.StringData(1)

	If tableName = "File" OR tableName = "IniFile" Then

		sql = "SELECT FileName FROM " & tableName	

		Set fileView= oDatabase.OpenView(sql) 
		fileView.Execute
		Set fileRecord = fileView.Fetch

		While Not fileRecord Is Nothing

			filename = fileRecord.StringData(1)
			sfncount = 1

			filenameArray = ""
			filenameNoExtension = ""

			'if the file doesnt have a sfn
			If Not InStr(filename,"|") > 0 Then

				If InStr(filename,".") > 0 Then 'if there's a period in the filename we get the filename with no extension
					filenameArray = Split(filename,".")
					For i = 0 To UBound(filenameArray) - 1
						filenameNoExtension = filenameNoExtension & filenameArray(i)				
					Next

					'return 'html', for example
					extension = filenameArray(ubound(filenameArray))		
					'return exampl~1.htm|examplefile.html 	
				Else
					filenameNoExtension = filename
					extension = ""
				End If

				If (Len(filenameNoExtension) > 8) Or (Len(filename) > 12) Or (Len(extension) > 3) Then 'it needs to be put in sfn

								'replace illegal 8.3 chars with '_'
					filenameNoExtension = Replace(filenameNoExtension," ","_")
					filenameNoExtension = Replace(filenameNoExtension,"/","_")
					filenameNoExtension = Replace(filenameNoExtension,"\","_")
					filenameNoExtension = Replace(filenameNoExtension,":","_")
					filenameNoExtension = Replace(filenameNoExtension,"*","_")
					filenameNoExtension = Replace(filenameNoExtension,"?","_")
					filenameNoExtension = Replace(filenameNoExtension,"""","_")
					filenameNoExtension = Replace(filenameNoExtension,"[","_")
					filenameNoExtension = Replace(filenameNoExtension,"]","_")
					filenameNoExtension = Replace(filenameNoExtension,"|","_")
					filenameNoExtension = Replace(filenameNoExtension,"=","_")
					filenameNoExtension = Replace(filenameNoExtension,",","_")
					filenameNoExtension = Replace(filenameNoExtension,".","_")
					filenameNoExtension = Replace(filenameNoExtension,";","_")

					tempfilename = UCase(CStr(Left(filenameNoExtension,6) & "~" & sfncount & "." & Left(extension,3)))

					'we've sorted by the filename column, so we can just compar against the previous row and increment it

					Do While sfnExists(tempfilename) And tableName <> "IniFile"
						'if the shortfilename entry exists, increment the sfn counter.  Unless we're in the IniFile table, where we can have identical SFN entries
						sfncount = sfncount + 1

						tempfilename = UCase(CStr(Left(filenameNoExtension,6) & "~" & sfncount & "." & Left(extension,3)))

						'if you've exceeded 9, then we need to generate new hex values.
						If sfncount > 9 Then					

							sfncount = 1 'decrement back to 1 and make some hex values
							'get new hex values
							ranhexa = Hex(Int((15+1)*Rnd))
							ranhexb = Hex(Int((15+1)*Rnd))
							ranhexc = Hex(Int((15+1)*Rnd))
							ranhexd = Hex(Int((15+1)*Rnd))					

							tempfilename = UCase(CStr(Left(filenameNoExtension,2) & ranhexa & ranhexb & ranhexc & ranhexd & "~" & sfncount & "." & Left(extension,3)))

						End If										
					Loop		

					'modify enables us to insert single quotes!
					fileRecord.StringData(1) = CStr(tempfilename & "|" & filename)
					fileView.Modify msiViewModifyUpdate, fileRecord
					WriteLog "Filename: " & filename & " has been modified to: " & 	CStr(tempfilename & "|" & filename) & " in the " & tableName & " table"
				End If	
			End If	
			Set fileRecord = fileView.Fetch
		Wend 

		Set fileView = Nothing
		Set fileRecord = Nothing
	End If
	Set tableRecord = tableView.Fetch
Wend 

Set tableView = Nothing
Set tableRecord = Nothing

oDatabase.Commit	

objLogFile.Close
Set fso = Nothing
Set objLogFile = Nothing	
Set oDatabase = Nothing
Set oInstaller = Nothing

Sub WriteLog(LogMessage)

	WScript.echo Now() & ": " & LogMessage
    objLogFile.Writeline(Now() & ": " & LogMessage)

End Sub

'checks to see if the short file name exists in file table before we add it

Function sfnExists(sfn)

sfnExists = False

	sql = "SELECT `FileName` FROM `File`" 
	Set fnView= oDatabase.OpenView(sql) 
	fnView.Execute
	Set fnRecord = fnView.Fetch
	Do Until fnRecord Is Nothing

		If Left(LCase(fnRecord.StringData(1)),Len(sfn)) = LCase(sfn) Then
			sfnExists = True
			Set fnView = Nothing
			Set fnRecord = Nothing
			Exit Function
		End If
		Set fnRecord = fnView.Fetch	
	Loop

	Set fnView = Nothing
	Set fnRecord = Nothing

End Function