Azure Deployment Administration

Azure Deployment

Introduction

The goal of the SplendidCRM Azure Deployment system is to automate the process of virtual machine creation, database create and application deployment in a customer-centered production environment. Although we originally considered using preconfigured virtual machines and prepopulated databases for performance reasons, we found that the effort of managing the matrix of pre-created resources in all supported regions was too much to manage.

The system we created uses clean operating systems that use the latest build of Windows Server 2012 R2 Microsoft has published. It takes approximately 20 minutes for Azure to spin-up a new virtual machine and a couple of minutes to create a SQL database. As part of the deployment process, we use PowerShell scripts to configure IIS and to deploy the application. We expect there to be a unique PowerShell script for each application. And, there can be multiple files as part of the deployment.

Azure Prices

We manage the cost of the deployment using tables in the CRM. The Azure prices are generally stable but can change a couple of times a year. We have included current prices as of November 5, 2015, but you may need to review them to make sure that they are accurate. You can review the current prices at the following locations:

https://azure.microsoft.com/en-us/pricing/details/sql-database/

https://azure.microsoft.com/en-us/pricing/details/virtual-machines/

We have only included a few sample SQL prices and VM prices in our pricing tables, but you can certainly add more.


Microsoft Azure Account Setup

Azure Service Account Creation

Azure Subscription Creation

If you already have a developer account on Azure you can start with it, but it is important that you create or use a Pay-As-You-Go subscription instead of the Free Trial subscription. There are some resources that are not easily migrated between subscriptions, so you will want to make sure that they are created on the production subscription.

