Greyhound.psm1

function Get-GreyhoundInstallPath {
    try {
        $GreyhoundInstallPath = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Greyhound' -Name InstallLocation -ErrorAction SilentlyContinue).InstallLocation
        if (($GreyhoundInstallPath) -and (Test-Path $GreyhoundInstallPath)) {
            $GreyhoundInstallPath
        }
    }
    catch {
        Write-Error $($PSItem.ToString())
    }
}



function Get-MariaDBInstallPath {
    try {
        $MariaDBInstallPath = (Get-ChildItem "$Env:ProgramFiles\Maria*").FullName
        if (($MariaDBInstallPath) -and (Test-Path $MariaDBInstallPath)) {
            $MariaDBInstallPath
        }
    }
    catch {
        Write-Error $($PSItem.ToString())
    }
}



<#
.SYNOPSIS
    Ermittelt die Version der GREYHOUND-Installation
.DESCRIPTION
    Ermittelt die Version der GREYHOUND-Installation
.EXAMPLE
    Example of how to use this cmdlet
#>

function Get-GreyhoundVersionInfo {
    $GreyhoundServerExe = (Get-GreyhoundInstallPath) + 'Server\GreyhoundServer.exe'
    if (Test-Path -Path $GreyhoundServerExe) {
        $Version = (Get-Item $GreyhoundServerExe).VersionInfo.ProductVersionRaw
        $Version
    } else {
        Write-Error "GREYHOUND ist nicht installiert." -Category ObjectNotFound
        Break
    }
}



function Invoke-GreyhoundAdmin {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false)]
        [Switch]$Start,
        [Switch]$Stop
    )
   
    try {
        $GreyhoundAdmin = (Get-GreyhoundInstallPath) + 'Server\GreyhoundAdmin.exe'
        if (!(Test-Path $GreyhoundAdmin)) {
            Throw "Der GREYHOUND Admin wurde nicht gefunden."
        }

        if ($Start) {
            if ((Start-Process -FilePath "$GreyhoundAdmin" -ArgumentList "-Start -NoGui" -Wait -NoNewWindow -PassThru).Exitcode -gt 0) {
                Throw "Der GREYHOUND Admin hat einen ExitCode ausgegeben"
            }
        } elseif ($Stop) {
            if ((Start-Process -FilePath "$GreyhoundAdmin" -ArgumentList "-Stop -NoGui" -Wait -NoNewWindow -PassThru).Exitcode -gt 0) {
                Throw "Der GREYHOUND Admin hat einen ExitCode ausgegeben"
            }
        }

    }
    catch {
        Write-Host $($PSItem.ToString())
    }
}



function Restart-GreyhoundServer {
    Invoke-GreyhoundAdmin -Stop
    Invoke-GreyhoundAdmin -Start
}



function Get-GreyhoundSystemPassword {
    $GreyhoundServerIni = (Get-GreyhoundInstallPath) + 'Server\GreyhoundServer.ini'
    if (Test-Path $GreyhoundServerIni) {
        $GreyhoundSystemPassword = (Get-Content $GreyhoundServerIni | Select-String -Pattern 'SystemPassword' -SimpleMatch | ConvertFrom-StringData).SystemPassword
        $GreyhoundSystemPassword
    } else {
        Write-Host 'Die GREYHOUND Serverkonfiguration ´"' $GreyhoundServerIni '´" wurde nicht gefunden.'
    }
}


<#
.SYNOPSIS
    Zeigt die Einstellungen des GREYHOUND-Servers an
.DESCRIPTION
    Ohne Parameter liefert dieses Cmdlet alle Werte der GreyhoundServer.ini. Wird nur ein bestimmter Wert benötigt, so kann dieser explizit ueber den Key angegeben werden.
#>

function Get-GreyhoundServerIniValue {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false)]
        [String]$Key,
        [Parameter(ParameterSetName='MySQL')]
        [String]$Compression,
        [ValidateSet('MySQL', 'Global', 'LogFile', 'HtmlInline', 'IndexServer', 'AppServer', 'QueueServer',
            'AntiSpam', 'OCR', 'AccessServer', 'DataExchangeServer', 'SyncServer', 'AddOnServer', 'ItemCount',
            'CommServer', 'AutoClassificationServer')][String]$Section
    )

    $GreyhoundServerIni = (Get-GreyhoundInstallPath) + 'Server\GreyhoundServer.ini'
    if (Test-Path $GreyhoundServerIni) {
        if (!$Key) {
            $Result = Get-Content $GreyhoundServerIni
        } else {
            $Result = (Get-Content $GreyhoundServerIni | Select-String "^$Key=" | ConvertFrom-StringData).$Key
        }
        $Result
    } else {
        Write-Host 'Die GREYHOUND Serverkonfiguration ´"' $GreyhoundServerIni '´" wurde nicht gefunden.'
    }
}


