$DisplayName = "NAKIVO Backup & Replication"
$ProductUuid = "2C90508235DDBB670135DDBB739E0001"
$Contact = "support@nakivo.com"
$HelpLink = "https://www.nakivo.com"
$Readme = "https://www.nakivo.com"
$UrlInfoAbout = "https://www.nakivo.com"
$UrlUpdateInfo = "https://www.nakivo.com"
$DisplayVersion = "11.2.0.101299"
$Publisher = "NAKIVO, Inc"
$InstallLocation = "C:\Program Files\NAKIVO Backup & Replication"
$TransporterInstallLocation = "C:\Program Files\NAKIVO Backup & Replication\transporter"
$InstallRegistryFileName = "install.reg"
$UninstallScriptFileName = "uninstall.ps1"
$ProductUuidJavaPrefs = "2/C90508235/D/D/B/B670135/D/D/B/B739/E0001" # All alpha symbols are escaped
$InstallerHiveJavaPrefs = "/Installer/Hive" # All alpha symbols are escaped
$TransporterServicePort = "9446"
$TransporterServiceFirewallPortRange = @("9446","9448-10000") # Array of strings, e.g. "9446","9448-10000"
$TransporterServiceName = "bhsvc"
$TransporterServiceDisplayName = "NAKIVO Backup & Replication Transporter"
$TransporterServiceBinary = "bhsvc.exe"
$TransporterServiceDescription = "Performs data processing and transfer for NAKIVO Backup & Replication."
$TransporterIcon = "icon.ico"
$Update = $false
$IgnoreVcRedistInstallFailure = $false
$VcRedistSuccessCodes = @("0", "1603", "1638", "3010", "5100")
$SkipVcRedistInstall = $false
# Terminate on first error, do not continue
$ErrorActionPreference="Stop"
# Get powershell version
$PSVersion=$PSVersionTable.PSVersion.Major
$HasRedirectBugs=($PSVersion -lt 3)
# Checks service existence
function IsServiceExists() {
    echo "Checking if the service exists: $TransporterServiceName"

    $serviceExists = $true
    try {
        Get-Service -name $TransporterServiceName
    } catch {
        $serviceExists = $false
    }

    echo "Service exists: $serviceExists"

    $serviceExists
}

# Adds standalone windows installer registry key
function AddWindowsInstallerInfo() {
    echo "AddWindowsInstallerInfo: importing $InstallRegistryFileName"

    # Run install.reg to mimic standalone windows installer, so the transporter can be updated manually later
    reg import "$TransporterInstallLocation\$InstallRegistryFileName"
}

# Dumps exception into the log
function DumpException($exception) {
    try {
        echo $exception | format-list -force
    } catch {
        try {
            echo $exception
        } catch {
            echo "Exception happened."
        }
    }
}

