Development environments with PowerShell DSC – Part 6

Getting back to the the issue of installing things for a Sitecore development environment, this week I’m going to start tackling how you can add “Coveo for Sitecore” to a machine. While Coveo have provided some documentation on how this can be achieved, (for CES and REST APIs) they make they point that they don’t offer support for this approach to installation. So this may not be right for everyone. But in case it’s of use to you, here’s the first part of my attempt at the automation:

(Edited to add: Links to all posts in this series: 1:Introduction to DSC2:Windows Features3:Mongo DB4:SQL Server5:Sitecore – 6:Coveo CES – 7:Coveo REST API & Coveo for Sitecore)

[Before I get going, couple of notes about the examples I’m including in this series of posts: They all have a call to Start-DSCConfiguration using the “-Force” flag to make DSC run this configuration immediately in “push” mode. However, the Configuration blocks declared should all work in pull configurations. Writing the scripts this way just makes them easier for people to try out without any other setup effort. Also the examples are all pretty much self-contained, so the overall configuration of a server using them would rely on many separate scripts. You don’t necessarily need to have as many as I’m showing here. It’s more to keep the examples clear and usable than to represent the “right” architecture. You’re free to merge things together, or even break them apart further if that suits you.]

As we’ll see in a bit, we need to run some of this process as another user. So as discussed in my previous post about DSC impersonation, we need to modify the basics of the script to allow for passing in credentials. For the purposes of a simple example, I’m just using the local administrator account here, but you may choose to use a more constrained account, and put more effort into securing the credentials:

Configuration CoveoInstall
{
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $PackagePath,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [PSCredential]
        $Cred
    )
 
    Node $AllNodes.where{ $_.Role.Contains("Coveo") }.NodeName
    {
        #
        # Resources go here
        #
    }
}

$username = "$Env:ComputerName\administrator" 
$password = ConvertTo-SecureString "p@55w0rd" -Force -AsPlainText 
$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password

CoveoInstall -ConfigurationData "configData.psd1" -PackagePath "\\vboxsvr\dsc\Coveo" -Cred $credential
Start-DscConfiguration -Path .\CoveoInstall -Wait -Force -Verbose 

We’re also going to require some extra configuration data for this install. Extending the config data used in the previous installs, we’ll add in some stuff specific to Coveo and it’s dependencies, and a bit more to the Sitecore section:

@{
    
    AllNodes = @(
        @{
            NodeName = "*"
            PSDscAllowPlainTextPassword = $true
        }
        @{
            NodeName = "WIN-AQEKG7L9SE8"

            Role = "Setup, WindowsFeatures, IE, SqlServer, MongoDB, Sitecore, Coveo"
            
            TempFolder = "c:\dsc"

            WWWRoot = "C:\inetpub\wwwroot"

            #
            # Mongo / SQL / etc configuration goes here
            #

            Sitecore = @{
                #
                # Rest of Sitecore configuration goes here
                #

                PowerShellExtensions = "Sitecore PowerShell Extensions-3.3 for Sitecore 8.zip"
                PowerShellRemoting = "SPE Remoting-3.3.zip"
            }

            Coveo = @{
                ZipFolder = "7z"
                ZipTool = "7z.exe"
                MSChart = "MSChart.exe"
                MSXml = "msxml6_x64.msi"
                VCRedist = "vcredist_x64.exe"
                CESInstaller = "Coveo Enterprise Search 7.0 x64 (7914).exe"

                SvcAccount = "administrator"
                SvcPassword = "p@55w0rd"

                CESAPIInstaller = "Coveo Search API 8.0.885.exe"
                AppSecret = "ThisIsTheAppSecret"
                CoveoForSitecore = "Coveo for Sitecore 80 3.0 (1123).zip"
            }
         }
    );

}

(Some of this is required for the next, post dealing with the REST API and the Coveo for Sitecore package)

Coveo’s prerequisites

The Coveo Enterprise Search service needs a collection of things installed before it can run. Based on the documentation from Coveo, you can use the following DSC resources to provide them.

First, they ask for all of .Net framework 4 and 3.5:

WindowsFeature NetFramework35Core
{
    Name = "NET-Framework-Core"
    IncludeAllSubFeature = "True"
    Ensure = "Present"
}
 
WindowsFeature NetFramework45Core
{
    Name = "NET-Framework-45-Core"
    IncludeAllSubFeature = "True"
    Ensure = "Present"
}

They also ask for all of IIS:

WindowsFeature IIS
{
    Name = "Web-Server"
    IncludeAllSubFeature = "True"
    Ensure = "Present"
}

Then they ask for the MS Chart library. You can download the version required by the documentation, and add it to the packages folder for your script. The file name has been added as a configuration property named MSChart in the config extract above. So you can then copy it over to your target machine and use the Package resource to install it without any UI:

File CopyMSChart
{
    SourcePath = "$PackagePath\$($Node.Coveo.MSChart)"
    DestinationPath = "$($Node.TempFolder)\$($Node.Coveo.MSChart)"
}

Package InstallMSChart
{
    Name = "Microsoft Chart Controls for Microsoft .Net Framework 3.5"
    Path = "$($Node.TempFolder)\$($Node.Coveo.MSChart)"
    ProductID = ""
    Arguments = "/passive"
}

Next is the MSXML framework. This can also be installed with a similar pattern – though for this one, the Package resource isn’t as much help so it’s using the Script resource to call msiexec.exe for the install instead:

