Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions BotProject/CSharp/Scripts/create.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
Param(
[string] $name,
[string] $location,
[string] $appId,
[string] $appPassword,
[string] $environment,
[string] $projDir = $(Get-Location),
[string] $logFile = $(Join-Path $PSScriptRoot .. "create_log.txt")
)

if ($PSVersionTable.PSVersion.Major -lt 6){
Write-Host "! Powershell 6 is required, current version is $($PSVersionTable.PSVersion.Major), please refer following documents for help."
Write-Host "For Windows - https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-6"
Write-Host "For Mac - https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-6"
Break
}

# Reset log file
if (Test-Path $logFile) {
Clear-Content $logFile -Force | Out-Null
}
else {
New-Item -Path $logFile | Out-Null
}

if (-not (Test-Path (Join-Path $projDir 'appsettings.json')))
{
Write-Host "! Could not find an 'appsettings.json' file in the current directory." -ForegroundColor DarkRed
Write-Host "+ Please re-run this script from your project directory." -ForegroundColor Magenta
Break
}

# Get mandatory parameters
if (-not $name) {
$name = Read-Host "? Bot Name (used as default name for resource group and deployed resources)"
}

if (-not $environment)
{
$environment = Read-Host "? Environment Name (single word, all lowercase)"
$environment = $environment.ToLower().Split(" ") | Select-Object -First 1
}

if (-not $location) {
$location = Read-Host "? Azure resource group region"
}

if (-not $appPassword) {
$appPassword = Read-Host "? Password for MSA app registration (must be at least 16 characters long, contain at least 1 special character, and contain at least 1 numeric character)"
}

if (-not $appId) {
# Create app registration
$app = (az ad app create `
--display-name $name `
--password `"$($appPassword)`" `
--available-to-other-tenants `
--reply-urls 'https://token.botframework.com/.auth/web/redirect' `
--output json)

# Retrieve AppId
if ($app) {
$appId = ($app | ConvertFrom-Json) | Select-Object -ExpandProperty appId
}

if(-not $appId) {
Write-Host "! Could not provision Microsoft App Registration automatically. Review the log for more information." -ForegroundColor DarkRed
Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed
Write-Host "+ Provision an app manually in the Azure Portal, then try again providing the -appId and -appPassword arguments. See https://aka.ms/vamanualappcreation for more information." -ForegroundColor Magenta
Break
}
}

$resourceGroup = "$name-$environment"
$servicePlanName = "$name-$environment"

# Get timestamp
$timestamp = Get-Date -f MMddyyyyHHmmss

# Create resource group
Write-Host "> Creating resource group ..."
(az group create --name $resourceGroup --location $location --output json) 2>> $logFile | Out-Null

# Deploy Azure services
Write-Host "> Validating Azure deployment ..."
$validation = az group deployment validate `
--resource-group $resourcegroup `
--template-file "$(Join-Path $PSScriptRoot '..' 'DeploymentTemplates' 'template-with-preexisting-rg.json')" `
--parameters appId=$appId appSecret="`"$($appPassword)`"" newAppServicePlanName=$servicePlanName appServicePlanLocation=$location botId=$name `
--output json

if ($validation) {
$validation >> $logFile
$validation = $validation | ConvertFrom-Json

if (-not $validation.error) {
Write-Host "> Deploying Azure services (this could take a while)..." -ForegroundColor Yellow
$deployment = az group deployment create `
--name $timestamp `
--resource-group $resourceGroup `
--template-file "$(Join-Path $PSScriptRoot '..' 'DeploymentTemplates' 'template-with-preexisting-rg.json')" `
--parameters appId=$appId appSecret="`"$($appPassword)`"" newAppServicePlanName=$servicePlanName appServicePlanLocation=$location botId=$name `
--output json
}
else {
Write-Host "! Template is not valid with provided parameters. Review the log for more information." -ForegroundColor DarkRed
Write-Host "! Error: $($validation.error.message)" -ForegroundColor DarkRed
Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed
Write-Host "+ To delete this resource group, run 'az group delete -g $($resourceGroup) --no-wait'" -ForegroundColor Magenta
Break
}
}