if (!$SkipVcRedistInstall) {
    # VC redist v90 installer is expected to be present, run it
    try {
        echo "Running VC redist v90 installation."

        Start-Process "$TransporterInstallLocation\vcredist_v90_x64.exe" -windowstyle Hidden -ArgumentList "/Q /norestart" -PassThru -Wait | Tee-Object -Variable proc

        if (-not ($VcRedistSuccessCodes -contains $proc.ExitCode)) {
            echo "Cannot install VC redist v90, exit code"$proc.ExitCode

            if (!$IgnoreVcRedistInstallFailure) {
                Exit 1
            }
        } else {
            echo "Installed VC redist v90, exit code"$proc.ExitCode
        }
    } catch {
        echo "Installing VC redist v90 failed."
        DumpException($_.Exception)
        Exit 2
    }

    # VC redist v120 installer is expected to be present, run it
    try {
        echo "Running VC redist v120 installation."
        Start-Process "$TransporterInstallLocation\vcredist_v120_x64.exe" -windowstyle Hidden -ArgumentList "/Q /norestart" -PassThru -Wait | Tee-Object -Variable proc
        if (-not ($VcRedistSuccessCodes -contains $proc.ExitCode)) {
            echo "Cannot install VC redist v120, exit code"$proc.ExitCode

            if (!$IgnoreVcRedistInstallFailure) {
                Exit 1
            }
        } else {
            echo "Installed VC redist v120, exit code"$proc.ExitCode
        }
    } catch {
        echo "Installing VC redist v120 failed."
        DumpException($_.Exception)
        Exit 2
    }

    # VC redist v170 installer is expected to be present, run it
    try {
        echo "Running VC redist v170 installation."

        Start-Process "$TransporterInstallLocation\vcredist_v170_x64.exe" -windowstyle Hidden -ArgumentList "/Q /norestart" -PassThru -Wait | Tee-Object -Variable proc
        if (-not ($VcRedistSuccessCodes -contains $proc.ExitCode)) {
            echo "Cannot install VC redist v170, exit code"$proc.ExitCode

            if (!$IgnoreVcRedistInstallFailure) {
                Exit 1
            }
        } else {
            echo "Installed VC redist v170, exit code"$proc.ExitCode
        }
    } catch {
        echo "Installing VC redist v170 failed."
        DumpException($_.Exception)
        Exit 2
    }
}

# Setup Transporter service
try {
    echo "Setting up the Transporter service."

    # Cleanup first
    if (IsServiceExists) {
        Stop-Service $TransporterServiceName -ErrorAction SilentlyContinue

        echo "Deleting service: $TransporterServiceName"

        if ($HasRedirectBugs) {
            sc.exe delete $TransporterServiceName >$null
        } else {
            sc.exe delete $TransporterServiceName
        }
    }

    echo "Creating service: $TransporterServiceName"

    New-Service -Name $TransporterServiceName `
        -BinaryPathName """$TransporterInstallLocation\$TransporterServiceBinary"" $TransporterServicePort" `
        -DependsOn "LanmanWorkstation" -DisplayName $TransporterServiceDisplayName `
        -StartupType Automatic -Description $TransporterServiceDescription

    echo "Updating service parameters: $TransporterServiceName"

    # Powershell does not allow modifying this, use sc.exe
    if ($HasRedirectBugs) {
        sc.exe failure $TransporterServiceName reset= 0 actions= restart/60000/restart/60000/restart/60000 >$null
    } else {
        sc.exe failure $TransporterServiceName reset= 0 actions= restart/60000/restart/60000/restart/60000
    }
} catch {
    echo "Transporter service setup failed."
    DumpException($_.Exception)
    Exit 3
}

# Start Transporter service
try {
    echo "Starting service: $TransporterServiceName"
    Start-Service $TransporterServiceName
} catch {
    echo "Transporter service startup failed."
    DumpException($_.Exception)
    Exit 4
}


# Setup firewall
try {
    echo "Setting up the firewall: cleanup."

    # Cleanup first
    # Support old Windows/PS version. This can happen even in Win2012R2.
    if (Get-Command Remove-NetFirewallRule -ErrorAction SilentlyContinue) {
        echo "Firewall: deleting rules via Remove-NetFirewallRule: $DisplayName"

        if ($HasRedirectBugs) {
            Remove-NetFirewallRule -DisplayName "$DisplayName" -ErrorAction SilentlyContinue >$null
        } else {
            Remove-NetFirewallRule -DisplayName "$DisplayName" -ErrorAction SilentlyContinue
        }
    } else {
        echo "Firewall: deleting rules via netsh: $DisplayName"

        if ($HasRedirectBugs) {
            Invoke-Expression "netsh advfirewall firewall delete rule name='$DisplayName' dir=in profile=any protocol=TCP localport=$TransporterServicePort" >$null
        } else {
            Invoke-Expression "netsh advfirewall firewall delete rule name='$DisplayName' dir=in profile=any protocol=TCP localport=$TransporterServicePort"
        }
    }
} catch {
    # Ignore
    echo "Cannot cleanup firewall rules."
}
try {
    echo "Setting up the firewall: adding new rules."

    # Support old Windows/PS version. This can happen even in Win2012R2.
    if (Get-Command New-NetFirewallRule -ErrorAction SilentlyContinue) {
        echo "Firewall: adding rules via New-NetFirewallRule: $DisplayName"

        New-NetFirewallRule -DisplayName "$DisplayName" -Name "$DisplayName" -Profile Any `
        -LocalPort $TransporterServiceFirewallPortRange -Protocol TCP
    } else {
        echo "Firewall: adding rules via netsh: $DisplayName"

        Invoke-Expression "netsh advfirewall firewall add rule name='$DisplayName' dir=in action=allow profile=any protocol=TCP localport=$TransporterServicePort" >$null
    }
} catch {
    # Firewall service is not enabled.
    if ($_.Exception.HResult -eq 0x80131500) {
        echo "Windows Firewall is not enabled. Bypass setting Firewall rule."
    } else {
        echo "Firewall setup failed."
        DumpException($_.Exception)
        Exit 5
    }
}