<#
.SYNOPSIS
    Erstellt eine neue VM fuer die Einrichtung einer neuen GREYHOUND Installation
.DESCRIPTION
    Erstellt eine neue VM fuer die Einrichtung einer neuen GREYHOUND Installation. Dabei wird der erste verfügbare VMSwitch vom Typ "Extern" verwendet. Optional kann eine bereits bestehende VHD angegeben werden. Fehlt dieser Angabe, dann wird eine neue VHD erzeugt.
    Nach der Erstellung werden die Daten der VM in ein eigenes Verzeichnis unterhalb des Standard-Pfades des VMHost verschoben, sodass alle Dateien beisammen sind.
#>

function New-GreyhoundVM {
    [CmdletBinding()]
    Param (
        # Just some help
        [Parameter(Mandatory=$true)]
        [String]$VmName,

        [Parameter(Mandatory=$false)]
        [String]$VmNotes,
        [String]$VmSwitchName=(Get-VMSwitch | Where-Object SwitchType -eq External)[0].Name,
        [Int64]$VmVHDSize=64GB,
        [String]$VHDPath,
        [String]$VmBasePath= (Get-VMHost).VirtualMachinePath + '\' + $VmName,
        [Int]$VmGeneration=2,
        [Int]$VMProcessorCount=4,
        [Int64]$VmMemoryStartupBytes=4GB,
        [Int64]$VmMemoryMinimumBytes=4GB,
        [Int64]$VMMemoryMaximumBytes=8GB
    )

    try {   
        if (!($VmSwitchName)) {
            $VmSwitches = Get-VMSwitch | Where-Object SwitchType -eq External
            if ($VmSwitches.Count -eq 0) {
                Throw "Es wurde kein virtueller Switch gefunden."
            } elseif ($VmSwitches.Count -eq 1) {
                $VmSwitchName = $VmSwitches[0].Name
            } elseif ($VmSwitches.Count -gt 1) {
                Write-Warning "Es sind mehrere virtuelle Switches vorhanden. Bitte einen auswaehlen."
                Break
            }
        }

        if (!$VHDPath) {
            # Vm mit neuer VHD erstellen falls keine VHD angegeben wurde
            $VHDPath = $VmName + '_C' + '.vhdx'
            New-VM -Name $VmName -Generation $VmGeneration -SwitchName $VmSwitchName -NewVHDPath $VHDPath -NewVHDSizeBytes $VmVHDSize |
                Set-VM -ProcessorCount $VMProcessorCount -DynamicMemory -MemoryStartupBytes $VmMemoryStartupBytes -MemoryMinimumBytes $VmMemoryMinimumBytes -MemoryMaximumBytes $VMMemoryMaximumBytes -Notes $VmNotes -Passthru |
                Move-VMStorage -DestinationStoragePath $VmBasePath

        } else {
            # Vm mit angegebener VHD erstellen
            if (Test-Path $VHDPath) {
                New-VM -Name $VmName -Generation $VmGeneration -SwitchName $VmSwitchName -VHDPath $VHDPath |
                    Set-VM -ProcessorCount $VMProcessorCount -DynamicMemory -MemoryStartupBytes $VmMemoryStartupBytes -MemoryMinimumBytes $VmMemoryMinimumBytes -MemoryMaximumBytes $VMMemoryMaximumBytes -Notes $VmNotes -Passthru |
                    Move-VMStorage -DestinationStoragePath $VmBasePath
            } else {
                Write-Error 'Der Pfad zur VHD-Datei ist ungültig.'
            }
        }

        # Add Windows Iso
        #Add-VMDvdDrive -VMName $VmName -Path C:\Hyper-V\_ISOs\14393.0.161119-1705.RS1_REFRESH_SERVER_EVAL_X64FRE_DE-DE.ISO-updated.iso

        # Change boot order to boot from windows iso
        #Set-VMFirmware -VMName $VmName -FirstBootDevice (Get-VMDvdDrive -VMName $VmName)
    }
    catch {
        Write-Host $($PSItem.ToString())
    }

}

<#
.SYNOPSIS
    Laedt die aktuell empfohlene Version von MariaDB fuer eine GREYHOUND Serverinstallation herunter.
.DESCRIPTION
    Laedt die aktuell empfohlene Version von MariaDB fuer eine GREYHOUND Serverinstallation herunter.
#>


