cIBMHTTPServer.psm1

# Import IBM HTTP Server Utils Module
Import-Module $PSScriptRoot\cIBMHTTPServerUtils.psm1 -ErrorAction Stop

enum Ensure {
    Absent
    Present
}

enum StartupType {
    Automatic
    Manual
    Disabled
}

<#
   DSC resource to manage the installation of IBM HTTP Server.
   Key features:
    - Install IBM HTTP Server for the first time
    - Can use media on the local drive as well as from a network share which may require specifying credentials
#>


[DscResource()]
class cIBMHTTPServer {
    
    [DscProperty(Mandatory)]
    [Ensure] $Ensure
    
    [DscProperty(Key)]
    [String] $Version
    
    [DscProperty()]
    [Int] $HTTPPort = 80
    
    [DscProperty()]
    [String] $InstallationDirectory = "C:\IBM\HTTPServer"
    
    [DscProperty()]
    [String] $IMSharedLocation = "C:\IBM\IMShared"
    
    [DscProperty()]
    [StartupType] $StartupType = [StartupType]::Automatic
    
    [DscProperty()]
    [PSCredential] $WindowsServiceAccount
    
    [DscProperty()]
    [String] $InstallMediaConfig
    
    [DscProperty()]
    [String] $ResponseFileTemplate

    [DscProperty()]
    [String] $SourcePath
    
    [DscProperty()]
    [System.Management.Automation.PSCredential] $SourcePathCredential
    
    

    <#
        Installs IBM HTTP Server
    #>