# Get deployment outputs
$outputs = az group deployment show `
--name $timestamp `
--resource-group $resourceGroup `
--output json 2>> $logFile

# If it succeeded then we perform the remainder of the steps
if ($outputs)
{
# Log and convert to JSON
$outputs >> $logFile
$outputs = $outputs | ConvertFrom-Json
$outputMap = @{}
$outputs.PSObject.Properties | Foreach-Object { $outputMap[$_.Name] = $_.Value }

# Update appsettings.json
Write-Host "> Updating appsettings.json ..."
if (Test-Path $(Join-Path $projDir appsettings.json)) {
$settings = Get-Content $(Join-Path $projDir appsettings.json) | ConvertFrom-Json
}
else {
$settings = New-Object PSObject
}

$settings | Add-Member -Type NoteProperty -Force -Name 'microsoftAppId' -Value $appId
$settings | Add-Member -Type NoteProperty -Force -Name 'microsoftAppPassword' -Value $appPassword
$settings | Add-Member -Type NoteProperty -Force -Name 'bot' -Value "RunningInstance"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunningInstance [](start = 70, length = 15)

wenyi is working on editing environment variables in composer and post them to bot project, how could those settings passed to this deployment script??

@zidaneymar zidaneymar Aug 29, 2019

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now the script search the appsettings.json file in bot and merge with the main appsettings.json in BotProject root folder.


foreach ($key in $outputMap.Keys) { $settings | Add-Member -Type NoteProperty -Force -Name $key -Value $outputMap[$key].value }
$settings | ConvertTo-Json -depth 100 | Out-File $(Join-Path $projDir appsettings.json)

Write-Host "> Done."
Write-Host "- App Id: $appId"
Write-Host "- App Password: $appPassword"
Write-Host "- Resource Group: $resourceGroup"
Write-Host "- ServicePlan: $servicePlanName"
Write-Host "- Bot Name: $name"
Write-Host "- Web App Name : $name"
}
else
{
# Check for failed deployments
$operations = az group deployment operation list -g $resourceGroup -n $timestamp --output json 2>> $logFile | Out-Null

if ($operations) {
$operations = $operations | ConvertFrom-Json
$failedOperations = $operations | Where { $_.properties.statusmessage.error -ne $null }
if ($failedOperations) {
foreach ($operation in $failedOperations) {
switch ($operation.properties.statusmessage.error.code) {
"MissingRegistrationForLocation" {
Write-Host "! Deployment failed for resource of type $($operation.properties.targetResource.resourceType). This resource is not avaliable in the location provided." -ForegroundColor DarkRed
Write-Host "+ Update the .\Deployment\Resources\parameters.template.json file with a valid region for this resource and provide the file path in the -parametersFile parameter." -ForegroundColor Magenta
}
default {
Write-Host "! Deployment failed for resource of type $($operation.properties.targetResource.resourceType)."
Write-Host "! Code: $($operation.properties.statusMessage.error.code)."
Write-Host "! Message: $($operation.properties.statusMessage.error.message)."
}
}
}
}
}
else {
Write-Host "! Deployment failed. Please refer to the log file for more information." -ForegroundColor DarkRed
Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed
}

Write-Host "+ To delete this resource group, run 'az group delete -g $($resourceGroup) --no-wait'" -ForegroundColor Magenta
Break
}
137 changes: 137 additions & 0 deletions BotProject/CSharp/Scripts/deploy.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
Param(
[string] $name,
[string] $environment,
[string] $luisAuthoringKey,
[string] $luisAuthoringRegion,
[string] $projFolder = $(Get-Location),
[string] $botPath,
[string] $logFile = $(Join-Path $PSScriptRoot .. "deploy_log.txt")
)

if ($PSVersionTable.PSVersion.Major -lt 6){
Write-Host "! Powershell 6 is required, current version is $($PSVersionTable.PSVersion.Major), please refer following documents for help."
Write-Host "For Windows - https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-6"
Write-Host "For Mac - https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-6"
Break
}

# Get mandatory parameters
if (-not $name) {
$name = Read-Host "? Bot Web App Name"
}

if (-not $environment)
{
$environment = Read-Host "? Environment Name (single word, all lowercase)"
$environment = $environment.ToLower().Split(" ") | Select-Object -First 1
}

if (-not $botPath) {
$botPath = Read-Host "? The Reletive Path Of Bot"
}


# Reset log file
if (Test-Path $logFile) {
Clear-Content $logFile -Force | Out-Null
}
else {
New-Item -Path $logFile | Out-Null
}

# Check for existing deployment files
if (-not (Test-Path (Join-Path $projFolder '.deployment'))) {
# Add needed deployment files for az
az bot prepare-deploy --lang Csharp --code-dir $projFolder --proj-file-path BotProject.csproj --output json | Out-Null
}

# Delete src zip, if it exists
$zipPath = $(Join-Path $projFolder 'code.zip')
if (Test-Path $zipPath) {
Remove-Item $zipPath -Force | Out-Null
}

# Perform dotnet publish step ahead of zipping up
$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp2.2')
dotnet publish -c release -o $publishFolder -v q > $logFile

# Copy bot files to running folder
$remoteBotPath = $(Join-Path $publishFolder "RunningInstance")
Remove-Item $remoteBotPath -Recurse -ErrorAction Ignore
Copy-Item -Path $botPath -Recurse -Destination $remoteBotPath -Container -Force

# Merge from custom config files
$customConfigFiles = Get-ChildItem -Path $remoteBotPath -Include "appsettings.json" -Recurse -Force
if ($customConfigFiles)
{
if (Test-Path $(Join-Path $publishFolder appsettings.json)) {
$settings = Get-Content $(Join-Path $publishFolder appsettings.json) | ConvertFrom-Json
}
else {
$settings = New-Object PSObject
}

$customConfig = @{}
$customSetting = Get-Content $customConfigFiles.FullName | ConvertFrom-Json
$customSetting.PSObject.Properties | Foreach-Object { $customConfig[$_.Name] = $_.Value }
foreach ($key in $customConfig.Keys) { $settings | Add-Member -Type NoteProperty -Force -Name $key -Value $customConfig[$key] }

$settings | ConvertTo-Json -depth 100 | Out-File $(Join-Path $publishFolder appsettings.json)
}

# Add Luis Config to appsettings
if ($luisAuthoringKey -and $luisAuthoringRegion)
{
# change setting file in publish folder
if (Test-Path $(Join-Path $publishFolder appsettings.json)) {
$settings = Get-Content $(Join-Path $publishFolder appsettings.json) | ConvertFrom-Json
}
else {
$settings = New-Object PSObject
}

$luisConfigFiles = Get-ChildItem -Path $publishFolder -Include "luis.settings*" -Recurse -Force

$luisAppIds = @{}

foreach ($luisConfigFile in $luisConfigFiles)
{
$luisSetting = Get-Content $luisConfigFile.FullName | ConvertFrom-Json
$luis = $luisSetting.luis
$luis.PSObject.Properties | Foreach-Object { $luisAppIds[$_.Name] = $_.Value }
}

$luisEndpoint = "https://$luisAuthoringRegion.api.cognitive.microsoft.com"

$luisConfig = @{}

$luisConfig["endpointKey"] = $luisAuthoringKey
$luisConfig["endpoint"] = $luisEndpoint

foreach ($key in $luisAppIds.Keys) { $luisConfig[$key] = $luisAppIds[$key] }

$settings | Add-Member -Type NoteProperty -Force -Name 'luis' -Value $luisConfig

$settings | ConvertTo-Json -depth 100 | Out-File $(Join-Path $publishFolder appsettings.json)
}

$resourceGroup = "$name-$environment"

if($?)
{
# Compress source code
Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null

# Publish zip to Azure
Write-Host "> Publishing to Azure ..." -ForegroundColor Green
(az webapp deployment source config-zip `
--resource-group $resourceGroup `
--name $name `
--src $zipPath `
--output json) 2>> $logFile | Out-Null
}
else
{
Write-Host "! Could not deploy automatically to Azure. Review the log for more information." -ForegroundColor DarkRed
Write-Host "! Log: $($logFile)" -ForegroundColor DarkRed
}