'//: ////////////////////////////////////////////////////////////////////////////
'//+
'//+       Copyright (c) Sagemcom Froeschl GmbH. All rights reserved.
'//+
'//+ ////////////////////////////////////////////////////////////////////////////
'//+
'//+  project:   BugFix build
'//+  parameter: There are several command line parameters defined.
'//+             Syntax: setup.vbs /<name>:<value> /<name>:<value> ...
'//+             <name> can be:
'//+              * install-path   Indicates where the files should be installed.
'//+                               If omitted the path installation is not silent.
'//+
'//+  remarks:   Installs the bugfix into a specific path.
'//+
'//. ////////////////////////////////////////////////////////////////////////////

Option Explicit

Run64BitScriptEngineIfAvailable

Const ForReading = 1

Dim g_oFSO                : Set g_oFSO   = CreateObject("Scripting.FileSystemObject")
Dim g_oShell              : Set g_oShell = WScript.CreateObject("WScript.Shell")
Dim g_oLogger             : Set g_oLogger = new CLogger
Dim g_oBugfixInstaller    : Set g_oBugfixInstaller = new CBugfixInstaller
Dim g_dicFilesToRegister  : Set g_dicFilesToRegister = CreateObject("Scripting.Dictionary")
Dim g_szScriptPath        : g_szScriptPath = g_oFSO.GetParentFolderName(WScript.ScriptFullName)
Dim g_szItfEdvPath        : g_szItfEdvPath = CombinePath(g_oShell.ExpandEnvironmentStrings("%PROGRAMDATA%"), "ITF-EDV\zfa_f")

Dim g_szInstallFolder     : g_szInstallFolder = ""
SyncCmdLineArg "install-path", g_szInstallFolder

g_dicFilesToRegister.CompareMode = vbTextCompare
'                        file name     | COM+ (True) or COM (False)
g_dicFilesToRegister.Add "Printsvr.dll", True

Main

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub Main()
   If IsSilentInstallation() Then
      SilentInstall()
   Else
      NonSilentInstall()
   End If
End Sub