    [void] Set () {
        try {
            if ($this.Ensure -eq [Ensure]::Present) {
                Write-Verbose -Message "Starting installation of IBM HTTP Server"
                $ihsVersion = $this.Version
                if (!($this.InstallMediaConfig)) {
                    $this.InstallMediaConfig = Join-Path -Path $PSScriptRoot -ChildPath "InstallMediaConfig\IHS-$ihsVersion.xml"
                }
                if (!($this.ResponseFileTemplate)) {
                    $this.ResponseFileTemplate = Join-Path -Path $PSScriptRoot -ChildPath "ResponseFileTemplates\IHS-$ihsVersion-template.xml"
                }
                $installed = Install-IBMHTTPServer -InstallMediaConfig $this.InstallMediaConfig `
                    -ResponseFileTemplate $this.ResponseFileTemplate -InstallationDirectory $this.InstallationDirectory `
                    -HTTPPort $this.HTTPPort -StartupType $this.StartupType -WindowsServiceAccount $this.WindowsServiceAccount `
                    -IMSharedLocation $this.IMSharedLocation -SourcePath $this.SourcePath -SourcePathCredential $this.SourcePathCredential
                if ($installed) {
                    Write-Verbose "IBM HTTP Server Installed Successfully"
                } else {
                    Write-Error "Unable to install IBM HTTP Server, please check installation logs for more information"
                }
            } else {
                Write-Verbose "Uninstalling IBM HTTP Server (Not Yet Implemented)"
            }
        } catch {
            Write-Error -ErrorRecord $_ -ErrorAction Stop
        }
    }

    <#
        Performs test to check if IHS is in the desired state, includes
        validation of installation directory and version
    #>

    [bool] Test () {
        Write-Verbose "Checking for IBM HTTP Server installation"
        $ihsConfiguredCorrectly = $false
        $ihsRsrc = $this.Get()
        
        if (($ihsRsrc.Ensure -eq $this.Ensure) -and ($ihsRsrc.Ensure -eq [Ensure]::Present)) {
            $sameVersion = ($ihsRsrc.Version -eq $this.Version)
            if (!($sameVersion)) {
                $currVersionObj = (New-Object -TypeName System.Version -ArgumentList $ihsRsrc.Version)
                $newVersionObj = (New-Object -TypeName System.Version -ArgumentList $this.Version)
                $sameVersion = (($currVersionObj.ToString(3)) -eq ($newVersionObj.ToString(3)))
            }
            if ($sameVersion) {
                if (((Get-Item($ihsRsrc.InstallationDirectory)).Name -eq 
                    (Get-Item($this.InstallationDirectory)).Name) -and (
                    (Get-Item($ihsRsrc.InstallationDirectory)).Parent.FullName -eq 
                    (Get-Item($this.InstallationDirectory)).Parent.FullName)) {
                    Write-Verbose "IBM HTTP Server is installed and configured correctly"
                    $ihsConfiguredCorrectly = $true
                }
            }
        } elseif (($ihsRsrc.Ensure -eq $this.Ensure) -and ($ihsRsrc.Ensure -eq [Ensure]::Absent)) {
            $ihsConfiguredCorrectly = $true
        }

        if (!($ihsConfiguredCorrectly)) {
            Write-Verbose "IBM HTTP Server not configured correctly"
        }
        
        return $ihsConfiguredCorrectly
    }

    <#
        Leverages the information stored in the registry to populate the properties of an existing
        installation of IHS
    #>

    [cIBMHTTPServer] Get () {
        $RetEnsure = [Ensure]::Absent
        $RetVersion = $null
        
        $versionObj = (New-Object -TypeName System.Version -ArgumentList $this.Version)
        $RetInsDir = Get-IBMHTTPServerInstallLocation $versionObj
        
        if($RetInsDir -and (Test-Path($RetInsDir))) {
            $VersionInfo = Get-IBMWebSphereProductVersionInfo $RetInsDir
            if($VersionInfo -and ($VersionInfo.Products) -and ($VersionInfo.Products["IHS"])) {
                Write-Verbose "IBM HTTP Server is Present"
                $RetEnsure = [Ensure]::Present
                $RetVersion = $VersionInfo.Products["IHS"].Version
            } else {
                Write-Warning "Unable to retrieve version information from the IBM HTTP Server installed"
            }
        } else {
            Write-Verbose "IBM HTTP Server is NOT Present"
        }

        $returnValue = @{
            InstallationDirectory = $RetInsDir
            Version = $RetVersion
            Ensure = $RetEnsure
        }

        return $returnValue
    }
}

[DscResource()]
class cIBMHTTPServerSSLCertificate {
    
    [DscProperty(Mandatory)]
    [Ensure] $Ensure
    
    [DscProperty(Key)]
    [String] $KeyDBPath

    [DscProperty(Mandatory)]
    [PSCredential] $KeyDBPassword
    
    [DscProperty(Key)]
    [String] $CertificateLabel
    
    [DscProperty()]
    [Boolean] $Default
    
    [DscProperty()]
    [String] $CertificatePath
    
    [DscProperty()]
    [PSCredential] $CertificatePassword
    
    [DscProperty()]
    [PSCredential] $CertificatePathCredential

    <#
        Adds SSL certificates to key database
    #>

    [void] Set () {
        try {
            if ($this.Ensure -eq [Ensure]::Present) {
                Write-Verbose -Message "Adding SSL certificate / key database"
                $addCert = $false
                if (!(Test-Path $this.KeyDBPath -PathType Leaf)) {
                    # Create new Key DB
                    $addCert = New-IBMSSLKeyDatabase -KeyDBPath $this.KeyDBPath -KeyDBPassword $this.KeyDBPassword -Stash
                    if (!$addCert) {
                        Write-Error "An issue occurred while creating the key database"
                    }
                } else {
                    $addCert = $true
                }
                
                if ($addCert) {
                    $sslCertAdded = $false
                    if ($this.Default) {
                        $sslCertAdded = Add-SSLCertificateToIBMKeyDB $this.KeyDBPath -KeyDBPassword $this.KeyDBPassword `
                             -CertificatePath $this.CertificatePath -CertificatePathCredential $this.CertificatePathCredential `
                             -CertificatePassword $this.CertificatePassword -DefaultCertificateLabel $this.CertificateLabel
                    } else {
                        $sslCertAdded = Add-SSLCertificateToIBMKeyDB $this.KeyDBPath -KeyDBPassword $this.KeyDBPassword `
                             -CertificatePath $this.CertificatePath -CertificatePathCredential $this.CertificatePathCredential `
                             -CertificatePassword $this.CertificatePassword
                    }
                }
            } else {
                Write-Verbose "Removing SSL certificate (Not Yet Implemented)"
            }
        } catch {
            Write-Error -ErrorRecord $_ -ErrorAction Stop
        }
    }

    <#
        Performs test to check if SSL certificates has been added to key database
    #>

    [bool] Test () {
        Write-Verbose "Checking if SSL Certificate has been installed"
        $certIsOK = $false
        $certRsrc = $this.Get()
        
        if (($certRsrc.Ensure -eq $this.Ensure) -and ($certRsrc.Ensure -eq [Ensure]::Present)) {
            if ($certRsrc.RetKeyDBPath -eq $this.RetKeyDBPath) {
                if ($certRsrc.RetCertLabel -eq $this.RetCertLabel) {
                    if ($certRsrc.Default -eq $this.Default) {
                        Write-Verbose "IBM SSL Certificate configured correctly"
                        $certIsOK = $true
                    }
                }
            }
        } elseif (($certRsrc.Ensure -eq $this.Ensure) -and ($certRsrc.Ensure -eq [Ensure]::Absent)) {
            $certIsOK = $true
        }

        if (!($certIsOK)) {
            Write-Verbose "IBM SSL Certificate not configured correctly"
        }
        
        return $certIsOK
    }

    <#
        Retreives current SSL config
    #>

    [cIBMHTTPServerSSLCertificate] Get () {
        $RetEnsure = [Ensure]::Absent
        $RetKeyDBPath = $null
        $RetCertLabel = $null
        $RetDefault = $false
        
        if (Test-Path $this.KeyDBPath -PathType Leaf) {
            $certs = Get-IBMKeyDBCertificates -KeyDBPath $this.KeyDBPath -KeyDBPassword $this.KeyDBPassword
            if ($certs) {
                $RetKeyDBPath = $this.KeyDBPath
                if ($certs.Contains($this.CertificateLabel)) {
                    $RetCertLabel = $this.CertificateLabel
                    $defaultCert = Get-IBMKeyDBDefaultCertificate -KeyDBPath $this.KeyDBPath -KeyDBPassword $this.KeyDBPassword
                    if ($RetCertLabel -eq $defaultCert) {
                        $RetEnsure = [Ensure]::Present
                        $RetDefault = $true
                    }
                }
            }
        }
        
        $returnValue = @{
            Ensure = $RetEnsure
            KeyDBPath = $RetKeyDBPath
            CertificateLabel = $RetCertLabel
            Default = $RetDefault
        }

        return $returnValue
    }
}