Greyhound.psm1

function Get-GreyhoundInstallLocation {
    $GreyhoundInstallLocation = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Greyhound' -Name InstallLocation).InstallLocation
    if (Test-Path $GreyhoundInstallLocation) {
        $GreyhoundInstallLocation
    } else {
        Write-Host 'Es wurde kein Installationspfad für GREYHOUND gefunden.'
    } 
}


function Stop-GreyhoundServer {
    $GreyhoundAdmin = (Get-GreyhoundInstallLocation) + 'Server\GreyhoundAdmin.exe'
    if (Test-Path $GreyhoundAdmin) {
        Start-Process -FilePath $GreyhoundAdmin -Stop -Wait
     } else {
        Write-Host ('Der GREYHOUND Admin ist nicht installiert.')
    }
}


function Start-GreyhoundServer {
    $GreyhoundAdmin = (Get-GreyhoundInstallLocation) + 'Server\GreyhoundAdmin.exe'
    if (Test-Path $GreyhoundAdmin) {
        Start-Process -FilePath $GreyhoundAdmin -Start -Wait
     } else {
        Write-Host ('Der GREYHOUND Admin ist nicht installiert.')
    }
}


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


function Get-GreyhoundSystemPassword {
    $GreyhoundServerIni = (Get-GreyhoundInstallLocation) + '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.'
    }
}



function Get-GreyhoundServerValue {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$Key
    )

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


function Get-GreyhoundServerInfo {
<#
.SYNOPSIS
    Gets information from the GREYHOUND Server
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
#>


[CmdletBinding(DefaultParameterSetName='Parameter Set 1'
    )]

    Param (
        [Parameter(
        Mandatory=$false,
        ParameterSetName='Parameter Set 1')]


        [Parameter(
        Mandatory=$false,
        ParameterSetName='Parameter Set 2')]

        [string]$Hostname = 'localhost',
        [string]$Username = 'system',
        [string]$Password = (Get-GreyhoundSystemPassword),
        [Boolean]$UseSsl = $true,
        [Int32]$Port = '443'
    )

    if ($UseSsl) {
        $GreyhoundServerUri = 'https://' + $Hostname + ':' + $Port + '/json'
    } else {
        $GreyhoundServerUri = 'http://' + $Hostname + ':' + $Port + '/json'
    }

    $ContentType    = 'application/json'
    $UserAgent      = 'PowerShell'
    $Body           = '{"version":"1.1", "method": "RpcInfo.GetServerInfo", "params": [true]}'

    $RandomStr      = (Get-Random).ToString()
    $Md5            = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $Utf8           = New-Object -TypeName System.Text.UTF8Encoding
    $ClientID       = ([System.BitConverter]::ToString($Md5.ComputeHash($Utf8.GetBytes($RandomStr)))).Replace('-', '')

    # $Username = 'system'
    # $Password = Get-GreyhoundSystemPassword
    $Authorization  = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f ($ClientID + '-' + $Username) ,$Password)))

    Write-Host @"
        "$GreyhoundServerUri" $GreyhoundServerUri
        '$RandomStr' $RandomStr
        '$Md5' $Md5
        '$Utf8' $Utf8
        '$ClientID + $Username' + ($ClientID + '-' + $Username)
        '$Authorization' + $Authorization