function Get-MariaDBSetup {
    [CmdletBinding()]
    param (
        [string]$DownloadDir=$PWD.Path,
        [string]$BaseUrl = 'https://greyhound-software.com/files/greyhound',
        [string]$SetupName = 'MariaDBSetup.msi'
    )

    try {
        $RemoteFile = $RemoteFile = "$BaseUrl/$SetupName"
        $LocalFile = $DownloadDir.TrimEnd('\') + '\' + $SetupName

        if (Test-Path $LocalFile) {
            [Int64]$RemoteFileSize = (Invoke-WebRequest -Uri $RemoteFile -Method Head -UseBasicParsing).Headers.'Content-Length'
            [Int64]$LocalFileSize = (Get-Item $LocalFile).Length

            Write-Verbose "LocalFileSize: $LocalFileSize RemoteFileSize: $RemoteFileSize"

            if ($RemoteFileSize -gt 0 -and $LocalFileSize -gt 0) {
                if ($RemoteFileSize -ne $LocalFileSize) {
                    Start-BitsTransfer -Source $RemoteFile -Destination $LocalFile -Description "Downloading $RemoteFile"
                } else {
                    Write-Host "Die Datei `"$SetupName`" mit einer Dateigroesse von $RemoteFileSize Bytes existiert bereits."
                }
            } else {
                Throw "Es ist ein Fehler beim Dateigroessenvergleich aufgetreten."
            }
        } else {
            Start-BitsTransfer -Source $RemoteFile -Destination $LocalFile -Description "Downloading $RemoteFile"
        }

        if (Test-Path $LocalFile) {
            $LocalFile
        } else {
            Throw "Es ist ein Fehler beim Herunterladen der Datei '$RemoteFile' aufgetreten."
        }
    }
    catch {
        Write-Error $($PSItem.ToString()) -Category ObjectNotFound
    } 
}



<#
.SYNOPSIS
    Laedt die aktuelle Version des GREYHOUND Setups von den GREYHOUND Servern herunter.
.DESCRIPTION
    Laedt die aktuelle Version des GREYHOUND Setups von den GREYHOUND Servern herunter. Dabei kann der Release-Zweig mit angegeben werden.
#>

function Get-GreyhoundServerSetup {
    [CmdletBinding()]
    param (
        [string]$DownloadDir=$PWD.Path,
        [string]$BaseUrl = 'https://greyhound-software.com/files/greyhound',
        [string]$SetupBaseName = 'GreyhoundSetup',
        [switch]$Beta,
        [switch]$Test
    )

    try {
        if ($Beta) {
            $SetupName = "${SetupBaseName}Beta.exe"
        } elseif ($Test) {
            $SetupName = "${SetupBaseName}Test.exe"
        } else {
            $SetupName = "${SetupBaseName}.exe"
        }
    
        $RemoteFile = "$BaseUrl/$SetupName"
        $LocalFile = $DownloadDir.TrimEnd('\') + '\' + $SetupName
    
        if (Test-Path $LocalFile) {
            [Int64]$RemoteFileSize = (Invoke-WebRequest -Uri $RemoteFile -Method Head -UseBasicParsing).Headers.'Content-Length'
            [Int64]$LocalFileSize = (Get-Item $LocalFile).Length

            Write-Verbose "LocalFileSize: $LocalFileSize RemoteFileSize: $RemoteFileSize"
   
            if ($RemoteFileSize -gt 0 -and $LocalFileSize -gt 0) {
                if ($RemoteFileSize -ne $LocalFileSize) {
                    Start-BitsTransfer -Source $RemoteFile -Destination $LocalFile -Description "Downloading $RemoteFile"
                } else {
                    Write-Verbose "Die Datei `"$SetupName`" mit einer Dateigroesse von $RemoteFileSize Bytes existiert bereits."
                }
            } else {
                Throw "Es ist ein Fehler beim Dateigroessenvergleich aufgetreten."
            }
        } else {
            Start-BitsTransfer -Source $RemoteFile -Destination $LocalFile -Description "Downloading $RemoteFile"
        }
    
        if (Test-Path $LocalFile) {
            $LocalFile
        } else {
            Throw "Es ist ein Fehler beim Herunterladen der Datei '$RemoteFile' aufgetreten."
        }
           
    }
    catch {
        Write-Error $($PSItem.ToString()) -Category ObjectNotFound
    }
    
}



<#
.SYNOPSIS
    Installiert MariaDB in einer Silent-Installation
.DESCRIPTION
    Installiert MariaDB in einer Silent-Installation. Die Setupdatei kann auch via Pipeline in Kombination mit Get-MariaDBSetup verwendet werden.
.EXAMPLE
    Get-MariaDBSetup | Install-MariaDBSetup -Password 'MyRootPassword'
#>

function Install-MariaDB {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$SetupFile,
        [Parameter(Mandatory=$false)]
        [String]$ServiceName='MySql',
        [Boolean]$AllowRemoteRootAccess,
        [Boolean]$SkipNetworking,
        [String]$Password
    )

    $SetupFile = Resolve-Path($SetupFile)
    if (!(Test-Path -Path $SetupFile)) {
        Write-Error "Die Datei '$SetupFile' wurde nicht gefunden." -Category ObjectNotFound
        Break
    }

    $Command = (Get-Command 'msiexec').Path
    $Arguments = @(
        "/package",
        "`"$SetupFile`"",
        "SERVICENAME=$ServiceName",
        "/qn"
    )

    if ($Password) {
        $Arguments += @("PASSWORD=$Password")
    }

    if ($AllowRemoteRootAccess) {
        $Arguments += @("ALLOWREMOTEROOTACCESS=True")
    } else {
        $Arguments += @("ALLOWREMOTEROOTACCESS=False")
    }

    Write-Host 'Die Datei' $SetupFile 'wird installiert...'

    try {
        $CommandBasename = $Command.Substring($Command.LastIndexOf('\') + 1, $Command.LastIndexOf('.') - $Command.LastIndexOf('\') - 1)
        $StdOutFile = "$env:TEMP\$CommandBasename.stdout"
        $StdErrFile = "$env:TEMP\$CommandBasename.stderr"

        if ((Start-Process -FilePath "$Command" -ArgumentList "$Arguments" -RedirectStandardOutput $StdOutFile -RedirectStandardError $StdErrFile -Wait -PassThru).ExitCode -eq 0) {
            Get-Content $StdOutFile
        } else {
            (Get-Content $StdErrFile)
            Throw "Es ist ein Fehler bei der Installation aufgetreten. StdOut: " + (Get-Content $StdErrFile)
        }
    } catch {
        Write-Error "Es ist ein Fehler bei der Ausführung des Befehls '$Command $Arguments' aufgetreten: $($PSItem.ToString())"
    }
    finally {
        Remove-Item $StdOutFile -Force -ErrorAction SilentlyContinue
        Remove-Item $StdErrFile -Force -ErrorAction SilentlyContinue 
    }
}



<#
.SYNOPSIS
    Installiert GREYHOUND in einer Silent-Installation
.DESCRIPTION
    Installiert GREYHOUND in einer Silent-Installation. Die Setupdatei kann auch via Pipeline in Kombination mit Get-GreyhoundServerSetup verwendet werden. Saemtliche Optionen des GUI-Setups können in diesem Cmdlet als Parameter übergeben werden.
    Für eine Serverinstallation sind die Angaben einer Vertragsnummer und einer Seriennummer obligatorisch.
.EXAMPLE
    GreyhoundServerSetup | Install-GreyhoundServer
#>

function Install-GreyhoundServer {
    [CmdletBinding()]
    [Alias("Update-GreyhoundServer")]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$SetupFile,
        [Parameter(Mandatory=$false)]
        [String]$ContractNumber,
        [String]$SerialNumber,
        [ValidateSet('Complete', 'Server', 'Client')][String]$Kind='Server',
        [String]$TargetDir="${env:ProgramFiles(x86)}\GREYHOUND\",
        [Switch]$DesktopShortcut=$false,
        [Switch]$StartMenuShortcut=$false,
        [Switch]$QuicklaunchShortcut=$false,
        [Switch]$DefaultMailClient=$false,
        [Switch]$PrinterDriver=$false,
        [Switch]$NoStart=$false,
        [String]$DatabaseUser='root',
        [String]$DatabasePass,
        [int16]$DatabasePort=3306,
        [ValidateSet('Small', 'Medium', 'Large')][String]$DatabaseTemlate='Large',
        [String]$AdminPassword='admin',
        [Switch]$Force=$false
    )

    try {
        $SetupMode = ''

        $SetupFile = Resolve-Path($SetupFile)
        Write-Verbose "Das Setup `"$SetupFile`" wird ausgefuehrt."
        if (Test-Path -Path $SetupFile) {
            $Command = $SetupFile
        } else {
            Write-Error "Die Datei '$SetupFile' wurde nicht gefunden." -Category ObjectNotFound
            Break
        }

        if (!($Force) -and (Get-GreyhoundInstallPath)) {
            $SetupMode = 'Update'
            try {
                $InstalledVersion = Get-GreyhoundVersionInfo
                $SetupVersion = (Get-Item $SetupFile).VersionInfo.ProductVersionRaw

                if ($InstalledVersion -gt $SetupVersion) {
                    Write-Host "Die installierte GREYHOUND-Version $InstalledVersion ist neuer als die Installationsdatei $SetupVersion." 
                    if (!($Force)) {
                        Break
                    }
                } elseif ($InstalledVersion -eq $SetupVersion) {
                    Write-Host "GREYHOUND Version $InstalledVersion ist bereits installiert." 
                    if (!($Force)) {
                        Break
                    }
                } else {
                    Write-Verbose "Die Installationsdatei $SetupVersion hat eine neuere Version als die installierte GREYHOUND-Version $InstalledVersion."
                }
    
                [String]$ContractNumber = Get-GreyhoundServerIniValue -Key 'ContractNumber'
                [String]$SerialNumber = Get-GreyhoundServerIniValue -Key 'Serial'

                Write-Verbose "Aktuelle Vertragsnummer: $ContractNumber"
                Write-Verbose "Aktuelle Seriennummer: $SerialNumber"
    
                $Arguments = @(
                    "-silent",
                    "-contract", "`"$ContractNumber`"",
                    "-serial", "`"$SerialNumber`"",
                    "-kind", "$Kind"
                )                  
            }
            catch {
                Write-Error "Es ist ein Fehler bei der Versionsermittlung aufgetreten."
            }
        } else {
            $SetupMode = 'Install'
            $Arguments = @(
                "-silent",
                "-contract", "`"$ContractNumber`"",
                "-serial", "`"$SerialNumber`"",
                "-kind", "$Kind",
                "-targetdir", "`"$TargetDir`"",
                "-databaseuser", "$DatabaseUser",
                "-databaseport", "$DatabasePort"
                "-databasetemplate", "$DatabaseTemlate",
                "-adminpassword", "$AdminPassword"
            )

            if ($DatabasePass) {
                $Arguments += @("-databasepass", "$DatabasePass")
            }
        
            if ($NoStart) {
                $Arguments += @("-nostart")
            }

            if (!$DesktopShortcut) {
                $Arguments += @("-nodesktop")
            }

            if (!$StartMenuShortcut) {
                $Arguments += @("-nostartmenu")
            }

            if (!$QuicklaunchShortcut) {
                $Arguments += @("-noquicklaunch")
            }

            if (!$DefaultMailClient) {
                $Arguments += @("-nodefaultmail")
            }

            if (!$PrinterDriver) {
                $Arguments += @("-noprinterdriver")
            }
        }

        if ($ContractNumber -and $SerialNumber) {
            if ($SetupMode -eq 'Install') {
                Write-Host "GREYHOUND Version $SetupVersion wird installiert..."
                Write-Verbose "Zielverzeichnis: `"$TargetDir`""
            } else {
                $VersionInstalled = (Get-GreyhoundVersionInfo).ToString()
                Write-Host "Die GREYHOUND-Installation wird von Version $VersionInstalled auf Version $SetupVersion aktualisiert..."
            }
            if ((Start-Process -FilePath "$Command" -ArgumentList "$Arguments" -Wait -PassThru).ExitCode -eq 0) {
                Write-Host "Die GREYHOUND-Installation war erfolgreich."
            } else {
                Throw "Das GREYHOUND-Setup hat einen unbekannten Fehler gemeldet."
            }
        } else {
            Write-Error "Fuer eine Installation oder ein Update sind eine Vertragsnummer und eine Seriennummer notwendig." -Category NotSpecified
            Break
        }
    }
    catch {
        Write-Error "Es ist ein Fehler bei der GREYHOUND-Installation aufgetreten: $($PSItem.ToString())"
    }
}



