EpiCloud.psm1
function AddTlsSecurityProtocolSupport { <# .SYNOPSIS This helper function adds support for TLS protocol 1.1 and/or TLS 1.2 .DESCRIPTION This helper function adds support for TLS protocol 1.1 and/or TLS 1.2 #> [CmdletBinding()] param( [Parameter(Mandatory=$false)] [Bool] $EnableTls11 = $true, [Parameter(Mandatory=$false)] [Bool] $EnableTls12 = $true ) # Add support for TLS 1.1 and TLS 1.2 if (-not [Net.ServicePointManager]::SecurityProtocol.HasFlag([Net.SecurityProtocolType]::Tls11) -AND $EnableTls11) { [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls11 } if (-not [Net.ServicePointManager]::SecurityProtocol.HasFlag([Net.SecurityProtocolType]::Tls12) -AND $EnableTls12) { [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 } } function GetApiErrorResponse { <# .SYNOPSIS This helper function retrieves the returned error message from the API .DESCRIPTION This helper function retrieves the returned error message from the API Because of the way Invoke-RestMethod works, the error message would otherwise be "hidden" and only the http code would be returned #> [CmdletBinding()] [OutputType([String])] param( $ExceptionResponse ) try { $errorResponseStream = $ExceptionResponse.GetResponseStream() $errorResponseStreamReader = New-Object System.IO.StreamReader($errorResponseStream) $errorResponseStreamReader.BaseStream.Position = 0 $errorResponseStreamReader.DiscardBufferedData() $errorResponse = $errorResponseStreamReader.ReadToEnd() $errorResponse } catch { $ExceptionResponse } } function GetApiObjectEncoded { <# .SYNOPSIS This helper function converts the responses from the API so the encoding is correct .DESCRIPTION This helper function converts the responses from the API so the encoding is correct (Related to an encoding bug in Invoke-RestMethod) #> [CmdletBinding(DefaultParameterSetName='Response')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory = $true, ParameterSetName = 'Response')] [System.Object[]] $ApiObject, [Parameter(Mandatory = $true, ParameterSetName = 'Payload')] [System.Object[]] $RequestPayload ) $utf8 = [System.Text.Encoding]::GetEncoding(65001) $iso88591 = [System.Text.Encoding]::GetEncoding(28591) #ISO 8859-1 ,Latin-1 if ($ApiObject) { $SerializedObject = ConvertTo-Json -Depth 10 -InputObject $ApiObject -Compress $bytesArray = [System.Text.Encoding]::Convert($utf8, $iso88591, $utf8.GetBytes($SerializedObject)) } else { $SerializedObject = ConvertTo-Json -Depth 10 -InputObject $RequestPayload -Compress $bytesArray = [System.Text.Encoding]::Convert($iso88591, $utf8, $utf8.GetBytes($SerializedObject)) } # Write the first results to the pipline $EncodedJsonString = $utf8.GetString($bytesArray) $EncodedObject = ConvertFrom-Json -InputObject $EncodedJsonString Write-Output $EncodedObject } function GetApiRequestSplattingHash { <# .SYNOPSIS This helper function creates a hashtable containing the basic properties needed to use the REST-api .DESCRIPTION This helper function creates a hashtable containing the basic properties needed to use the REST-api. Other properties will need to be added for most calls but that will be handled in the respective functions for those methods. #> [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [String] $UriEnding, [Parameter(Mandatory = $false)] [ValidateSet( 'Default', 'Delete', 'Get', 'Head', 'Merge', 'Options', 'Patch', 'Post', 'Put', 'Trace' )] [String] $Method = 'Get' ) if ($Global:EpiCloudApiEndpointUri) { $apiEndpoint = $Global:EpiCloudApiEndpointUri } else { $apiEndpoint = 'https://paasportal.episerver.net/api/v1.0/' } $hashToReturn = @{ Headers = @{ Authorization = '' } Uri = $apiEndpoint + $UriEnding ContentType = 'application/json' Method = $Method ErrorAction = 'Stop' TimeoutSec = 120 Verbose = $false } $hashToReturn } function ImportAzureStorageModule { $azureModuleLoaded = Get-Module -Name "Azure.Storage" $azModuleLoaded = Get-Module -Name "Az.Storage" if (-not ($azureModuleLoaded -or $azModuleLoaded)) { try { $null = Import-Module -Name "Az.Storage" -ErrorAction Stop $azModuleLoaded = $true } catch { Write-Verbose "Tried to find 'Az.Storage', module couldn't be imported." } } if (-not ($azureModuleLoaded -or $azModuleLoaded)) { try { $null = Import-Module -Name "Azure.Storage" -ErrorAction Stop $azureModuleLoaded = $true } catch { Write-Verbose "Tried to find 'Azure.Storage', module couldn't be imported." } } if ($azModuleLoaded) { "Az" } elseif ($azureModuleLoaded) { $azureModuleLoaded = Get-Module -Name "Azure.Storage" if ($azureModuleLoaded.Version.Major -lt 4 -or ($azureModuleLoaded.Version.Major -eq 4 -and $azureModuleLoaded.Version.Minor -lt 4)) { # Previous versions of Azure.Storage do not support SAS links with write-only permission. throw "'Azure.Storage' version 4.4.0 or greater is required." } "Azure" } else { throw "'Az.Storage' or 'Azure.Storage' module is required to run this cmdlet." } } function InvokeApiRequest { <# .SYNOPSIS This helper function creates does the actual API call .DESCRIPTION This helper function does the actual API call and signs the request #> [CmdletBinding(DefaultParameterSetName = 'NoRequestPayload')] param( [Parameter(Mandatory = $true)] [String] $ClientKey, [Parameter(Mandatory = $true)] [String] $ClientSecret, [Parameter(Mandatory = $true)] [System.Collections.Hashtable] $RequestSplattingHash, [Parameter(Mandatory = $true, ParameterSetName = 'ObjectRequestPayload')] [System.Collections.Hashtable] $RequestPayload ) begin { AddTlsSecurityProtocolSupport } process { if ($RequestPayload) { try { $encodedString = GetApiObjectEncoded -RequestPayload $RequestPayload $encodedPayload = ConvertTo-Json -Depth 10 -InputObject $encodedString } catch { throw "Failed to encode the request payload. The error was: $($_.Exception.Message)" } $RequestSplattingHash.Add('Body', $encodedPayload) } $setApiAuthorizationHeaderParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret RequestHash = $RequestSplattingHash } SetApiAuthorizationHeader @setApiAuthorizationHeaderParams try { $response = Invoke-RestMethod @RequestSplattingHash } catch { $errorMessage = GetApiErrorResponse -ExceptionResponse $_.Exception.Response throw "API call failed! The error was: $($_.Exception.Message) $errorMessage" } if (!$response.success) { throw "API call failed! The error(s) was: $(($response.errors) -join ', ')" } if ($response.result) { GetApiObjectEncoded -ApiObject $response.result } } end { } } function SetApiAuthorizationHeader { <# .SYNOPSIS This helper function contains the logic for signing the request/creating the authorization header .DESCRIPTION This helper function contains the logic for signing the request/creating the authorization header #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [String] $ClientKey, [Parameter(Mandatory=$true)] [String] $ClientSecret, [Parameter(Mandatory=$true)] [System.Collections.Hashtable] $RequestHash ) # Initialize utils required for computing an HMAC and md5 signature/hash $hmacAlgorithm = New-Object System.Security.Cryptography.HMACSHA256 $md5 = [System.Security.Cryptography.MD5]::Create() # Set the secret the HMAC algorithm uses for computing the signature $hmacAlgorithm.key = [System.Convert]::FromBase64String($ClientSecret) # Define the different parts that make up the HMAC signature $path = ([System.Uri] $RequestHash.Uri).PathAndQuery $method = $RequestHash.Method.ToUpperInvariant() $timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliSeconds().ToString("0") $nonce = (New-Guid).ToString("N") # Define the HTTP request payload that will be tacked on to the signature if ($RequestHash.Body) { $bodyBytes = [Text.Encoding]::UTF8.GetBytes($RequestHash.Body) } else { $bodyBytes = [Text.Encoding]::UTF8.GetBytes('') } $bodyHashBytes = $md5.ComputeHash($bodyBytes) $hashBody = [Convert]::ToBase64String($bodyHashBytes) # Combine all the parts into a signature message $message = "{0}{1}{2}{3}{4}{5}" -f $ClientKey, $method, $path, $timestamp, $nonce, $hashBody $messageBytes = [Text.Encoding]::UTF8.GetBytes($message) # Define the HMAC signature from the message $signatureHash = $hmacAlgorithm.ComputeHash($messageBytes); $signature = [Convert]::ToBase64String($signatureHash) # Define the authorization header for the HTTP request $authorization = "epi-hmac {0}:{1}:{2}:{3}" -f $ClientKey, $timestamp, $nonce, $signature # Set the header $RequestHash.Headers.Authorization = $authorization } function Add-EpiDeploymentPackage { <# .SYNOPSIS Will upload the specified file to the code package container by using a SAS link. .DESCRIPTION Will upload the specified file to the code package container by using a SAS link. Requires storage cmdlets from the Azure.Storage module to run. .PARAMETER Path The file name with full path .PARAMETER BlobName The name of Blob in the container. .PARAMETER SasUrl The Sas link contains access to storage account. .EXAMPLE Add-EpiDeploymentPackage -SasUrl "https://thle2307mh134.blob.core.windows.net/deploymentpackages?sv=2017-04-17&sr=c&sig=MGW6ndtX1vNT%2BSRpLUT8vPuurteyb" -Path .\site.cms.app.1.0.0.nupkg Uploads the file ".\site.cms.app.1.0.0.nupkg" to the code package container on the storage account specified via the SAS link ("SasUrl") #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $SasUrl, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias('FullName')] [String] $Path, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [Alias('Name')] [String] $BlobName ) begin { AddTlsSecurityProtocolSupport $DefaultContainer = "deploymentpackages" $urlComponent = $SasUrl -split $DefaultContainer if ($urlComponent.Length -lt 2 -or -not $SasUrl.StartsWith('https://') -or -not $SasUrl.Contains('.blob.core.windows.net/')) { throw "The SasUrl is not correct" } $sasToken = $urlComponent[1].ToString() $storageAccountName = $urlComponent[0].ToString().Replace('https://', '').Replace('.blob.core.windows.net/', '') $azureModuleType = ImportAzureStorageModule if ($azureModuleType -eq "Azure") { $storageAccountContext = New-AzureStorageContext -StorageAccountName $storageAccountName -SASToken $sasToken -ErrorAction Stop } else { $storageAccountContext = New-AzStorageContext -StorageAccountName $storageAccountName -SASToken $sasToken -ErrorAction Stop } } process { if (-not $BlobName) { $BlobName = Split-Path $Path -leaf } Write-Verbose "Uploading blob $BlobName to storage account ..." $setAzureStorageBlobContentParams = @{ File = $Path Container = $DefaultContainer Blob = $BlobName Context = $storageAccountContext Force = $true ErrorAction = 'Stop' } if ($azureModuleType -eq "Azure") { $null = Set-AzureStorageBlobContent @setAzureStorageBlobContentParams } else { $null = Set-AzStorageBlobContent @setAzureStorageBlobContentParams } Write-Verbose "Done!" } end { } } function Complete-EpiDeployment { <# .SYNOPSIS This function will complete the specified code deployment .DESCRIPTION This function will complete the specified code deployment .EXAMPLE $clientKey = '12331bpXbHmuTDkhZmtUAq1scYsEbCIlY4N355SWLmTq1cgi' $clientSecret = '123456dkQQZ2ohrVMwtyZAtEkqHd75l2f9ACPIN1nm4pHmZDQ4NMikCNWBlZ2H6D' $projectId = '8ad8cc5b-0c49-4b79-8ebd-6451465a92c2' $deploymentId = '6c0ed684-8548-48aa-8695-fcfd43477b43' Complete-EpiDeployment -ClientKey $clientKey -ClientSecret $clientSecret -ProjectId $projectId -Id $deploymentId .EXAMPLE $clientKey = '12331bpXbHmuTDkhZmtUAq1scYsEbCIlY4N355SWLmTq1cgi' $clientSecret = '123456dkQQZ2ohrVMwtyZAtEkqHd75l2f9ACPIN1nm4pHmZDQ4NMikCNWBlZ2H6D' $projectId = '8ad8cc5b-0c49-4b79-8ebd-6451465a92c2' $deploymentId = '6c0ed684-8548-48aa-8695-fcfd43477b43' Complete-EpiDeployment -ClientKey $clientKey -ClientSecret $clientSecret -ProjectId $projectId -Id $deploymentId -Wait -WaitTimeoutMinutes 10 -PollingIntervalSeconds 10 .PARAMETER ClientKey The client key used to access the project. .PARAMETER ClientSecret The client secret used to access the project. .PARAMETER ProjectId The Id (should be a guid) of the project. .PARAMETER Id The Id of the deployment that you want to complete. .PARAMETER Wait Specify this switch to wait for the deployment to finish. .PARAMETER WaitTimeoutMinutes The maximum amount of time, in minutes, to retry to check the deployment status. Default to 30 minutes. .PARAMETER PollingIntervalSeconds The time interval, in seconds, to check the deployment status. Default to 30 seconds. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $ClientKey, [Parameter(Mandatory = $true)] [String] $ClientSecret, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String] $ProjectId, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String] $Id, [Parameter(Mandatory = $false)] [Switch] $Wait, [Parameter(Mandatory = $false)] [ValidateRange(1, 60)] [Int] $WaitTimeoutMinutes = 30, [Parameter(Mandatory = $false)] [ValidateRange(1, 60)] [Int] $PollingIntervalSeconds = 30 ) begin { } process { $uriEnding = "projects/$ProjectId/deployments/$Id/complete" $requestHash = GetApiRequestSplattingHash -UriEnding $uriEnding -Method 'Post' $completeEpiDeploymentParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret RequestSplattingHash = $requestHash } $deploymentDetails = InvokeApiRequest @completeEpiDeploymentParams if ($Wait.IsPresent) { $timeoutDate = (Get-Date).AddMinutes($WaitTimeoutMinutes) do { Write-Verbose "Deployment status: $($deploymentDetails.status)" Start-Sleep -Second $PollingIntervalSeconds $getEpiDeploymentDetailsParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret ProjectId = $ProjectId Id = $Id } $deploymentDetails = Get-EpiDeployment @getEpiDeploymentDetailsParams } while ($deploymentDetails.status -notin @('Failed', 'Succeeded') -and (Get-Date) -le $timeoutDate) } $deploymentDetails } end { } } function Connect-EpiCloud { <# .SYNOPSIS Adds credentials (ClientKey and Client Secret) for all functions in EpiCloud module to be used during the session/context. .DESCRIPTION This function will specify the default credentials (ClientKey and Client Secrets) that should be used for all functions in the current session/context. .EXAMPLE Connect-EpiCloud -ClientKey 12331bpXbHmuTDkhZmtUAq1scYsEbCIlY4N355SWLmTq1123 -ClientSecret UowYA4dkQQZ2ohrVMwtyZAtEkqHd75l2f9ACPIN1nm4pHmZDQ4NMikCNWBlZ2H6D Get-EpiDeploymentPackageLocation -ProjectId 1234567890 .PARAMETER ClientKey The client key used to access the project. .PARAMETER ClientSecret The client secret used to access the project. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $ClientKey, [Parameter(Mandatory = $true)] [String] $ClientSecret ) begin { $commands = Get-Command -Module 'EpiCloud' } process { foreach ($command in $commands) { if ($global:PSDefaultParameterValues."$($command.Name):ClientKey") { $global:PSDefaultParameterValues.Remove("$($command.Name):ClientKey") } if ($global:PSDefaultParameterValues."$($command.Name):ClientSecret") { $global:PSDefaultParameterValues.Remove("$($command.Name):ClientSecret") } $global:PSDefaultParameterValues.Add("$($command.Name):ClientKey", $ClientKey) $global:PSDefaultParameterValues.Add("$($command.Name):ClientSecret", $ClientSecret) } } end { } } function Get-EpiDeployment { <# .SYNOPSIS Retrieves deployments that have been triggered via the deployment api for the specified project id .DESCRIPTION Retrieves deployments that have been triggered via the deployment api for the specified project id .PARAMETER ClientKey The client key used to access the project .PARAMETER ClientSecret The client secret used to access the project .PARAMETER ProjectId The Id (should be a guid) of the project .PARAMETER Id The Id (should be a guid) of the deployment .EXAMPLE Get-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv .EXAMPLE Get-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv -Id d142a635-c09e-4c56-a4ba-394d0dd7a14a #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [String] $ClientKey, [Parameter(Mandatory=$true)] [String] $ClientSecret, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName = $true)] [String] $ProjectId, [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName = $true)] [String] $Id ) begin { } process { $uriEnding = "projects/$ProjectId/deployments" if ($Id) { $uriEnding += "/$Id" } $requestHash = GetApiRequestSplattingHash -UriEnding $uriEnding $invokeApiRequestSplat = @{ ClientSecret = $ClientSecret ClientKey = $ClientKey RequestSplattingHash = $requestHash } InvokeApiRequest @invokeApiRequestSplat } end { } } function Get-EpiDeploymentPackageLocation { <# .SYNOPSIS Retrieves the location where deployment packages can be uploaded .DESCRIPTION Retrieves the location where deployment packages can be uploaded This will be a SAS-link to an Azure blob storage account .EXAMPLE Get-EpiDeploymentPackageLocation -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv .PARAMETER ClientKey The client key used to access the project .PARAMETER ClientSecret The client secret used to access the project .PARAMETER ProjectId The Id (should be a guid) of the project #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [String] $ClientKey, [Parameter(Mandatory=$true)] [String] $ClientSecret, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName = $true)] [String] $ProjectId ) begin { } process { $uriEnding = "projects/$ProjectId/packages/location" $requestHash = GetApiRequestSplattingHash -UriEnding $uriEnding $invokeApiRequestSplat = @{ ClientSecret = $ClientSecret ClientKey = $ClientKey RequestSplattingHash = $requestHash } # Since the response only contains one property we expand it (InvokeApiRequest @invokeApiRequestSplat).location } end { } } function Reset-EpiDeployment { <# .SYNOPSIS Resets the specified deployment .DESCRIPTION Resets the specified deployment .PARAMETER ClientKey The client key used to access the project .PARAMETER ClientSecret The client secret used to access the project .PARAMETER ProjectId The Id (should be a guid) of the project. .PARAMETER Id The Id (should be a guid) of the deployment .PARAMETER Wait Specify this switch to wait for the deployment to finish. .PARAMETER WaitTimeoutMinutes The maximum amount of time, in minutes, to retry to check the deployment status. Default to 30 minutes. .PARAMETER PollingIntervalSeconds The time interval, in seconds, to check the deployment status. Default to 30 seconds. .EXAMPLE Reset-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId 423ae883-7202-44cb-a907-3006d0d1cd58 -Id d117c12c-d02e-4b53-aabd-aa8e00a47cdv #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [String] $ClientKey, [Parameter(Mandatory = $true)] [String] $ClientSecret, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String] $ProjectId, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String] $Id, [Parameter(Mandatory = $false)] [Switch] $Wait, [Parameter(Mandatory = $false)] [ValidateRange(1, 60)] [Int] $WaitTimeoutMinutes = 30, [Parameter(Mandatory = $false)] [ValidateRange(1, 60)] [Int] $PollingIntervalSeconds = 30 ) begin { } process { $uriEnding = "projects/$ProjectId/deployments/$Id/reset" $requestHash = GetApiRequestSplattingHash -UriEnding $uriEnding -Method 'Post' $invokeApiRequestParams = @{ ClientSecret = $ClientSecret ClientKey = $ClientKey RequestSplattingHash = $requestHash } $resetDeploymentDetails = InvokeApiRequest @invokeApiRequestParams if ($Wait.IsPresent) { $timeoutDate = (Get-Date).AddMinutes($WaitTimeoutMinutes) $getEpiDeploymentDetailsParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret ProjectId = $ProjectId Id = $Id } do { Start-Sleep -Second $PollingIntervalSeconds $resetDeploymentDetails = Get-EpiDeployment @getEpiDeploymentDetailsParams Write-Verbose -Message "Deployment status: $($resetDeploymentDetails.status)" } while ($resetDeploymentDetails.status -notin @('Failed', 'Succeeded') -and (Get-Date) -le $timeoutDate) } $resetDeploymentDetails } end { } } function Start-EpiDeployment { <# .SYNOPSIS Starts a code deployment for the specified project .DESCRIPTION Starts a code deployment for the specified project .PARAMETER ClientKey The client key used to access the project. .PARAMETER ClientSecret The client secret used to access the project. .PARAMETER ProjectId The project identifier. .PARAMETER SourceApp The source app(s) for the deployment (if no uploaded code package should be used) .PARAMETER SourceEnvironment The source environment for the deployment (if no uploaded code package should be used) .PARAMETER TargetEnvironment The target environment which the code is deploying to. .PARAMETER DeploymentPackage The code package(s) being deployed .PARAMETER UseMaintenancePage The flag to tell whether maintenance page is used during the deployment. .PARAMETER IncludeBlob Specify this switch to include blobs from the source environment .PARAMETER IncludeDb Specify this switch to include the SQL DB from the source environment .PARAMETER Wait Specify this switch to enable "polling" of the deployment until it's completed. .PARAMETER PollingIntervalSec The timeout, in seconds, to wait between retries when getting the deployment details. .PARAMETER WaitTimeOutSec The maximum amount of time to retry to get the deployment details. .EXAMPLE Start-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv -TargetEnvironment Integration -DeploymentPackage cms.app.1.0.0.nupkg Deploys a code package to the Integration environment .EXAMPLE Start-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv -TargetEnvironment Integration -DeploymentPackage cms.app.1.0.0.nupkg -Wait -PollingIntervalSec 10 -WaitTimeOutSec 1800 Deploys a code package to the Integration environment and waits for it to finish (for up to 30 minutes) .EXAMPLE Start-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv -SourceEnvironment Integration -SourceApp cms -TargetEnvironment Preproduction -IncludeBlob -IncludeDb Starts a deployment of the contents of the specified cms app and the blobs and dbs of that environment .EXAMPLE Start-EpiDeployment -ClientKey $myKey -ClientSecret $mySecret -ProjectId d117c12c-d02e-4b53-aabd-aa8e00a47cdv -SourceEnvironment Production -TargetEnvironment Integration -IncludeBlob -IncludeDb Starts a deployment of the contents of the production environment (blobs and db(s)) to the Integration environment #> [CmdletBinding(DefaultParameterSetName='DeploymentPackage')] param( [Parameter(Mandatory = $true)] [String] $ClientKey, [Parameter(Mandatory = $true)] [String] $ClientSecret, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [String] $ProjectId, [Parameter(Mandatory = $false, ParameterSetName = 'SourceEnvironment')] [ValidateSet('cms','commerce')] [String[]] $SourceApp, [Parameter(Mandatory = $true, ParameterSetName = 'SourceEnvironment')] [String] $SourceEnvironment, [Parameter(Mandatory = $true)] [String] $TargetEnvironment, [Parameter(Mandatory = $true, ParameterSetName = 'DeploymentPackage')] [String[]] $DeploymentPackage, [Parameter(Mandatory = $false)] [Switch] $UseMaintenancePage, [Parameter(Mandatory = $false, ParameterSetName = 'SourceEnvironment')] [Switch] $IncludeBlob, [Parameter(Mandatory = $false, ParameterSetName = 'SourceEnvironment')] [Switch] $IncludeDb, [Parameter(Mandatory = $false)] [Switch] $Wait, [Parameter(Mandatory = $false)] [ValidateRange(1, 60)] [Int] $PollingIntervalSec = 30, [Parameter(Mandatory = $false)] [ValidateRange(1, [int]::MaxValue)] [Int] $WaitTimeOutSec = 7200 ) begin {} process { if ($Wait.IsPresent) { $timeOutDateTime = (Get-Date).AddSeconds($WaitTimeOutSec) } else { $timeOutDateTime = Get-Date } $uriEnding = "projects/$ProjectId/deployments" $requestSplattingHash = GetApiRequestSplattingHash -UriEnding $uriEnding -Method 'Post' $startDeploymentParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret RequestSplattingHash = $requestSplattingHash RequestPayload = @{ TargetEnvironment = $TargetEnvironment MaintenancePage = $UseMaintenancePage.IsPresent } } if ($PSCmdlet.ParameterSetName -eq 'DeploymentPackage') { $startDeploymentParams.RequestPayload.Packages = $DeploymentPackage } elseif ($PSCmdlet.ParameterSetName -eq 'SourceEnvironment') { $startDeploymentParams.RequestPayload.sourceEnvironment = $SourceEnvironment if ($SourceApp) { $startDeploymentParams.RequestPayload.sourceApps = $SourceApp } $startDeploymentParams.RequestPayload.includeBlob = $IncludeBlob.IsPresent $startDeploymentParams.RequestPayload.includeDB = $IncludeDb.IsPresent if (-not $startDeploymentParams.RequestPayload.sourceApps -and -not $IncludeBlob.IsPresent -and -not $IncludeDb.IsPresent) { throw "You need to specify at least one of the following parameters: DeploymentPackage, SourceApp, IncludeBlob or IncludeDb." } } Write-Verbose "Starting deployment for the project: $($ProjectId) / targetEnvironment: $($TargetEnvironment)" $startDeploymentResponse = InvokeApiRequest @startDeploymentParams $deploymentCompletionStates = @('Failed', 'AwaitingVerification', 'Succeeded') do { if ($Wait.IsPresent) { Start-Sleep -Seconds $PollingIntervalSec } $getDeploymentParams = @{ ClientKey = $ClientKey ClientSecret = $ClientSecret ProjectId = $ProjectId Id = $startDeploymentResponse.id } $getDeploymentResponse = Get-EpiDeployment @getDeploymentParams Write-Verbose "Deployment status: $($getDeploymentResponse.status)" } while ($Wait.IsPresent -and $deploymentCompletionStates -notcontains $getDeploymentResponse.status -and (Get-Date) -le ($timeOutDateTime)) if ($Wait.IsPresent -and $deploymentCompletionStates -notcontains $getDeploymentResponse.status) { throw "Timed out during deployment with status: $($getDeploymentResponse.status)" } $getDeploymentResponse } end {} } |