"@
 `
        -ForegroundColor Yellow


    #try {
        $GreyhoundResponse = Invoke-RestMethod -Method Post -UserAgent $UserAgent -ContentType $ContentType -Uri $GreyhoundServerUri -Body $Body -Headers @{Authorization=($Authorization)}

        Write-Host '$GreyhoundResponse' ($GreyhoundResponse)
        write-host '$GreyhoundResponse.Error' ($GreyhoundResponse.Error)
        Write-Host '$GreyhoundResponse.Result' ($GreyhoundResponse.Result)

        if ((!$GreyhoundResponse).Error) {
            return $GreyhoundResponse.Result
        } else {
            return $GreyhoundResponse.Error.message
        }
       $GreyhoundResult
    #} catch {
        #Write-Host 'Es ist ein Fehler bei der Abfrage des GREYHOUND Servers an' $GreyhoundServerUri 'aufgetreten.'
    #}
}


function Get-ApplianceDataXml {
<#
.SYNOPSIS
    Gets individual Appliance configuration data from GREYHOUND Control Center (GCC)
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
#>


    [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
                   SupportsShouldProcess=$true,
                   PositionalBinding=$false,
                   HelpUri = '',
                   ConfirmImpact='')]
    [Alias()]
    Param (
        # Param1 help description
        [Parameter(Mandatory=$false,
                   Position=0,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   ValueFromRemainingArguments=$false, 
                   ParameterSetName='Parameter Set 1')]
        [AllowEmptyString()]
        [string]$ApplianceKey,
        
        # Param2 help description
        [Parameter(Mandatory=$true,
                   Position=1,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   ValueFromRemainingArguments=$false)]
        [string[]]$ApplianceSerialNumbers
    )
    
    $GccUri         = 'https://greyhound-software.com/gcc/xmlrpc/'
    $ContentType    = 'application/xml'
  
    for ($i=0; $i -lt $ApplianceSerialNumbers.Count; $i++) {$SerialValues = $SerialValues + "<value>" + $ApplianceSerialNumbers[$i] + "</value> "}

    $Body           = "<?xml version=`"1.0`" encoding=`"UTF-8`"?>
    <methodCall>
        <methodName>GetApplianceData</methodName>
        <params>
            <param>
                <value>
                    <array>
                        <data>
                            "
 + $SerialValues + "
                        </data>
                    </array>
                </value>
            </param>
            <param>
                <value>
                    <string>"
 + $ApplianceKey + "</string>
                </value>
            </param>
        </params>
    </methodCall>"


    #Write-Host "`$Body = '$Body'" -ForegroundColor Yellow

    $GccResult = Invoke-RestMethod -Uri $GccUri -Method Post -Body $Body -ContentType $ContentType

    try
    {
        $FaultString = $GccResult.methodResponse.fault.value.struct.member[1].value.string
    }
    catch
    {}

    $GccValues = $GccResult.methodResponse.params.param.value.struct.member

    if (!$FaultString) {

        $NewObject = New-Object -TypeName psobject

        # Alle Daten außer ProductKeys speichern
        $GccValues | Where-Object Name -ne ProductKeys | ForEach-Object -Process {Add-Member -InputObject $NewObject -MemberType NoteProperty -Name $_.Name -Value $_.Value.InnerText -Force}

        # ProductKeys aus Array ermitteln und speichern
        $ProductKeyValues = ($GccValues | Where-Object Name -eq ProductKeys).value.array.data.value.struct.member

        Write-Host $ProductKeyValues

        if ($ProductKeyValues) {
            for ($i=0; $i -le ($ProductKeyValues | Measure-Command).Count - 1; $i++) {

                if ($ProductKeyValues.name[$i] -eq 'Name' -and $ProductKeyValues.name[$i+1] -eq 'ProductKey')

                {
                    $NewObject | Add-Member -NotePropertyName $ProductKeyValues.value[$i].string -NotePropertyValue $ProductKeyValues.value[$i+1].string
                }

            }
        } else {
            Write-Host 'Es wurden keine Productkeys gefunden.'
        }


    } else {

        Write-Host 'GCC-Antwort:' $FaultString -ForegroundColor Red
    }

return $NewObject

}


function Get-ApplianceSerialNumbers {
<#
.SYNOPSIS
    Gets the serial numbers of installed harddrives, memory chips and motherboard
.DESCRIPTION
    Long description
.EXAMPLE
    Example of how to use this cmdlet
#>


    # Seriennummern aller Laufwerke ermitteln
    Get-CimInstance CIM_DiskDrive | Select-Object SerialNumber | ForEach-Object -Process {$ApplianceSerialNumbers += @($_.SerialNumber)}
    # Seriennummern aller RAM-Chips ermitteln
    Get-CimInstance CIM_Chip | Select-Object SerialNumber | ForEach-Object -Process {$ApplianceSerialNumbers += @($_.SerialNumber)}
    # Seriennummer des Motherboards ermitteln
    Get-CimInstance CIM_BIOSElement | Select-Object SerialNumber| ForEach-Object -Process {$ApplianceSerialNumbers += @($_.SerialNumber)}

    $ApplianceSerialNumbers 
    
}


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
    )

    if (!$VHDPath) {
        # Vm mit neuer VHD erstellen falls keine VHD angegeben wurde
        $VHDPath + '.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)

}


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

    $SetupName = $SetupUrl.Substring($SetupUrl.LastIndexOf('/') + 1)
    $DestFile = $DownloadDir + '\' + $SetupName

    Start-BitsTransfer -Source $SetupUrl -Destination $DestFile -Description "Downloading $SetupName ..."

    if (Test-Path $DestFile) {
        $DestFile
    } else {
        Write-Error 'Es ist ein Fehler beim Herunterladen der Datei' + $SetupUrl + 'aufgetreten.'
    }
    
}


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"
        }
    
        $SourceFile = "$BaseUrl/$SetupName"
        $SetupFile = $DownloadDir.TrimEnd('\') + '\' + $SetupName
    
        Start-BitsTransfer -Source "$SourceFile" -Destination "$SetupFile" -Description "Downloading $SourceFile"
    
        if (Test-Path $SetupFile) {
            $SetupFile
        } else {
            Throw "Es ist ein Fehler beim Herunterladen der Datei '$SourceFile' aufgetreten."
        }
           
    }
    catch {
        Write-Error $($PSItem.ToString()) -Category ObjectNotFound
    }
    
}