function Uninstall-GreyhoundServer {
    $GreyhoundSetupExe = (Get-GreyhoundInstallPath) + 'GreyhoundSetup.exe'
    if (Test-Path -Path $GreyhoundSetupExe) {
        Write-Host "GREYHOUND wird deinstalliert..."
        if ((Start-Process -FilePath "$GreyhoundSetupExe" -ArgumentList '-uninstall -useregistry -silent' -Wait -NoNewWindow -PassThru).ExitCode -eq 0) {
            Write-Host "GREYHOUND wurde erfolgreich deinstalliert."
        } else {
            Throw "Das GREYHOUND-Setup hat einen unbekannten Fehler gemeldet."
        }
    } else {
        Write-Error "Die Datei `"$GreyhoundSetupExe`" ist nicht vorhanden." -Category ObjectNotFound
        Break
    }
}



<#
.SYNOPSIS
    Erstellt einen Dump der GREYHOUND Datenbank
.DESCRIPTION
    Erstellt einen Dump der GREYHOUND Datenbank. Optional kann dieser direkt komprimiert werden.
#>

function New-GreyhoundDatabaseDump {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false,
        ValueFromPipeline)]
        [string]$MySqlUser='root',
        [string]$MySqlPassword='',
        [string]$MySqlParameters='--default-character-set=latin1',
        [string]$MySqlDatabase='greyhound',
        [switch]$Compress,
        [string]$DestinationPath=$PWD.Path
    )

    $MySqlInstallPath = (Get-ChildItem 'C:\Program Files\Maria*').FullName
    $MySqlDump= $MySqlInstallPath + '\bin\mysqldump.exe'
    $StdErr = $env:TEMP + '\mysql.stderr'
        
    if (!(Test-Path -Path $MySqlDump)) {
        Write-Warning 'Die Exe-Datei' $MySqlDump 'wurde nicht gefunden.'
        Break
    }

    $MySqlDumpArgs = @(
        "--user=$MySqlUser"
    )

    if ($MySqlPassword) {
        $MySqlDumpArgs += @(
            "--password=$MySqlPassword"
        )
    }
    
    $MySqlDumpArgs += @(
        "--default-character-set=latin1",
        "$MySqlDatabase"
    )

    try {
        [string]$SqlFile = $DestinationPath + '\' + $MySqlDatabase + '.sql'
        if ((Start-Process -FilePath $MySqlDump -ArgumentList $MySqlDumpArgs -RedirectStandardOutput $SqlFile -RedirectStandardError $StdErr -Wait -NoNewWindow -PassThru).Exitcode -gt 0) {
            if (Test-Path -Path $StdErr) {
                $ExceptionText = Get-Content $StdErr
                Remove-Item $StdErr
            }
            Throw $ExceptionText
        } else {
            Write-Host $SqlFile
        }
    }
    catch {
        Write-Host $($PSItem.ToString())
        Remove-Item $SqlFile
        Break 
    }

    if ($Compress) {
        if (Test-Path -Path $SqlFile) {
            $Zip = (Get-Item  $SqlFile).DirectoryName + '\' + (Get-Item  $SqlFile).BaseName + '.zip'
            if (Test-Path -Path $Zip) {
                Remove-Item $Zip
            }
            
            try {
                Write-Verbose "Der Datenbank-Dump wird komprimiert. Ziel: $Zip"
                Compress-Archive -Path $SqlFile -DestinationPath $Zip -CompressionLevel Optimal
            }
            catch {
                Write-Error "Es ist ein Fehler beim Komprimieren des Datenbank-Dumps aufgetreten."
            }
            finally {
                Write-Verbose "Die Datei $SqlFile wird gelöscht."
                Remove-Item $SqlFile 
            }

        } else {
            Write-Warning "Die Datenbank-Datei $SqlFile konnte nicht komprimiert werden, weil sie nicht vorhanden ist."
        }
    }
}



<#
.SYNOPSIS
    Fuert beliebige Sql-Abfragen aus.
.DESCRIPTION
    Dieses Cmdlet ist ein Wrapper für mysql.exe einer bestehenden MySQL- oder MariaDB-Installation. Die gewuenschte Abfrage kann als Parameter übergeben werden. Die Ausgabe von mysql.exe wird in der Konsole ausgegen.
#>

function Invoke-MySqlQuery {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]$MySqlQuery,
        [Parameter(Mandatory=$false)]
        [string]$MySqlHostname='localhost',
        [string]$MySqlUser='root',
        [string]$MySqlPass=''
    )

    $MySqlInstallPath = (Get-ChildItem 'C:\Program Files\Maria*').FullName
    $Exe = $MySqlInstallPath + '\bin\mysql.exe'
    
    if (!(Test-Path -Path $Exe)) {
        Write-Warning 'Die Exe-Datei' $Exe 'wurde nicht gefunden.'
        Break
    }

    $Arguments = @(
        "--host=$MySqlHostname"
        "--user=$MySqlUser"
        '--execute="' + $MySqlQuery + '"'
    )

    if ($MySqlPass) {
        $Arguments += @(
            "--password=$MySqlPass"
        )
    }
    
    try {
        $ExeBasename = $Exe.Substring($Exe.LastIndexOf('\') + 1, $Exe.LastIndexOf('.') - $Exe.LastIndexOf('\') - 1)
        $StdOut = $env:TEMP + '\' + $ExeBasename + '.stdout'
        $StdErr = $env:TEMP + '\' + $ExeBasename + '.stderr'
    
        Start-Process -FilePath "$Exe" -ArgumentList "$Arguments" -NoNewWindow -Wait -RedirectStandardOutput $StdOut -RedirectStandardError $StdErr
        if (Test-Path -Path $StdOut) {
            Get-Content $StdOut
        }
        if (Test-Path -Path $StdErr) {
            Get-Content $StdErr
        }           
    }
    finally {
        Remove-Item $StdOut -Force
        Remove-Item $StdErr -Force      
    }
}



<#
.SYNOPSIS
    Zeigt das letzte Logfile einer GREYHOUND Serverinstalltion an.
.DESCRIPTION
    Zeigt das letzte Logfile einer GREYHOUND Serverinstalltion an.
#>

function Get-GreyhoundLog {
    try {
        $Logfile = Get-ChildItem((Get-GreyhoundInstallPath) + '\Server\Logs\') | Select-Object -Last 1
        Get-Content $Logfile.FullName
    }
    catch {
        Write-Host $($PSItem.ToString())
    }    
}



<#
.SYNOPSIS
    Loescht die aktuelle GREYHOUND Datenbank
.DESCRIPTION
    Loescht die aktuelle GREYHOUND Datenbank, sodass eine neue, leere Datenbank beim naechsten GREYHOUND Serverstart erstellt wird. Die Dateien im GREYHOUND Data-Verzeichnis werden dabei nicht gelöscht
#>

function Reset-GreyhoundDatabase {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false,
        ValueFromPipeline)]
        [string]$MySqlHostname='localhost',
        [string]$MySqlUser='root',
        [string]$MySqlPass=''
    )
    try {
        $PrevGreyhoundServerStatus = ((Get-Service GreyhoundService).Status)

        Invoke-GreyhoundAdmin -Stop
        if (((Get-Service GreyhoundService).Status) -eq 'Stopped') {
            $MySqlQuery = 'DROP DATABASE greyhound;'
            Invoke-MySqlQuery -MySqlQuery $MySqlQuery -MySqlHostname $MySqlHostname -MySqlUser $MySqlUser -MySqlPass $MySqlPass
        } else {
            Throw "Der GREYHOUND-Dienst konnte nicht gestoppt werden."
        }

        if ($PrevGreyhoundServerStatus -eq 'Running') {
            Invoke-GreyhoundAdmin -Start
            if (((Get-Service GreyhoundService).Status) -ne 'Running') {
                Throw "Der GREYHOUND-Dienst konnte nicht gestartet werden."
            }
        }
    }
    catch {
        Write-Host $($PSItem.ToString())
    }
}



<#
.SYNOPSIS
    Konfiguriert perfekte Windows-Defender-Ausnahmen fuer den GREYHOUND-Serverbetrieb
.DESCRIPTION
    Konfiguriert perfekte Windows-Defender-Ausnahmen fuer den GREYHOUND-Serverbetrieb. Vorhandene Einstellungen werden dabei nicht gelöscht.
#>

function Add-GreyhoundDefenderPreference {
    try {
        $GreyhoundInstallPath = (Get-GreyhoundInstallPath).TrimEnd('\')
        $MySqlInstallPath = ((Get-ChildItem "${env:ProgramFiles}\Maria*" -Directory).FullName).TrimEnd('\')

        if ($GreyhoundInstallPath) {
            if ($MySqlInstallPath) {
                Add-MpPreference `
                -ExclusionProcess ("$GreyhoundInstallPath\Server\*", "$GreyhoundInstallPath\Server\Plugins\*", "$MySqlInstallPath\*") `
                -ExclusionPath ("$GreyhoundInstallPath\Server", "$MySqlInstallPath\data")
            } else {
                Throw Der MariaDB-Installationspfad wurde nicht gefunden.
            }
        } else {
            Throw Der GREYHOUND-Installationspfad wurde nicht gefunden.
        }
    } catch {
        Write-Host $($PSItem.ToString())
    }
}



<#
.SYNOPSIS
    Entfernt eine vorhandene MySql-Tabellenpartitionierung einer GREYHOUND 5-Installation
.DESCRIPTION
    Entfernt eine vorhandene MySql-Tabellenpartitionierung einer GREYHOUND 5-Installation und stellt die notwendigen Indizes wieder her. Dieses Cmdlet macht die Aenderungen von New-GreyhoundDatabasePartitioning wieder rueckgaengig.
#>

function Remove-GreyhoundDatabasePartitioning {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false,
        ValueFromPipeline)]
        [string]$MySqlHostname='localhost',
        [string]$MySqlUser='root',
        [string]$MySqlPass=''
    )
    try {
        # Auf Partitionierung prüfen
        $Path = (Get-MariaDBInstallPath) + '\Data\greyhound'
        Write-Verbose "GREYHOUND Datenbank-Pfad: $Path"

        if (($Path) -and (Test-Path $Path) -and (Get-ChildItem -Path $Path -Filter 'items#*')) {
            Write-Verbose "GREYHOUND Dienst wird gestoppt..."
            $PrevGreyhoundServerStatus = ((Get-Service GreyhoundService).Status)

            Invoke-GreyhoundAdmin -Stop -Verbose
            if (((Get-Service GreyhoundService).Status) -eq 'Stopped') {
                $MySqlQuery =  @'
USE greyhound;
ALTER TABLE `items` REMOVE PARTITIONING;
ALTER TABLE `items` CHANGE `e_state` `e_state` enum('open','new','question','answer','done','forward','draft','rejected') DEFAULT 'open' NOT NULL;
ALTER TABLE `items` CHANGE `e_kind` `e_kind` enum('email','fax','letter','shortmessage','call','appointment','task','note','contact','file') DEFAULT 'email' NOT NULL;
ALTER TABLE `items` ADD INDEX `e_kind` (`e_kind`);
ALTER TABLE `items` ADD INDEX `e_state` (`e_state`);
ALTER TABLE `items` DROP INDEX `PRIMARY`, ADD PRIMARY KEY(`i_id`);
'@

                Write-Verbose "Die MySQL-Abfrage wird ausgefuehrt: $MySqlQuery"
                Invoke-MySqlQuery -MySqlQuery $MySqlQuery -MySqlHostname $MySqlHostname -MySqlUser $MySqlUser -MySqlPass $MySqlPass -Verbose
            } else {
                Throw "Der GREYHOUND-Dienst konnte nicht gestoppt werden."
            }

            if ($PrevGreyhoundServerStatus -eq 'Running') {
                Write-Verbose "GREYHOUND Dienst wird gestartet..."
                Invoke-GreyhoundAdmin -Start
                if (((Get-Service GreyhoundService).Status) -ne 'Running') {
                    Throw "Der GREYHOUND-Dienst konnte nicht gestartet werden."
                }
            }
        } else {
            Write-Host "Die GREYHOUND-Datenbank ist nicht partitioniert. Keine Aktion erforderlich."
        }
    }
    catch {
        Write-Host $($PSItem.ToString())
    }
}



function New-GreyhoundDatabasePartitioning {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false,
        ValueFromPipeline)]
        [string]$MySqlHostname='localhost',
        [string]$MySqlUser='root',
        [string]$MySqlPass=''
    )
    try {
        # Auf Partitionierung prüfen
        $Path = (Get-MariaDBInstallPath) + '\Data\greyhound'
        Write-Verbose "GREYHOUND Datenbank-Pfad: $Path"

        if (($Path) -and (Test-Path $Path) -and (!(Get-ChildItem -Path $Path -Filter 'items#*'))) {
            Write-Verbose "GREYHOUND Dienst wird gestoppt..."
            $PrevGreyhoundServerStatus = ((Get-Service GreyhoundService).Status)

            Invoke-GreyhoundAdmin -Stop -Verbose
            if (((Get-Service GreyhoundService).Status) -eq 'Stopped') {
                $MySqlQuery =  @'
USE greyhound;
ALTER TABLE items DROP INDEX e_kind, DROP INDEX e_state;
ALTER TABLE items CHANGE e_state e_state TINYINT(1) DEFAULT '1' NOT NULL;
ALTER TABLE items CHANGE e_kind e_kind TINYINT(2) DEFAULT '1' NOT NULL;
ALTER TABLE items DROP PRIMARY KEY, ADD PRIMARY KEY (i_id, e_state, e_kind);
ALTER TABLE items
PARTITION BY LIST(e_state)
SUBPARTITION BY HASH(e_kind)
SUBPARTITIONS 10 (PARTITION isOpen VALUES IN (1), PARTITION isNew VALUES IN (2), PARTITION isQuestion VALUES IN (3), PARTITION isAnswer VALUES IN (4), PARTITION isDone VALUES IN (5), PARTITION isForward VALUES IN (6),
PARTITION isDraft VALUES IN (7),
PARTITION isRejected VALUES IN (8)
);
'@

                Write-Verbose "Die MySQL-Abfrage wird ausgefuehrt: $MySqlQuery"
                Invoke-MySqlQuery -MySqlQuery $MySqlQuery -MySqlHostname $MySqlHostname -MySqlUser $MySqlUser -MySqlPass $MySqlPass -Verbose
            } else {
                Throw "Der GREYHOUND-Dienst konnte nicht gestoppt werden."
            }

            if ($PrevGreyhoundServerStatus -eq 'Running') {
                Write-Verbose "GREYHOUND Dienst wird gestartet..."
                Invoke-GreyhoundAdmin -Start
                if (((Get-Service GreyhoundService).Status) -ne 'Running') {
                    Throw "Der GREYHOUND-Dienst konnte nicht gestartet werden."
                }
            }
        } else {
            Write-Host "Die GREYHOUND-Datenbank ist bereits partitioniert. Keine Aktion erforderlich."
        }
    }
    catch {
        Write-Host $($PSItem.ToString())
    }
}