File CopyMSXml
{
    SourcePath = "$PackagePath\$($Node.Coveo.MSXml)"
    DestinationPath = "$($Node.TempFolder)\$($Node.Coveo.MSXml)"
}

Script InstallMSXml
{
    DependsOn = "[file]CopyMSXml"
    GetScript = { 
        @{ Feature = "Install MSXml library" }
    }
    TestScript = { $False }
    SetScript = {
        $pkg = "$($using:Node.TempFolder)\$($using:Node.Coveo.MSXml)"

        msiexec.exe /qn /i "$pkg" | out-null
    }
}

Next up is the Visual C Runtime re-distributable. This one doesn’t come as an MSI, but the installer allows a silent install by passing a flag to the executable:

File CopyVCRedist
{
    SourcePath = "$PackagePath\$($Node.Coveo.VCRedist)"
    DestinationPath = "$($Node.TempFolder)\$($Node.Coveo.VCRedist)"
}

Script InstallVCRedist
{
    DependsOn = "[file]CopyVCRedist"
    GetScript = { 
        @{ Feature = "Install VC Redist library" }
    }
    TestScript = { $False }
    SetScript = {
        $redist = "$($using:Node.TempFolder)\$($using:Node.Coveo.VCRedist)"

        &$redist /q | out-null
    }
}

For both this and the MSXML Script there’ll be some registry keys created which could be tested in the GetScript to avoid re-installing when not necessary – but I’ve not had time to find those yet. A tool like Process Monitor would allow watching for registry writes during the install to find an appropriate key.

Installing the Coveo Entrprise Search service

The standard installer that Coveo provide for the core of their software can’t be automated directly, according to Coveo’s documents. Hence it’s necessary to extract the files and automate the .MSI file. Rather than the approach used for Sitecore previously, the installer doesn’t seem to offer an extract feature itself – so we need to unzip it manually. The zip-handling in Windows can’t cope with this format of this file, so we need a 3rd party tool to achieve this. I happened to have the command line version of 7zip available, but you can use others if you prefer.

First up, we need to copy over the command-line zip tool. In this case the exe and it’s DLL have been put in a folder under the package path. This folder can then be transferred over to the target machine:

File CopyZip
{
    SourcePath = "$PackagePath\$($Node.Coveo.ZipFolder)"
    DestinationPath = "$($Node.TempFolder)\"
    Type = "Directory"
    Ensure = "Present"
    Recurse = "true"
}

Then we need to copy over the CES installer itself:

File CopyCoveo
{
    SourcePath = "$PackagePath\$($Node.Coveo.CESInstaller)"
    DestinationPath = "$($Node.TempFolder)\$($Node.Coveo.CESInstaller)"
    Ensure = "Present"
}

And then we can use the zip to to decompress it with a Script resource:

Script UnzipCoveo
{
    DependsOn = "[file]CopyCoveo", "[file]CopyZip"
    GetScript = { 
        @{ Feature = "Unzip the Coveo installer" }
    }
    TestScript = { $False }
    SetScript = {
        $zipTool = "$($using:Node.TempFolder)\$($using:Node.Coveo.ZipTool)"
        $file = "$($using:Node.TempFolder)\$($using:Node.Coveo.CESInstaller)"
        $target = "$($using:Node.TempFolder)"

        Push-Location $target

        &$zipTool x -oCoveo -y "$file" | write-verbose

        Pop-Location
    }
}

The script changes directory to the temp folder and then calls the zip tool to extract the file into a sub-folder called “Coveo”.

With this done, a further script resource can perform the job of installing CES:

Script InstallCoveo
{
    Credential = $cred
    DependsOn = "[script]UnzipCoveo"
    GetScript = { 
        @{ Feature = "Install the CES sevice" }
    }
    TestScript = { $False }
    SetScript = {
        $tmp = "$($using:Node.TempFolder)"
        $msiFile = [System.IO.Path]::ChangeExtension($using:Node.Coveo.CESInstaller,".msi")
        $msiPath = "$($using:Node.TempFolder)\Coveo\$($msiFile)"

        $user = "$($using:Node.Coveo.SvcAccount)"
        $pwd = "$($using:Node.Coveo.SvcPassword)"

        msiexec.exe /qn /i "$msiPath" "ADDLOCAL=BaseFeature,VCRedist,CESService,Admin,AdminService,CESConsole" "LOGONTYPE=account" "LOGONACCOUNT_USERNAME=$user" "LOGONACCOUNT_PASSWORD=$pwd" /l*+v "$tmp\Coveo-Install.log" | Out-Null
    }
}

(Again, the GetScript with this and the unzip Script above aren’t filled in yet. These could be done with appropriate Test-Path calls)

This is mostly just another example of using msiexec.exe to install a package. The set of parameters passed just install all the “single server install” features, and set the service account to the credentials given in the config file. Note that the resource takes the Credential parameter. As described in my previous post DSC scripts run in as a user which lacks certain operating system permissions the CES installer needs to run correctly. Hence impersonating a different user with more rights.

With that done, CES should be installed and running. You won’t be able to do much with it as yet, since it doesn’t have a license installed or any indexes to search. Next time we’ll move on to the REST API and the Coveo for Sitecore extensions – which will get those set up.

Advertisements

One thought on “Development environments with PowerShell DSC – Part 6

  1. Pingback: Development environments with PowerShell DSC – Part 7 | Jeremy Davis

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s