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