function Get-GreyhoundWim {
    [CmdletBinding()]
    param (
        $Url = 'https://greyhound-software.com/files/greyhound/tools/GreyhoundServer.wim',
        $DownloadDir = $env:TEMP,
        [switch]$Force
    )

    $ImageName = $Url.Substring($Url.LastIndexOf('/') + 1)
    $ImageFile = "$DownloadDir\$ImageName"

    if (Test-Path $ImageFile) {
        if ($Force) {
            Start-BitsTransfer -Source $Url -Destination $ImageFile -Description "Downloading $ImageName ..."
        } else {
            Write-Information "Die Datei '$ImageFile' ist bereits vorhanden. -Force benutzen um diese zu überschreiben."
            Return $ImageFile
        }
    } else {
        Start-BitsTransfer -Source $Url -Destination $ImageFile -Description "Downloading $ImageName ..."
    }

    if (Test-Path $ImageFile) {
        Return $ImageFile
    } else {
        Write-Error 'Es ist ein Fehler beim Herunterladen der Datei' + $Url + 'aufgetreten.'
    }    
}




function Install-MariaDB {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$SetupFile
    )

    # Verify that setup exist
    if (!(Test-Path -Path $SetupFile)) {
        Write-Warning 'Die Setup-Datei' $SetupFile 'wurde nicht gefunden.'
        Break
    }

    $Command = 'msiexec'
    $CommandArgs = @(
        "/package",
        "`"$SetupFile`"",
        "SERVICENAME=MySql",
        "INSTALLDIR=`"$env:ProgramFiles\MariaDB`"",
        "ALLOWREMOTEROOTACCESS=True",
        "PASSWORD=root",
        "/qn"
    )

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

    Start-Process -FilePath $Command $CommandArgs -Wait
}




function Install-GreyhoundServer {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$SetupFile,
        [String]$ContractNo,
        [String]$SerialNo
    )

    # Verify that both setups exist
    if (!(Test-Path -Path $SetupFile)) {
        Write-Warning 'Die Setup-Datei' $SetupFile 'wurde nicht gefunden.'
        Break
    }

    $Command = $SetupFile
    $CommandArgs = @(
        "-silent",
        "-contract $ContractNo",
        "-serial $SerialNo",
        "-kind server",
        "-nodesktop",
        "-nostartmenu",
        "-noquicklaunch",
        "-nodefaultmail",
        "-noprinterdriver",
        "-databaseuser", "root",
        "-databasepass", "root",
        "-databasetemplate", "large",
        "-adminpassword", "admin"
    )

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

    Start-Process -FilePath $Command $CommandArgs -Wait
}



function Update-GreyhoundServer {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true,
        ValueFromPipeline)]
        [String]$SetupFile
    )

    if (!(Test-Path -Path $SetupFile)) {
        Write-Warning 'Die Setup-Datei' $SetupFile 'wurde nicht gefunden.'
        Break
    }

    [String]$ContractNo = Get-GreyhoundServerValue 'ContractNumber'
    [String]$SerialNo = Get-GreyhoundServerValue 'Serial'

    if (!($ContractNo -and $SerialNo)) {
        Write-Warning 'Fuer ein Update sind eine Vertragsnummer und eine Seriennummer notwendig.'
        Break
    }

    $Command = $SetupFile
    $CommandArgs = @(
        "-silent",
        "-contract $ContractNo",
        "-serial $SerialNo",
        "-kind server"
    )

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

    Start-Process -FilePath $Command $CommandArgs -Wait
}


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."
        }
    }
}



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

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

    $MySqlArgs = @(
        "--host=$MySqlHostname"
        "--user=$MySqlUser"
        '--execute="' + $Query + '"'
    )

    if ($MySqlPass) {
        $MySqlArgs += @(
            "--password=$MySqlPass"
        )
    }

    Start-Process -FilePath "$MySql" -ArgumentList "$MySqlArgs" -Wait -RedirectStandardOutput $StdOut -RedirectStandardError $StdErr
    if (Test-Path -Path $StdOut) {
        Get-Content $StdOut
        Remove-Item $StdOut
    }
    if (Test-Path -Path $StdErr) {
        Get-Content $StdErr
        Remove-Item $StdErr
    }
}



function Remove-GreyhoundDatabase {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$false,
        ValueFromPipeline)]
        [string]$MySqlHostname='localhost',
        [string]$MySqlUser='root',
        [string]$MySqlPass=''
    )

    $Query = 'DROP DATABASE greyhound;'

    Invoke-MySqlQuery -Query $Query -MySqlHostname $MySqlHostname -MySqlUser $MySqlUser -MySqlPass $MySqlPass

}