Microsoft has a document that describes the various accounts and roles (https://msdn.microsoft.com/en-us/library/azure/hh531793.aspx).

Azure Service User

SplendidCRM will need an Unattended User Account on the Azure Active Directory. The service user is created on the Active Directory tab of the Azure Portal on the Default Directory. Under Users, select Add User and specify the user name and "New user in your organization". When you click next, you will be asked for the Role. You must select the "Service Admin" role.


On a related note, later, you will want to change the organizational role temporarily to a Global Admin user so that you can use a PowerShell script to prevent the service user password from expiring. Otherwise your deployments will fail unexpectedly when the service account password does expire. Make sure to change the role back to Service Admin once you fix the password expiration.

Add-AzureAccount

Select-AzureSubscription -SubscriptionName "Pay-As-You-Go"

 

$msolcred = Get-Credential

Connect-MsolService -credential $msolcred

Set-MsolUser -UserPrincipalName "service@xxxxxxx" -PasswordNeverExpires $true

 

Azure App Creation

You will need to create an application under the default active directory. Select "Add an application my organization is developing". Make sure to specify "Native Client Application". For the Redirect URI, you can specify "http://localhost/".

Once the app is created, you will want to copy the Client ID as it will be needed in the CRM. The last step is to add permissions to the new app to allow access to the APIs. You will need to add "Windows Azure Active Directory" and "Windows Azure Service Management".

 


SplendidCRM Azure Settings

There are a couple of admin panels in the SplendidCRM admin area that provide access to all the administrative modules. The place to start is the Azure Settings page where you will insert the settings from the Azure Service Account you just created.

The CRM needs to have the security credentials in order to create resources on the Azure stack.

Verbose Status

This flag is used to increase the status information logged while processing an Azure deployment.

Resource Group/Cloud Service Prefix

Some resources within Azure require a globally unique name, across all companies. We recommend that you use your company name with a hyphen as the prefix (i.e. Splendid-). Although this prefix is used in the name of the virtual machine to ensure uniqueness, the customer will not see it. Instead, the customer will access the services using a DNS name derived from the DNS Base Domain.

Subscription ID

The Subscription ID comes from the Azure Portal page. You will find it on the Settings page.

Tenant Domain

The Tenant Domain comes from the Azure Portal page. It is the Default Directory for the subscription. You will find it on the Settings page.

Client ID

The Client ID comes from the Azure Portal page. It refers to the Native client application you created earlier.

Service Account User Name

The Service Account User Name refers to the user you created earlier.

Service Account Password

The Service Account User Password refers to the user you created earlier.

Global Resource Group

The CRM needs a global resource group to manage DNS entries. The resource group does not need to be created in advance. When you save the Azure Settings, the group will be created if it does not already exist.

Default Region

The Default Region is the region where the Global Resource Group will reside. The default region is typically where your DNS server will be hosted and where your global storage account will be hosted.

DNS Base Domain

The DNS Base Domain is the root domain from which all customer domains will be created against. You will need to use a domain that you own so that you can change the DNS name server entries to point to the Azure DNS servers. When you save the Azure Settings page, the base domain is created on the Azure DNS server, so you do not need to pre-create it. One note: you can use the Azure DNS services for all your DNS needs, but it might be easier and safer to use a separate domain for Azure deployments. For example, we use splendidcrm.com for our corporate needs and splendidcrm.net for Azure deployments. This eliminated the need to migrate splendidcrm.com entries from our old DNS servers to the new Azure DNS servers. If you have no legacy DNS server with critical email MX records, then it may make sense to have just one DNS system for your company.

SQL Firewall IP Address

Azure SQL servers are protected by a firewall. When the CRM creates a new SQL server in the region requested by your customers, it may need to add IP address for the SplendidCRM location so that the app can continue to manage the server. The CRM will automatically add support for all Azure servers to access the SQL server so that any VM create can access the matching database.

SQL Admin User Name

When the CRM creates a new SQL server, it will need to create an admin password for SQL server so that database can be created. This username is different than the username create for each database. For security purposes, each SQL database will get a unique SQL login that has a random component and a unique password. The only place these values are stored are in the VM itself. You are expected to use the SQL Admin User to access these customer databases.

SQL Admin Password

When the CRM creates a new SQL server, it will need to create an admin password for SQL server so that database can be created.

VM Admin User Name

All virtual machines created by the CRM will share an administrator user name and password. You will want to make sure that the pair is both reasonably long and complex. This is so that it is reasonably easy to connect to the VM and perform and necessary configuration, but also reasonably difficult for a hacker to derive.

VM Admin Password

All virtual machines created by the CRM will share an administrator user name and password. You will want to make sure that the pair is both reasonably long and complex.

 


Azure Regions

The Azure Regions table AZURE_REGIONS is used to maintain a list of all Microsoft Azure regions, both inactive and active. We have prepopulated this table for your using the known regions as of November 5th, 2015.

Name

The Name comes from the Microsoft Azure API, so you should not change the value and any new values must match those published by Microsoft. You can get the list of regions / locations using PowerShell (http://windowsitpro.com/azure/check-all-virtual-machine-sizes-all-azure-locations).

$azurelocations = Get-AzureLocation;

foreach ( $location in $azurelocations )

{

      Write-Output $location.Name;

}

Status

A disabled region will prevent customers from deploying to that region.

City

The city is editable and can be changed to anything you want. It is only expected to be used on the customer selection screen.

 


Azure Price Names

The Azure Price Names table AZURE_PRICE_NAMES is used to provide a dynamic list of available services. It includes the collection of VM services and the collection of SQL services that will be supported. The collections we support are much smaller than all the services Microsoft supports simply because we expect that the customer does not need that many choices.

Related to these lists is the Azure Service Levels table where we match VM services to their appropriate SQL services to even further simplify the choices the customer is presented.

Name

The name is used in the Microsoft Azure API, so the name must match the values specified by Microsoft. You can get the list of VM names using PowerShell (http://windowsitpro.com/azure/check-all-virtual-machine-sizes-all-azure-locations).

$location = Get-AzureLocation | Where {$_.Name -like 'East US' }

foreach ( $size in $location.VirtualMachineRoleSizes )

{

    Write-Output $size;

}

 

Accepted VM names are: Basic_A0, Basic_A1, Basic_A2, Basic_A3, Basic_A4, Standard_D1, Standard_D2, Standard_D3, Standard_D4, etc.

You can get a list of SQL service levels using PowerShell (https://msdn.microsoft.com/en-us/library/dn546721.aspx).

$objectives = Get-AzureSqlDatabaseServiceObjective -ServerName 'xxxxxxxxxxx';

foreach ( $objective in $objectives )

{

    if ( $objective.IsSystem -eq $false )

    {

      Write-Output $objective.Name;

    }

}

 

Accepted SQL names are: Basic, S0, S1, S2, S3, P1, P2, P3, P4, etc.

Type

The type can be VM or SQL.

List Order

This is the display order.


Azure SQL Prices

The Azure SQL Prices table AZURE_SQL PRICES will need to include an entry for each available SQL service at each supported region. We have prepopulated this list for known regions, but you may need to add more if you have added more SQL services. You will want to make sure that the Cost Price is correct as this is what Microsoft is going to charge you.

Name

This is the name of the SQL database service level as defined in the Microsoft Azure API. This listbox is populated from the Azure Price Names table for records of type SQL.

Status

A price can be active or inactive. This flag is not typically seen by the customer and is primarily informational.

Region Name

The region is important as SQL prices vary by region. This list is populated from the Azure Regions table.

Throughput

This is the throughput of the database for this service level. It is primarily a display value because the Name determines the service value. This price is not expected to change very often, but you will want to make sure that it is up-to-date.

Database Size

This is the maximum size of the database in GB. This is primarily a display value as the SQL service will determine the maximum size. As SQL services are not billed based on the size of the database, there is little reason to use any value less than the maximum.

Cost Price

The cost comes from Microsoft’s pricing tables and is in USD. https://azure.microsoft.com/en-us/pricing/details/sql-database/. You will want to make sure to update this value as Microsoft publishes updates to their pricing tables.

Pricing Factor

The pricing factor is multiplied by the Cost Price to determine the price for the customer. You have the option here of not marking-up the Microsoft fees by specifying a value of 1.0, or you can decrease or increase the price the customer sees by decreasing or increasing this value.

Description

This is the description displayed to the customer. It is not translated into a localized language for the customer, so you will have to handle that detail at the web site level.


Azure VM Prices

The Azure VM Prices table AZURE_VM_PRICES will need to include an entry for each available VM service at each supported region. We have prepopulated this list for known regions, but you may need to add more if you have added more VM services. You will want to make sure that the Cost Price is correct as this is what Microsoft is going to charge you.

Name

This is the name of the virtual machine service level as defined in the Microsoft Azure API. This listbox is populated from the Azure Price Names table for records of type VM.

Status

A price can be active or inactive. This flag is not typically seen by the customer and is primarily informational.

Region Name

The region is important as VM prices vary by region. This list is populated from the Azure Regions table.

RAM

This is the amount of RAM in GB for is service value. It is primarily a display value because the Name determines the service level.

Cores

This is the number of processor cores for is service value. It is primarily a display value because the Name determines the service level.

Disk Size

This is the disk size in GB for is service value. It is primarily a display value because the Name determines the service level.

Cost Price

The cost comes from Microsoft’s pricing tables and is in USD. https://azure.microsoft.com/en-us/pricing/details/virtual-machines/. You will want to make sure to update this value as Microsoft publishes updates to their pricing tables.

Pricing Factor

The pricing factor is multiplied by the Cost Price to determine the price for the customer. You have the option here of not marking-up the Microsoft fees by specifying a value of 1.0, or you can decrease or increase the price the customer sees by decreasing or increasing this value.

Description

This is the description displayed to the customer. It is not translated into a localized language for the customer, so you will have to handle that detail at the web site level.


Azure Service Levels

The Azure Service Levels table AZURE_SERVICE_LEVELS is used so simplify the selection process for the customer by combining a specific VM service for a specific SQL service. Although the matrix of all VM services against all SQL services can be large, we believe that the customer will want a simply and small list of choices with logical combinations. For example, it makes little sense to combine a very slow VM service with a super-fast SQL service, and vice versa.

Name

This is the name of the service level displayed to the customer. The name may need to be localized at the web site level.

Status

Only active service levels are displayed to the customer.

VM Price Name

The VM price for the service level.

SQL Price Name

The SQL price for the service level.

List Order

This list order is the order used to display the service levels to the customer.

Description

This is the description displayed to the customer. It is not translated into a localized language for the customer, so you will have to handle that detail at the web site level.


Azure App Prices

The Azure App Prices table AZURE_APP_PRICES contains all the information needed to deploy an application. It is also important to note that we do not use the standard SplendidCRM PRODUCT_TEMPLATES table for app pricing. When orders and invoices are created by the deployment system, it is this Azure App Prices table that is used as the template for those records.

Name

This is the name of the application.

Version

This is the version of the application.

List Order

This is the order that the apps are displayed to the customer.

Status

Only active apps are displayed to the customer.

Per User Pricing

This flag is enabled if the app is priced per user. If so, then the user is expected to be prompted for user quantities at the web site level.

Prompt for Password

This field is not used at this time but is intended to allow the customer to provide an admin password for the application in advance.

Min Users

This is the minimum number of users when priced per user.

Max Users

This is the maximum number of users when priced per user.

Setup Price

If there is an initial charge to setup the app, then set a value here. It can be zero if there is no setup fee. When there is a setup fee, the customer will be invoiced separately for the fee.

Cost Price

This is the cost of the application per month. It can be zero for open-source applications.

Pricing Factor

The pricing factor is multiplied by the cost price before displaying to the customer. The pricing factor only applies to the Cost Price and not the Setup Price.

Deploy Storage

The Azure storage that will contain the files being deployed.

Deploy Container

The container used in the storage. Only one container is used per application, so you will need to upload the shared PowerShell script files to all containers. We recommend one container per application to simplify management.

Deploy Files

A comma-separated list of files used in the deployment. The first file should be a PowerShell file that performs the customization of the OS and the deploying of the application.

Description

This is the description displayed to the customer. It is not translated into a localized language for the customer, so you will have to handle that detail at the web site level.

 

Azure Orders

The Azure Orders table AZURE_ORDERS is the heart of the deployment system. Key fields in the table are Service Name, Application, Region and Service Level. The remaining fields are informational or are used for management of the deployment.

Service Name

The service name should be a valid DNS name. The name can only contain letters, numbers and the hyphen. The name must start with a letter. The name must be at least 3 characters and it cannot be more than 15 characters. Some of these restrictions are because the name must follow Microsoft Azure Virtual Machine naming as well as DNS names. The Fully Qualified Doman Name is built by combining this service name value with the DNS Domain Base, with a dot separator.

Application

The Application is a required field that points to the Azure App Price table.

App Version

The App Version field is information and is derived from the Application.

Status

The initial value of Status should be "Pending Processing" to begin the deployment process. Other status values include Pending Delete, Processing, Failed, Succeeded and Cancelled.

Stage

The Azure Order will go through various stages as part of the deployment, starting with validation, to creation, to deployment. The list includes all the stages, as well deletion/recovery stages. If an error is encountered during the creation stages, the system will reverse the successful creation steps until the system is back to the original state.

  1. Validate Service Name
  2. Validate DNS Name
  3. Validate SQL Server
  4. Validate Database Name
  5. Create Database
  6. Create Virtual Machine
  7. Get Public IP Address
  8. Create DNS Entry
  9. Provisioning Virtual Machine
  10. Installing Web Service
  11. Complete
  12. Delete Virtual Machine
  13. Delete Database
  14. Delete DNS Entry

Region

The Region is the Microsoft Azure location where the virtual machine and the database will be created.

Service Level

The Service Level is a required field that points to the Azure Service Level table.

VM Price

The VM Price is determined from the specified Service Level.

SQL Price

The SQL Price is determined from the specified Service Level.

SQL Server

As part of the database creation step, a SQL Server is selected or created in the same region as the virtual machine. We store the server name so that the database can be deleted if necessary.

Order

The Order field points to the standard CRM Orders table.

Contact

The Contact field is determined using the Order Field. It points to the Billing Contact in the CRM Order.

Description

The description field is used to store the error from the last step.

 


Azure Resource Management

It is not our intent to fully replace the Azure Portal for creation of resources, but we do provide some management for convenience.

Azure Resource Groups

The deployment system will create a resource group in each region. To ensure uniqueness, we will pre-pend the resource group with the Cloud Prefix. However, we also allow you to manually create a resource group without the Cloud Prefix.

Name

This is the name of the resource group.

Location

The region / location of the resource group. The CRM will automatically create a new resource group for each region, using the Cloud Prefix and the region in the name.

Azure Resource Group List

You can see a list of all resource groups that exist. Resource groups cannot be deleted on the CRM side as this is a very destructive operation that would include deleting all contained virtual machines and databases.


DNS Names

The creation of DNS names is a critical part of the deployment system as it allows customers to have a simple and single domain name to access the site. As the Microsoft Azure Portal does not provide a way to manage DNS names, we have provided the ability to create and delete entries.

We generally do not recommend that you manually create entries, but there are certainly times when it makes sense.

Record Type

The type of the record. The only types that can be created are A, AAAA, CNAME and MX. The Azure DNS System will automatically create SOA and NS records.

The deployment system will create CNAME records to the cloudapp.azure.com domains that the Microsoft Azure system creates for each virtual machine. By using a CNAME instead of the IP address of the VM will allow for more flexibility with regard to VM reallocations.

Name

The name of the record.

Value

The value of the record.

Priority

The priority is used for MX records.


Storage Accounts

We do provide management of the storage accounts as you will be uploading files to Microsoft Azure to the deployment storage account. The deployment system will create new storage accounts for each region as necessary.

We have provided a relatively simple implementation that allows the listing of storage accounts and the uploading of files to a specified container within a storage account.

Name

The name of the storage account.

Resource Group

The resource group that the storage account applies to.

Location

The region / location of the storage account.

Uploading a File

When you upload a file, the container will be created if it does not already exist.


Virtual Machines

We provide a way to list the existing Virtual Machines, but we do not provide any management of them. The list is purely informational.

 

SQL Servers

We provide a way to list the existing SQL Servers, but we do not provide any management of them. The list is purely informational.

 

SQL Databases

We provide a way to list the existing SQL Databases, but we do not provide any management of them. The list is purely informational.

 


PowerShell Scripts

Internet Information Server (IIS) Installation

The script to install IIS is very simple as there is a cmdlet that does it all. We make sure to install ASP.NET 4.5 and HTTP Activation. We provide the sample script (IIS_Install.ps1) for this purpose.

Import-Module ServerManager

Add-WindowsFeature Web-Server,Web-WebServer,Web-Common-Http,Web-Static-Content,Web-Default-Doc,Web-Http-Errors,Web-Http-Redirect,Web-App-Dev,Web-ISAPI-Ext,Web-ISAPI-Filter,Web-Http-Logging,Web-Log-Libraries,Web-Request-Monitor,Web-Http-Tracing,Web-Security,Web-Basic-Auth,Web-Mgmt-Tools,Web-Mgmt-Console,Web-Scripting-Tools,Web-Metabase,Web-Asp-Net45,Web-Net-Ext45,Web-WebSockets,NET-WCF-HTTP-Activation45

 

SSL Certificate Installation

An optional step is to install an SSL certificate. We have provided a sample script (PFX_Install.ps1) that you will need to customize based on your environment. You will need to replace {SplendidCRM.SSL.Certificate.Name} with the actual name of your certificate file and {SplendidCRM.SSL.Certificate.Password} with the actual password for the PFX file. As much as we dislike including a password in a text file, we do not know of any other way to install the certificate. As a side note, we do typically delete the PFX_Install.ps1 file after deployment as a simple technique to hide the password.

$certLocalPath = '.\{SplendidCRM.SSL.Certificate.Name}.pfx'

$https         = (Get-WebBinding 'Default Web Site' | where {$_.protocol -eq 'https'})

if ( $https -eq $null -and (Test-Path $certLocalPath) )

{

    Write-Output 'Adding HTTPS'

    New-WebBinding -Name 'Default Web Site' -IP '*' -Port 443 -Protocol https

 

    # http://www.powershellmagazine.com/2014/03/31/powershell-remoting-with-azure-windows-vms/

    $X509Object = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2

    $X509Object.Import($certLocalPath, '{SplendidCRM.SSL.Certificate.Password}', 'PersistKeySet')

    $X509Store = New-Object System.Security.Cryptography.X509Certificates.X509Store 'My', 'LocalMachine'

    $X509Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)

    $X509Store.Add($X509Object)

    $X509Store.Close()

 

    New-Item 'IIS:\SslBindings\*!443' -Thumbprint $X509Object.Thumbprint

    Remove-Item $certLocalPath

    Remove-Item '.\PFX_Install.ps1'

}

 

Environment Setup

We have also included an environment setup script (Environment_Setup.ps1) that sets a bunch of Windows settings to make management of the virtual machine easier. The script is completely optional but does the following:

  1. Disable IE Enhanced Security
  2. Disable User Control Management
  3. Set IE default page
  4. Disable IE first run customize
  5. Do Not Show Server Manager
  6. Explorer settings
  7. Taskbar
  8. Command Prompt
  9. Show Desktop Icons

 

We are not including the file in this document because it is not informational.


Application Installation

As part of a SplendidCRM deployment, the application installation needs to install IIS, unzip the application files, configure IIS to point to the application files, apply the SSL certificate and initialize the database. As part of the execution of the deployment script, the first parameter will be the connection to the database. For this reason, the first line of the script should reference the connection string parameter.

param($ConnectionString)

 

# 07/21/2015 Paul. We need to make sure that the current location is set so that relative files are accessible.

Set-Location $PSScriptRoot

.\Environment_Setup.ps1

.\IIS_Install.ps1

 

#Unique variables for each product

$company   = 'SplendidCRM'

$product   = 'SplendidCRM'

$zip_file = '.\SplendidCRM_9.2.5692.40581_Community_WebGallery.zip'

 

#Invarients

$CRLF        = "`r`n";

$root_dest   = ('C:\' + $company)

$site_dest   = ($root_dest + '\' + $product)

$webConfig   = ($site_dest + '\' + 'web.config')

$app_offline = ($site_dest + '\' + 'app_offline.htm')

$build_sql   = ($root_dest + '\Build.sql')

$build_log   = ($root_dest + '\Build.log')

 

if ( !(Test-Path $root_dest) )

{

    Write-Output ('Creating ' + $root_dest)

    New-Item $root_dest -ItemType Directory | Out-Null

}

Copy-Item .\Environment_Setup.ps1 $root_dest

 

Add-Type -assembly 'System.IO.Compression.FileSystem'

[System.IO.Compression.ZipFile]::ExtractToDirectory($zip_file, $root_dest)

 

# Update Web.config with connection string.

Set-ItemProperty $webConfig -name IsReadOnly -value $false

 

$xml = (Get-Content $webConfig) -as [Xml]

$SplendidSQLServer = $xml.configuration.appSettings.add | where {$_.key -eq 'SplendidSQLServer'}

$SplendidSQLServer.value = $ConnectionString

$xml.Save($webConfig)

 

Import-Module WebAdministration

Set-ItemProperty 'IIS:\Sites\Default Web Site' -Name physicalPath -Value $site_dest

Set-ItemProperty 'IIS:\AppPools\DefaultAppPool' -Name processModel.idleTimeout       -Value ([TimeSpan]::FromMinutes(0))

Set-ItemProperty 'IIS:\AppPools\DefaultAppPool' -Name recycling.periodicrestart.time -Value ([TimeSpan]::FromMinutes(0))

 

.\PFX_Install.ps1

 

One trick that we do as part of the deployment is to create an app_offline.htm at the root of the application web site while we populate the database. This special file will be presented to anyone that visits the site while it is still being built. SplendidCRM database initialization can take 20 minutes, so the use of a progress page is important to the customer.

The following script is unique to SplendidCRM. It is used to create the CRM objects in an empty database.

$errors = 0

$log_text = ''

Set-Content -Path $build_log -Value $log_text -Force

 

$con = New-Object System.Data.SqlClient.SqlConnection

$con.ConnectionString = $ConnectionString

$con.open()

for ( $i = 0; $i -lt $Commands.Length; $i++ )

{

    $command = $Commands[$i].Trim()

    if ( $command.Length -gt 0 )

    {

        $progress = [math]::Round((100 * $i)/$Commands.Length)

        try

        {

            $offline = [String]::Format($html, $progress, $progress, $log_text, $command)

            try

            {

                Set-Content -Path $app_offline -Value $offline -Force

            }

            catch [Exception]

            {

                # We do not care if there was a problem writing to the offline file.

            }

            $cmd = $con.CreateCommand()

            $cmd.CommandTimeout = 0

            $cmd.CommandText = $command

            $cmd.ExecuteNonQuery() | Out-Null

      }

        # http://www.leaseweblabs.com/2014/01/print-full-exception-powershell-trycatch-block-using-format-list/

        catch [Exception]

        {

            $errors = $errors + 1

            $this_error = ($i.tostring() + ': ' + $_.Exception.Message + $CRLF)

            $log_text += $this_error

            # https://technet.microsoft.com/en-us/library/Ee156791.aspx

            Add-Content $build_log ($this_error + $command + $CRLF + $CRLF)

            # 10/24/2015 Paul. The connection can randomly fail. Attempt to recover.

            if ( $errors -lt 100 -and ($_.Exception.Message.Contains("A transport-level error has occurred") -or $_.Exception.Message.Contains("The connection's current state is closed.")) )

            {

                $i--;

                $con = New-Object System.Data.SqlClient.SqlConnection

                $con.ConnectionString = $ConnectionString

                $con.open()

            }

        }

    }

}

$con.close()

 

Once the database has been initialized, we delete the offline file so that the site will function normally. If there is a problem during deployment, we leave the offline file in place and it will need to be removed manually (i.e. a support specialist will need to use RDP to connect to the virtual machine to remove the file and fix the problem.)

if ( $errors -gt 0 )

{

    $log_text = Get-Content -Path $build_log -Raw

    $offline = [String]::Format($html, $log_text)

    Set-Content -Path $app_offline -Value $offline -Force

}

else

{

    Remove-Item $app_offline

}

 


Appendix

Additional Information

The SplendidCRM Application Platform is constantly being improved. Please visit the SplendidCRM Software website to obtain the most recent version of the software:

http://www.splendidcrm.com

If you have any questions, please post them to the SplendidCRM Support forum:

http://www.splendidcrm.com/Forums/tabid/66/Default.aspx

 

Errors and Omissions

If you discover any errors or omissions in this document, please email support@splendidcrm.com.