# Integrate with standalone Windows NBR installer
try {
    echo "Adding Registry info for standalone installer."
    AddWindowsInstallerInfo
} catch {
    echo "Standalone installer info setup failed."
    DumpException($_.Exception)
    Exit 6
}

# Integrate with Windows Programs and Features registry
try {
    echo "Adding uninstall info into Programs and Features."

    $uninstall = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
    $fullpath = "$uninstall$ProductUuid"

    # Try to remove old key
    try {
        if (Test-Path $fullpath) {
            Remove-Item -Path $fullpath -ErrorAction Continue
        }
    } catch {
        # Ignore. "ErrorAction" is ignored on some systems.
    }

    $UninstallString = "powershell.exe -ExecutionPolicy UnRestricted -File ""$TransporterInstallLocation\$UninstallScriptFileName"""
    $DisplayIcon = "$TransporterInstallLocation\$TransporterIcon"
    $NoModify = 1
    $NoRepair = 1

    # Create the key or skip error if exists
    try {
        New-Item -Path $uninstall -Name $ProductUuid -ErrorAction SilentlyContinue
    } catch {
        # Ignore. "ErrorAction" is ignored on some systems.
    }

    New-ItemProperty -Path $fullpath -Name DisplayName -Value $DisplayName -PropertyType String
    New-ItemProperty -Path $fullpath -Name DisplayVersion -Value $DisplayVersion -PropertyType String
    New-ItemProperty -Path $fullpath -Name InstallLocation -Value $InstallLocation -PropertyType String
    New-ItemProperty -Path $fullpath -Name UninstallString -Value $UninstallString -PropertyType String

    New-ItemProperty -Path $fullpath -Name Contact -Value $Contact -PropertyType String
    New-ItemProperty -Path $fullpath -Name HelpLink -Value $HelpLink -PropertyType String
    New-ItemProperty -Path $fullpath -Name Readme -Value $Readme -PropertyType String
    New-ItemProperty -Path $fullpath -Name UrlInfoAbout -Value $UrlInfoAbout -PropertyType String
    New-ItemProperty -Path $fullpath -Name UrlUpdateInfo -Value $UrlUpdateInfo -PropertyType String
    New-ItemProperty -Path $fullpath -Name DisplayIcon -Value $DisplayIcon -PropertyType String
    New-ItemProperty -Path $fullpath -Name NoModify -Value $NoModify -PropertyType DWord
    New-ItemProperty -Path $fullpath -Name NoRepair -Value $NoRepair -PropertyType DWord
    New-ItemProperty -Path $fullpath -Name Publisher -Value $Publisher -PropertyType String
} catch {
    echo "Windows Programs and Features setup failed."
    DumpException($_.Exception)
    Exit 7
}