'/// Main function for nonsilent installation
Function NonSilentInstall()
   Dim szInstallFolder
   Dim fVersionCopied : fVersionCopied = False

   Dim oVersionHarvester : Set oVersionHarvester = new CVersionHarvester
   Dim aInstalledVersions : aInstalledVersions = oVersionHarvester.GetInstalledVersions()

   For Each szInstallFolder In aInstalledVersions
      If MsgBox("Apply bugfix to ZFA-F in the folder """ & szInstallFolder & """?", vbYesNo+vbQuestion, WScript.ScriptName)=vbYes Then
         Init GetRealPathName(szInstallFolder)
         If CopyExtractedFilesIntoTargetFolder() Then fVersionCopied = True
      End If
   Next

   If Not fVersionCopied Then
      Init GetRealPathName(InputBox("Installation directory", WScript.ScriptName, ""))
      CopyExtractedFilesIntoTargetFolder()
   End If

   RunInstanceManager
   g_oLogger.ShowLogFile
End Function

'/// Main function for silent installation
Function SilentInstall()
   EnsureCScriptIsRunningExt 1, True, False
   Init GetRealPathName(g_szInstallFolder)
   CopyExtractedFilesIntoTargetFolder()
   RunInstanceManager
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub Init(ByRef szInstallFolder)
   g_szInstallFolder = szInstallFolder
   Dim fValidInstallDir : fValidInstallDir = IsValidInstallDir()
   InitOutput()
   CheckInput()
   BugfixInstaller WScript.ScriptFullName, fValidInstallDir
   RemoveFilesFromTargetFolder()
End Sub

'/// Initializes the Output (console, logging)
Function InitOutput()
   g_oLogger.Init CombinePath(g_szInstallFolder, "log\installer\")
   g_oLogger.Write ""
   g_oLogger.Write "Applying Bugfix to folder """ & g_szInstallFolder & """ ..."
   g_oLogger.Write ""
   If IsSilentInstallation() Then
      g_oLogger.Write "Silent Installation started"
   Else
      g_oLogger.Write "Installation started"
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub CheckInput()
   If Len(g_szInstallFolder)=0 Then
      g_oLogger.Write "Installation path: invalid input"
      g_oLogger.ShowLogFile
      WScript.Quit(-1)
   End If
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function IsValidInstallDir()
   If (Not g_oFSO.FolderExists(g_szInstallFolder)) Then
      IsValidInstallDir = false
      Exit Function
   End If

   Dim oFolder : Set oFolder = g_oFSO.GetFolder(g_szInstallFolder)
   If (g_oFSO.FolderExists(g_szInstallFolder) _
       And oFolder.Files.Count = 0  _
       And oFolder.SubFolders.Count = 0) Then
      IsValidInstallDir = false
   Else
      IsValidInstallDir = true
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function IsSilentInstallation()
   IsSilentInstallation = (WScript.Arguments.Count > 0)
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Public Function DeleteFile(ByVal filePath)
   On Error Resume Next
   Err.Clear

   g_oFSO.DeleteFile filePath, True
   Dim szErrorText : szErrorText = ""

   If Err.Number <> 0 Then
      szErrorText = " (err.Number """ & err.Number & "; "" err.Description """ & err.Description & """)"
   End If

   Err.Clear
   On Error GoTo 0

   If Len(szErrorText)=0 Then
      g_oLogger.WriteWithTime "File removed: " & filePath
      DeleteFile = True
   Else
      g_oLogger.WriteWithTime "ERROR: '" & filePath & "' couldn't be deleted!" & szErrorText
      DeleteFile = False
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub RemoveFilesFromTargetFolder()
   Dim filesToDeleteTxt : filesToDeleteTxt = CombinePath(g_szScriptPath, "FilesToDelete.txt")

   If Not g_oFSO.FileExists(filesToDeleteTxt) Then
      Exit Sub
   End If

   Dim errorCount : errorCount = 0
   Dim txtFileStream : Set txtFileStream = g_oFSO.OpenTextFile(filesToDeleteTxt, ForReading, False)
   g_oLogger.Write "Cleanup 64-Bit ZFA-F"

   Do While txtFileStream.AtEndOfStream = False
      Dim filePath : filePath = g_szInstallFolder & Trim(txtFileStream.ReadLine)

      If g_oFSO.FileExists(filePath) Then
         g_oFSO.DeleteFile filePath
         Dim fileDeleted : fileDeleted = Not g_oFSO.FileExists(filePath)

         If Not fileDeleted Then
            g_oLogger.WriteWithTime "Error: '" & filePath & "' couldn't be deleted!"
            errorCount = errorCount + 1
         End If
      Else
         g_oLogger.WriteWithTime "WARNING: Skipped: '" & filePath & "' not found"
      End If
   Loop

   txtFileStream.Close
   g_oLogger.Write errorCount & " error(s) occurred"
   g_oLogger.Write " "
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function CopyExtractedFilesIntoTargetFolder()
   CopyExtractedFilesIntoTargetFolder = False

   Dim oColDicUpdateInfo : Set oColDicUpdateInfo = new CUpdateInfoCollection
   AnalyseFileStructure oColDicUpdateInfo

   Dim errorText : errorText = oColDicUpdateInfo.RenameInvalidFiles()
   If Len(errorText) > 0 Then
      g_oLogger.Write "Update is not possible due to following conflicts:"
      g_oLogger.Write ""
      g_oLogger.Write "64-Bit update errors"
      g_oLogger.Write ""
      g_oLogger.Write errorText
      Exit Function
   End If

   g_oLogger.Write "Updating 64-Bit ZFA-F " & " (" & oColDicUpdateInfo.Count & " files)"
   CopyReleaseNotes "En"
   CopyReleaseNotes "De"

   Dim fRegisterComObjectIfNecessary : fRegisterComObjectIfNecessary = Not oColDicUpdateInfo.OnlyNewFiles

   Dim uiFailures : uiFailures = 0
   Dim oUpdateInfo
   For Each oUpdateInfo In oColDicUpdateInfo.Items
      CreateCompleteFolder g_oFSO.GetParentFolderName(oUpdateInfo.m_TargetFile)
      If oUpdateInfo.CopyFile() Then
         If fRegisterComObjectIfNecessary Then
            If Not RegisterComObjectIfNecessary(oUpdateInfo) Then
               uiFailures = uiFailures + 1
            End If
         End If
      Else
         uiFailures = uiFailures + 1
      End If
   Next
   g_oLogger.Write uiFailures & " error(s) occurred"

   CopyExtractedFilesIntoTargetFolder = True
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Private Sub CopyReleaseNotes(ByVal szLanguage)
   Dim szReleaseNotesFileName : szReleaseNotesFileName = CombinePath(g_szScriptPath, "ReleaseNotes" & szLanguage & ".html")
   If g_oFSO.FileExists(szReleaseNotesFileName) Then
      CreateCompleteFolder g_szInstallFolder
      g_oFSO.CopyFile szReleaseNotesFileName, CombinePath(g_szInstallFolder, "ReleaseNotes" & szLanguage & ".html"), True
   End If
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function BugfixInstaller(ByVal szScriptFullName, ByRef fValidInstallDir)
Dim oFile : Set oFile = g_oFSO.GetFile(szScriptFullName)
Dim szFolder : szFolder = g_oFSO.GetParentFolderName(oFile)
   g_oLogger.Write ""

   If (g_oBugfixInstaller.Init(szFolder, g_szInstallFolder, g_oLogger.GetLogFilePath) And _
       fValidInstallDir) Then
      g_oLogger.Write "Run bugfixinstaller.exe"
   Else
      g_oLogger.Write "Skip bugfixinstaller.exe"
      Exit Function
   End If

   g_oLogger.CloseLogFile
   Dim iErrorCode : iErrorCode = g_oBugfixInstaller.Run
   If Not (iErrorCode = 0) Then
      g_oLogger.OpenLogFile
      g_oLogger.Write "Error occured in bugfixinstaller.exe. ERRORCODE: " & iErrorCode
      g_oLogger.Write "You can find further information in the manual ""install_hb.pdf"" under:"
      g_oLogger.Write "Shared processes > Installing a bugfix and customer build"
      g_oLogger.ShowLogFile
      WScript.Quit(-1)
   End If

   g_oLogger.OpenLogFile
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub RunInstanceManager()
   Dim szInstanceManagerCfg : szInstanceManagerCfg = CombinePath(g_szInstallFolder, "bin\instancemanager_wu.cfg")

   If g_oFSO.FileExists(szInstanceManagerCfg) Then
      g_oLogger.Write ""
      g_oLogger.Write "Setup Instance Manager"
      g_oLogger.Write ""

      Dim szSourceInstanceManager : szSourceInstanceManager = CombinePath(g_szScriptPath,    "instancemanagersetup.exe")
      Dim szInstanceManager       : szInstanceManager       = CombinePath(g_szInstallFolder, "bin\instancemanagersetup.exe")

      If g_oFSO.FileExists(szSourceInstanceManager) Then
         g_oFSO.CopyFile szSourceInstanceManager, szInstanceManager, True
      End If

      If Not g_oFSO.FileExists(szInstanceManager) Then
         g_oLogger.Write "Error: '" & szInstanceManager & "' not found!"
         Exit Sub
      End If

      g_oFSO.DeleteFile szInstanceManagerCfg
      If g_oFSO.FileExists(szInstanceManagerCfg) Then
         g_oLogger.Write "Error: '" & szInstanceManagerCfg & "' couldn't be deleted!"
         Exit Sub
      End If

      g_oShell.Run("cmd /c " & szInstanceManager), 1, True

      If g_oFSO.FileExists(szInstanceManagerCfg) Then
         g_oLogger.Write "'" & szInstanceManagerCfg & "' created"
      Else
         g_oLogger.Write "Error: '" & szInstanceManagerCfg & "' couldn't be created!"
      End If
   End If
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function RegisterComObjectIfNecessary(ByVal oUpdateInfo)
   RegisterComObjectIfNecessary = True
   If g_dicFilesToRegister.Exists(g_oFSO.GetFileName(oUpdateInfo.m_TargetFile)) Then
      Dim oRegisterServer : Set oRegisterServer = new CRegisterServer
      g_oLogger.Write "Register file """ & oUpdateInfo.m_TargetFile & """."
      If Not oRegisterServer.Register(oUpdateInfo, g_dicFilesToRegister(g_oFSO.GetFileName(oUpdateInfo.m_TargetFile))) Then
         g_oLogger.Write "ERROR: An error occurred while trying to register """ & oUpdateInfo.m_TargetFile & """!"
         g_oLogger.Write "INFO: Registering a DLL requires admin rights. Please run Bugfix.exe as admin if not already done!"
         RegisterComObjectIfNecessary = False
      End If
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub AnalyseFileStructure(ByVal oColDicUpdateInfo)
   Dim oSubFolder
   For Each oSubFolder In g_oFSO.GetFolder(CombinePath(g_szScriptPath, "unicode\x64")).SubFolders
      AnalyseFileStructureRecursive oSubFolder, CombinePath(g_szInstallFolder, oSubFolder.name), oColDicUpdateInfo
   Next
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Sub AnalyseFileStructureRecursive(ByVal oSourceFolder, ByVal szTargetPath, ByVal oColDicUpdateInfo)
   Dim oFile, oUpdateInfo
   For Each oFile In oSourceFolder.Files
      Set oUpdateInfo = new CUpdateInfo
      oUpdateInfo.m_SourceFile = oFile.path
      oUpdateInfo.m_TargetFile = CombinePath(szTargetPath, oFile.name)

      If (StrComp(g_oFSO.GetExtensionName(oFile.name), "dll", vbTextCompare) = 0 Or _
          StrComp(g_oFSO.GetExtensionName(oFile.name), "exe", vbTextCompare) = 0) Then
         oUpdateInfo.m_fBinaryFile = True

         If g_oFSO.FileExists(oUpdateInfo.m_TargetFile) Then
            oUpdateInfo.m_fTargetFileDoesExist = True

            If IsThirdPartyBinary(oUpdateInfo.m_TargetFile) Then
               oUpdateInfo.m_fThirdPartyDll = True
            End If

            If IsUpdateAllowedRegardingVersion(oFile.path, oUpdateInfo.m_TargetFile) Then
               oUpdateInfo.m_fVersionIdentical = True
            End If
         End If
      Else
         Dim iHtdocsPosition : iHtdocsPosition = InStr(1, oFile.Path, "htdocs", vbTextCompare)
         If iHtdocsPosition > 0 Then
            oUpdateInfo.m_fWebFile = True
            If oColDicUpdateInfo.IsDistributedInstallation() Then
               oUpdateInfo.m_TargetFile = CombinePath(g_szItfEdvPath, Mid(oFile.Path, iHtdocsPosition))
            End If
         End If

         If g_oFSO.FileExists(oUpdateInfo.m_TargetFile) Then oUpdateInfo.m_fTargetFileDoesExist = True
      End If
      oColDicUpdateInfo.Add oUpdateInfo
   Next

   Dim oSubFolder
   For Each oSubFolder In oSourceFolder.SubFolders
      AnalyseFileStructureRecursive oSubFolder, CombinePath(szTargetPath, oSubFolder.name), oColDicUpdateInfo
   Next
End Sub

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function IsUpdateAllowedRegardingVersion(ByVal szSourceFile, ByVal szTargetFile)
   Dim aVersionSource : aVersionSource = Split(GetFileVersion(szSourceFile), ".")
   Dim aVersionTarget : aVersionTarget = Split(GetFileVersion(szTargetFile), ".")

   IsUpdateAllowedRegardingVersion = (aVersionSource(0)=aVersionTarget(0) And aVersionSource(1)=aVersionTarget(1))
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function GetMajorAndMinorVersionOfBugfix()
   Dim szVersionInfo : szVersionInfo = CombinePath(g_szScriptPath, "version.info")
   If Not g_oFSO.FileExists(szVersionInfo) Then
      MsgBox "ERROR: The file 'version.info' is missing.", vbCritical, WScript.ScriptFullName
      WScript.Quit(-1)
   End If

   Dim szMajor : szMajor = ReadIni(szVersionInfo, "VERSION", "MAJOR")
   Dim szMinor : szMinor = ReadIni(szVersionInfo, "VERSION", "MINOR")
   GetMajorAndMinorVersionOfBugfix = szMajor & "." & szMinor
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function ReadIni( myFilePath, mySection, myKey )
    Const ForReading   = 1
    Const ForWriting   = 2
    Const ForAppending = 8

    Dim intEqualPos
    Dim objFSO, objIniFile
    Dim strFilePath, strKey, strLeftString, strLine, strSection

    Set objFSO = CreateObject( "Scripting.FileSystemObject" )

    ReadIni     = ""
    strFilePath = Trim( myFilePath )
    strSection  = Trim( mySection )
    strKey      = Trim( myKey )

    If objFSO.FileExists( strFilePath ) Then
        Set objIniFile = objFSO.OpenTextFile( strFilePath, ForReading, False )
        Do While objIniFile.AtEndOfStream = False
            strLine = Trim( objIniFile.ReadLine )

            If LCase( strLine ) = "[" & LCase( strSection ) & "]" Then
                strLine = Trim( objIniFile.ReadLine )

                Do While Left( strLine, 1 ) <> "["
                    intEqualPos = InStr( 1, strLine, "=", 1 )
                    If intEqualPos > 0 Then
                        strLeftString = Trim( Left( strLine, intEqualPos - 1 ) )
                        If LCase( strLeftString ) = LCase( strKey ) Then
                            ReadIni = Trim( Mid( strLine, intEqualPos + 1 ) )
                            If ReadIni = "" Then
                                ReadIni = " "
                            End If
                            Exit Do
                        End If
                    End If

                    If objIniFile.AtEndOfStream Then Exit Do

                    strLine = Trim( objIniFile.ReadLine )
                Loop
            Exit Do
            End If
        Loop
        objIniFile.Close
    Else
        WScript.Echo strFilePath & " doesn't exists. Exiting..."
        Wscript.Quit 1
    End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function GetMajorAndMinorVersion(ByVal szInstallFolder)
   GetMajorAndMinorVersion = ""
   Dim szZfa : szZfa = CombinePath(szInstallFolder, "bin\zfa_f.exe")

   If g_oFSO.FileExists(szZfa) Then
      ' zfa_f.exe must always exist if it is an installed version
      Dim aVersion : aVersion = Split(GetFileVersion(szZfa), ".")
      GetMajorAndMinorVersion = aVersion(0) & "." & aVersion(1)
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Private Function GetFileVersion(ByVal szFileName)
   GetFileVersion = g_oFSO.GetFileVersion(szFileName)

   If Len(GetFileVersion)=0 Then
      g_oLogger.WriteWithTime "WARNING: Version information for file """ & szFileName & """ can't be determined. File may be locked!"
      GetFileVersion = "0.0.0.0"
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function IsThirdPartyBinary(ByVal szFilePath)
   ' copyright = 25
   Dim szCopyright : szCopyright = GetDetail(szFilePath, 25)

   If InStr(1, szCopyright, "Sagemcom", vbTextCompare) > 0 Then
      g_oLogger.WriteWithTime "File: " & szFilePath & " is a Sagemcom binary"
      IsThirdPartyBinary = False
   Else
      g_oLogger.WriteWithTime "File: " & szFilePath & " is a thirdparty binary"
      IsThirdPartyBinary = True
   End If
End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
class CRegisterServer
   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function Register(ByVal oUpdateInfo, ByVal fIsComPlus)
      UnRegister oUpdateInfo, fIsComPlus
      'wscript.echo "cmd /c """ & GetCmdLine(oUpdateInfo, fIsComPlus, True) & """"
      g_oLogger.Write "cmd /c """ & GetCmdLine(oUpdateInfo, fIsComPlus, True) & """"
      Register = (g_oShell.Run("cmd /c """ & GetCmdLine(oUpdateInfo, fIsComPlus, True) & """", 1, True) = 0)
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function UnRegister(ByVal oUpdateInfo, ByVal fIsComPlus)
      UnRegister = (g_oShell.Run("cmd /c """ & GetCmdLine(oUpdateInfo, fIsComPlus, False) & """", 1, True) = 0)
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetCmdLine(ByVal oUpdateInfo, ByVal fIsComPlus, ByVal fRegister)
      Dim szRegSvcsExecutable : szRegSvcsExecutable = GetRegExecutable(fIsComPlus)
      If fRegister Then
         GetCmdLine = szRegSvcsExecutable & " /c "
      Else
         GetCmdLine = szRegSvcsExecutable & " /u "
      End If

      If fIsComPlus Then
         GetCmdLine = GetCmdLine & "/appname:" & GetAppName(oUpdateInfo) & " "
      End If
      GetCmdLine = GetCmdLine & """" & oUpdateInfo.m_TargetFile & """"
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetAppName(ByVal oUpdateInfo)
      If InStr(1, oUpdateInfo.m_SourceFile, "x64", vbTextCompare) > 1 Then
         GetAppName = g_oFSO.GetBaseName(oUpdateInfo.m_SourceFile) & "64"
      Else
         GetAppName = g_oFSO.GetBaseName(oUpdateInfo.m_SourceFile)
      End If
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetRegExecutable(ByVal fIsComPlus)
      Dim szDotNetFrameworkPath : szDotNetFrameworkPath = CombinePath(g_oShell.ExpandEnvironmentStrings("%WinDir%"), "Microsoft.NET")

      If Not g_oFSO.FolderExists(szDotNetFrameworkPath) Then
         MsgBox ".Net Framework not found!", vbCritical, WScript.ScriptFullName
         WScript.Quit(-1)
      End If

      Dim iCnt : iCnt = 0
      Dim oDicExecutables : Set oDicExecutables = CreateObject("Scripting.Dictionary")
      Dim szDotNetFrameworkPath64 : szDotNetFrameworkPath64 = CombinePath(szDotNetFrameworkPath, "Framework64")

      If g_oFSO.FolderExists(szDotNetFrameworkPath64) Then
         GetRegExecutablesHelper g_oFSO.GetFolder(szDotNetFrameworkPath64), oDicExecutables, iCnt, fIsComPlus
      End If

      If oDicExecutables.Count = 0 Then
         MsgBox "RegSvcs.exe not found!", vbCritical, WScript.ScriptFullName
         WScript.Quit(-1)
      End If

      GetRegExecutable = oDicExecutables(1)
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetRegExecutablesHelper(ByVal oFolder, ByRef oDicExecutables, ByRef iCnt, ByVal fIsComPlus)
      Dim oSubFolder
      For Each oSubFolder In oFolder.SubFolders
         GetRegExecutablesHelper oSubFolder, oDicExecutables, iCnt, fIsComPlus
      Next

      Dim szExecName
      If fIsComPlus Then
         szExecName = "RegSvcs.exe"
      Else
         szExecName = "RegAsm.exe"
      End If

      Dim oFile
      For Each oFile In oFolder.Files
         If StrComp(Left(oFile.ParentFolder.Name, 2), "v4", vbTextCompare) = 0 Then
            If StrComp(oFile.Name, szExecName, vbTextCompare) = 0 Then
               iCnt = iCnt + 1
               oDicExecutables.Add iCnt, oFile.path
            End If
         End If
      Next
   End Function
End Class


'/// //////////////////////////////////////////////////////////////////////////////////////////////
Class CUpdateInfo
   Public m_SourceFile
   Public m_TargetFile
   Public m_fBinaryFile
   Public m_fVersionIdentical
   Public m_fThirdPartyDll
   Public m_fTargetFileDoesExist
   Public m_fWebFile

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Sub Class_Initialize()
      m_fBinaryFile = False
      m_fVersionIdentical = False
      m_fThirdPartyDll = False
      m_fTargetFileDoesExist = False
      m_fWebFile = False
   End Sub

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Property Get SourceFileInfo
      SourceFileInfo = GetFileInfo(m_SourceFile)
   End Property

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Property Get TargetFileInfo
      TargetFileInfo = GetFileInfo(m_TargetFile)
   End Property

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function CopyFile()
      On Error Resume Next
      Err.Clear
      g_oFSO.CopyFile m_SourceFile, m_TargetFile, True
      Dim szErrorText : szErrorText = ""
      If Err.Number <> 0 Then
         szErrorText = " (err.Number """ & err.Number & "; "" err.Description """ & err.Description & """)"
      End If
      Err.Clear
      On Error GoTo 0
      If Len(szErrorText)=0 Then
         g_oLogger.WriteWithTime "Copy from """ & SourceFileInfo & """ to """ & TargetFileInfo & """"
         CopyFile = True
      Else
         g_oLogger.WriteWithTime "ERROR: Copy from """ & SourceFileInfo & """ to """ & TargetFileInfo & """" & szErrorText
         CopyFile = False
      End If
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetFileInfo(ByVal szFileName)
      If Not m_fBinaryFile Or Not g_oFSO.FileExists(szFileName) Then
         GetFileInfo = szFileName
         Exit Function
      End If

      GetFileInfo = szFileName & " : " & GetFileVersion(szFileName)
   End Function
End Class ' CUpdateInfo

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Class CUpdateInfoCollection
   Private m_dicUpdateInfo

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Sub Class_Initialize()
      Set m_dicUpdateInfo = CreateObject("Scripting.Dictionary")
   End Sub

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Property Get Count
      Count = m_dicUpdateInfo.Count
   End Property

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Property Get Items
      Items = m_dicUpdateInfo.Keys
   End Property

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Sub Add(ByVal oUpdateInfo)
      m_dicUpdateInfo.Add oUpdateInfo, 0
   End Sub

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function RenameInvalidFiles()
      RenameInvalidFiles = ""
      Dim oUpdateInfo
      For Each oUpdateInfo In Items
         If oUpdateInfo.m_fBinaryFile _
            And oUpdateInfo.m_fTargetFileDoesExist _
            And Not oUpdateInfo.m_fVersionIdentical _
            And Not oUpdateInfo.m_fThirdPartyDll Then
               Dim szSourceFile : szSourceFile = oUpdateInfo.m_TargetFile
               Dim szTargetFile : szTargetFile = oUpdateInfo.m_TargetFile & "." & GetFileVersion(oUpdateInfo.m_TargetFile) & ".old"
               On Error Resume Next
               Err.Clear
               g_oFSO.MoveFile szSourceFile, szTargetFile
               Dim szErrorText : szErrorText = ""
               If Err.Number <> 0 Then
                  szErrorText = " (err.Number """ & err.Number & "; "" err.Description """ & err.Description & """)"
               End If
               Err.Clear
               On Error GoTo 0
               If Len(szErrorText)=0 Then
                  g_oLogger.Write "File renamed from """ & szSourceFile & """ to """ & szTargetFile & """"
               Else
                  RenameInvalidFiles = RenameInvalidFiles + "   ERROR: Rename file from """ & szSourceFile & """ to """ & szTargetFile & """" & szErrorText
               End If
         End If
      Next
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function IsDistributedInstallation()
      Dim oConfigFilePath
      Dim szConfigPath : szConfigPath = CombinePath(g_szInstallFolder, "config")
      Dim szCentralConfigurationIniPath : szCentralConfigurationIniPath = CombinePath(szConfigPath, "central_configuration.ini")
      Dim szLanguageIniPath : szLanguageIniPath = CombinePath(szConfigPath, "\language.ini")

      If(g_oFSO.FileExists(szCentralConfigurationIniPath)) Then
         Set oConfigFilePath = g_oFSO.OpenTextFile(szCentralConfigurationIniPath, ForReading)
      ElseIf(g_oFSO.FileExists(szLanguageIniPath)) Then
         Set oConfigFilePath = g_oFSO.OpenTextFile(szLanguageIniPath, ForReading)
      Else
         IsDistributedInstallation = False
         Exit Function
      End If

      Do until oConfigFilePath.AtEndOfStream
         Dim szLine : szLine = oConfigFilePath.ReadLine

         If (Left(szLine, 10) = "SETUP_MODE") Then
            If (Right(szLine, 11) = "centralized") Then
               IsDistributedInstallation = False
               Exit Do
            Else
               IsDistributedInstallation = True
               Exit Do
            End If
         End If
      Loop
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function OnlyNewFiles()
      OnlyNewFiles = True
      Dim oUpdateInfo
      For Each oUpdateInfo In Items
         If oUpdateInfo.m_fTargetFileDoesExist Then
            OnlyNewFiles = False
            Exit Function
         End If
      Next
   End Function
End Class ' CUpdateInfoCollection

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Class CVersionHarvester
   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function GetInstalledVersions()
      Dim szRegKeyZfa64 : szRegKeyZfa64 = "HKLM\SOFTWARE\ITF-EDV\ZFA-F\"

      Dim oDic : Set oDic = CreateObject("Scripting.Dictionary")
      AddInstalledVersionIfAvailable szRegKeyZfa64 & "InstallFolder", oDic
      AddInstalledVersionIfAvailable szRegKeyZfa64 & "InstallDir", oDic

      Dim szSubKey
      For Each szSubKey In RegReadSubKeys("SOFTWARE\ITF-EDV\ZFA-F")
         AddInstalledVersionIfAvailable szRegKeyZfa64 & szSubKey & "\InstallFolder", oDic
         AddInstalledVersionIfAvailable szRegKeyZfa64 & szSubKey & "\InstallDir", oDic
      Next

      GetInstalledVersions = oDic.Keys
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function GetRegEntry(szRegkey)
      On Error Resume Next
      GetRegEntry = g_oShell.RegRead(szRegKey)
      On Error GoTo 0
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Private Function RegReadSubKeys(ByVal szKeyPath)
      On Error Resume Next
      Dim arrSubKeys
      const HKEY_LOCAL_MACHINE = &H80000002
      Dim oReg : Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
      oReg.EnumKey HKEY_LOCAL_MACHINE, szKeyPath, arrSubKeys
      If Not IsArray(arrSubKeys) Then
         RegReadSubKeys = Split("", ",")
         Exit Function
      End If
      On Error GoTo 0
      RegReadSubKeys = arrSubKeys
   End Function

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Class CBugfixInstaller
   Private m_szBugfixInstaller
   Private m_szInstallDir
   Private m_szVersionInfoPath
   Private m_szLogFile

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function Init(ByVal szSource, ByVal szInstallDir, ByVal szLogFile)
      szSource = TrimEx(szSource, """")
      szInstallDir = TrimEx(szInstallDir, """")
      szLogFile = TrimEx(szLogFile, """")

      m_szBugfixInstaller = """" & szSource & "\bugfixinstaller.exe" & """"
      m_szInstallDir = """" & szInstallDir & """"
      m_szVersionInfoPath = """" & szSource & "\version.info" & """"
      m_szLogFile = """" & szLogFile & """"
      Init = g_oFSO.FileExists(TrimEx(m_szBugfixInstaller, """")) and g_oFSO.FileExists(TrimEx(m_szVersionInfoPath, """")) and g_oFSO.FileExists(TrimEx(m_szLogFile, """"))
   End Function

   '/// //////////////////////////////////////////////////////////////////////////////////////////////
   Public Function Run()
      Run = (g_oShell.Run("cmd /c """ & m_szBugfixInstaller & " --installdir=" & m_szInstallDir & " --logfile=" & m_szLogFile & " --versioninfo=" & m_szVersionInfoPath & """", 1, True))
   End Function
End Class ' CBugfixInstaller


'/// //////////////////////////////////////////////////////////////////////////////////////////////
'///                                     Helper functions
'/// //////////////////////////////////////////////////////////////////////////////////////////////

'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function GetRealPathName(ByVal szPathName)
   If Len(szPathName) = 0 Then
      GetRealPathName = szPathName
      Exit Function
   End If
   szPathName = TrimEx(szPathName, """")
   GetRealPathName = g_oFSO.GetAbsolutePathName(g_oShell.ExpandEnvironmentStrings(szPathName))
End Function

'/// Checks if a specific named command line argument exists. If it exists it would be
'/// assigned to the output variable.
'/// @param[in]  szCmdLineParamName Name of the named command line argument.
'/// @param[out] Value              Buffer for the value of the named command line argument.
Sub SyncCmdLineArg(ByVal szCmdLineParamName, ByRef Value)
   If WScript.Arguments.Named(szCmdLineParamName) = "" Then
      Exit Sub
   End If

   Select Case VarType(Value)
   Case vbEmpty
      Value=WScript.Arguments.Named(szCmdLineParamName)
   Case vbString
      Value=WScript.Arguments.Named(szCmdLineParamName)
   Case vbInteger
      Value=CInt(WScript.Arguments.Named(szCmdLineParamName))
   Case vbBoolean
      If StrComp(WScript.Arguments.Named(szCmdLineParamName), "true", vbTextCompare)=0 Then
         Value = True
      ElseIf StrComp(WScript.Arguments.Named(szCmdLineParamName), "false", vbTextCompare)=0 Then
         Value = False
      Else
         MsgBox "A boolean variable must be initialized with ""true"" or ""false"".", vbCritical, WScript.ScriptFullName
      End If
   Case Else
      MsgBox "Variable type not supported yet. You have to extend the function ""SyncCmdLineArg"".", vbCritical, WScript.ScriptFullName
   End Select
End Sub


'/// //////////////////////////////////////////////////////////////////////////////////////////////
Function TrimEx(ByVal szStringWhichWillBeTrimmed, ByVal szCharacterToTrim)
   Dim oRegEx : Set oRegEx = new RegExp
   szCharacterToTrim = Replace(szCharacterToTrim, "\", "\\")
   oRegEx.Pattern     = "^[" & szCharacterToTrim & "]*(.*?)[" & szCharacterToTrim & "]+$"
   oRegEx.IgnoreCase  = True
   TrimEx = oRegEx.Replace(szStringWhichWillBeTrimmed, "$1")
End Function

'/// Ensures that a complete path is created.
'/// @param[in]  Name of path which should be generated.


'/// @remarks Caution! This function can deliver different results by using different windows versions (iColumn).
Function GetDetail(ByVal szFilePath, ByVal iColumn)
   If Not g_oFSO.FileExists(szFilePath) Then Exit Function

   Dim oAppShell : Set oAppShell = CreateObject("Shell.Application")
   Dim oFolder   : Set oFolder = oAppShell.Namespace(g_oFSO.GetParentFolderName(szFilePath))
   If oFolder Is Nothing Then Exit Function

   Dim oFolderItem : Set oFolderItem = oFolder.ParseName(g_oFSO.GetFileName(szFilePath))
   If oFolderItem Is Nothing Then Exit Function

   GetDetail = oFolder.GetDetailsOf(oFolderItem, iColumn)
   Set oFolderItem = Nothing
End Function

Convert to c# code