How do I deploy to Azure App Service with PowerShell (az module)? - azure

I want to deploy app services from Powershell.
I would like to use only publish profile (no password for azure account).
I tried FTP service, but sometimes files are blocked by running users.
I think I have to stop app service.
There is powershell command like:
Publish-AzWebApp
However first I need login with:
Connect-AzAccount
and pass credentials what I want to avoid.
There is any way to call Publish-AzWebApp based on only publish profile (no login by account)?
Connect-AzAccount has other options to login (token or certificate).
Unfortunately I don't know how to generate it.
BTW There was a topic about it:
How do I deploy to Azure App Service with PowerShell?
But it is old and now module "az" is recommended.

There is any way to call Publish-AzWebApp based on only publish profile (no login by account)?
No, you can't. If you want to use the Publish-AzWebApp , you always need to login with Connect-AzAccount, whatever the parameters you use, examples here.
If you want to use powershell to deploy the web app based on only publish profile, the workaround is to use Kudu API via powershell.
$username = "`$webappname"
$password = "xxxxxxx"
# Note that the $username here should look like `SomeUserName`, and **not** `SomeSite\SomeUserName`
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
$userAgent = "powershell/1.0"
$apiUrl = "https://joywebapp.scm.azurewebsites.net/api/zipdeploy"
$filePath = "C:\Users\joyw\Desktop\testdep.zip"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method POST -InFile $filePath -ContentType "multipart/form-data"

You may refer to this tutorial: https://learn.microsoft.com/en-us/powershell/azure/authenticate-azureps?view=azps-2.5.0#sign-in-with-a-service-principal-

Here is the step by step process of deploying and publishing an Azure app service with PowerShell (PS) using newly recommended Az module. You'll have to install Azure CLI before running the scripts:
$subscription = 'Visual Studio Enterprise – MPN' #Change it as per your Azure subscription
$location = 'Central US' #Change it according to the location where you want to host your web app
$resourceGroup = 'MyWebAppResourceGroup'
$ErrorActionPreference = "Stop" #this ensures that script stops executing at first error in the script.
Write-host "Installing nuget package provider"
Install-PackageProvider -Name NuGet -Scope CurrentUser -MinimumVersion 2.8.5.201 -Force
Write-Host "Setting Power Shell gallery"
Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
Write-Host "Installing missing PowerShell modules required for running this script.."
if ((Get-InstalledModule -Name "Az.Accounts" -ErrorAction SilentlyContinue) -eq $null) {
Write-Host "Az.Accounts module missing. Now installing..."
Install-Module -Name Az.Accounts -Scope CurrentUser
}
if ((Get-InstalledModule -Name "Az.Websites" -ErrorAction SilentlyContinue) -eq $null) {
Write-Host "Az.Websites module missing. Now installing .."
Install-Module -Name Az.Websites -Scope CurrentUser
}
Write-Host "Installing PowerShell modules completed."
Write-Host "Staring to import PowerShell modules in current session...."
Import-Module Az.websites
Write-Host "Importing PowerShell modules completed."
#This is required due to an issue due to which PowerShell fails to connect with online resources. This issue is machine specific. So you can comment it if not required.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "Connecting to Azure account..."
Connect-AzAccount
Write-Host "Setting subscription for current session..."
az account set --subscription $subscription
Write-Host "Creating resource group..."
az group create --name $resourceGroup --location $location
$webAppName="WelcomeCloudApp"
$appServicePlan="WelcomeCloudAppServicePlan"
Write-Host "Creating WebApp Service plan..."
New-AzAppServicePlan -Name $appServicePlan -ResourceGroupName $resourceGroup -Location $location -Tier 'Free' #-Debug
Write-Host "Creating WebApp..."
New-AzWebApp -Name $webAppName -Location $location -AppServicePlan $appServicePlan -ResourceGroupName $resourceGroup
Write-Host "Publishing WebApp..."
Publish-AzWebApp -ResourceGroupName $resourceGroup -Name $webAppName -ArchivePath WelcomeCloudAppService.zip
Write-Host "Finished installing your web app. Bye!"

Related

Connect-AzAccount with Azure Devops Pipeline?

I am finding difficulties in finding the best and secure way to use connect-azaccount with azure devops pipeline. I have in the pipeline the following this simple powershell script which is used to create azure resources. Just to simplify things I only used the creation of a resource group:
$Location = "Location Name"
$resourceGroupName = "Resource Group Name"
try {
#Creation of Resource Group
$resourceGroup = Get-AzResourceGroup -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if($null -eq $resourceGroup)
{
New-AzResourceGroup -Name $resourceGroupName -Location $Location
}
else
{
Write-Host "The ResourceGroup with the name: $resourceGroupName already exists."
}
}
catch
{
Write-Host "Error occurred: $_"
}
The problem here is when the pipeline is being run and it reaches the Powershell task, it gives me an error, Error occurred: Run Connect-AzAccount to login.
My issue here is that I honestly don't know which way is the most secure way to connect without typing any user credentials. It should directly connect and create the resources. Note that I am using Multi-Factor Authentication. In order to achieve that I found several solutions but I need help in choosing the best way. I found several solutions by adding a powershell task in the Yaml file. Here is the Yaml showing the powershell task to run the script:
- task: PowerShell#2
inputs:
filePath: '$(Pipeline.Workspace)/Deploy/functionapp.ps1'
Option 1:
Connect-AzAccount -Tenant 'xxxx-xxxx-xxxx-xxxx' -SubscriptionId 'yyyy-yyyy-yyyy-yyyy'
Now the problem here is that the Tenant ID and Subscription are going to be visible in the code and that is a very bad practice
Option 2 is to use the following script:
$User = "xxx#xxxx.onmicrosoft.com"
$PWord = ConvertTo-SecureString -String "<Password>" -AsPlainText -Force
$tenant = "<tenant id>"
$subscription = "<subscription id>"
$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User,$PWord
Connect-AzAccount -Credential $Credential -Tenant $tenant -Subscription $subscription
This is very similar to the first, but if I am not mistaken it is limited to a specific user.
Option 3 is to use a service principal:
$azureAplicationId ="Azure AD Application Id"
$azureTenantId= "Your Tenant Id"
$azurePassword = ConvertTo-SecureString "strong password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
I don't know if creating a service principal will incur any costs and what steps should I do to make it work.
I am honestly new to all this, can someone please provide me what are the exact steps to achieve this. Thank you for your answers :)
The most secure way is to create an Azure Resource Manager service connection and use it in your pipeline. You can create it using automated way, or manually using previously created service principal.

restart cloud service using powershell

we have a problem with a Microsoft bot hosted in Azure.
As long as we haven't resolved it, we want to periodically restart it.
We found 3 sets of powershell commands and spent the full day on it without making it work.
Solution 1:
we found the cmdlets : Get-AzCloudService Restart-AzCloudService.
We didn't understand from the documentation what module to install.
It returns : The term 'Restart-AzCloudService' is not recognized as the name of a cmdlet.
They talk about an obscure "extended support" to have access to it.
Solution 2:
We are able to list the cloud service using:
Connect-AzAccount
get-azresource -name $serviceName -resourcetype
"Microsoft.BotService/botServices"
But we do not find the cmdlet to restart the resource.
Solution 3:
Reset-AzureRoleInstance -serviceName $serviceName -Slot "production" -InstanceName $serviceName
Error : No default subscription has been designated. Use Select-AzureSubscription -Default
We are using MFA. Login-AzureRmAccount systematically fails , evenly saying that our account is disabled.
We did no manager to run the sequence:
Login-AzureRmAccount
Select-AzureSubscription -Default
Reset-AzureRoleInstance -serviceName $serviceName -Slot "production" -InstanceName $serviceName
The idea is to run this script twice a day, either from a VM or from an Azure Runbook.
We managed to run this code using an automation Account but we are still missing the last command that would restart the bot (that we consider a cloud service).
Param()
$automationAccount = "xxx"
$resourceGroup = "xxx"
$serviceName = "xxx"
$subscriptionname ="xxx"
$subscriptionid ="xxx"
# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process | Out-Null
# Connect using a Managed Service Identity
try {
$AzureContext = (Connect-AzAccount -Identity).context
}
catch{
Write-Output "There is no system-assigned user identity. Aborting.";
exit
}
#Set-AzureSubscription -SubscriptionId $subscriptionid
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription `
-DefaultProfile $AzureContext
get-azresource -name $serviceName -resourcetype "Microsoft.BotService/botServices"

How do you associate an Azure web app with a vnet using PowerShell Az?

I know it can be done using Azure CLI like this:
az webapp vnet-integration add -g $resourceGroupName -n $applicationName --vnet $vnetName --subnet $subnetName
Is there an equivalent command using PowerShell Az?
If you reference the docs at https://learn.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet, at the bottom is a link to the Script Center gallery where this is a full PS1 script at https://gallery.technet.microsoft.com/scriptcenter/Connect-an-app-in-Azure-ab7527e3 which shows how to integrate web app with vnet.
The final lines of interest (it uses AzureRM, but should be easy to convert to Az):
$PropertiesObject = #{
"vnetName" = $VirtualNetworkName; "vpnPackageUri" = $packageUri
}
New-AzureRmResource -Location $location -Properties $PropertiesObject -ResourceName "$($webAppName)/$($vnetName)/primary" -ResourceType "Microsoft.Web/sites/virtualNetworkConnections/gateways" -ApiVersion 2015-08-01 -ResourceGroupName $webAppResourceGroup -Force

Deploy Code from GitLab Repository to Azure Web App using PowerShell and Azure CLI

I would like to setup continuous deployment from a GitLab repository to an Azure App using a PowerShell script and the Azure CLI. There is already an answer for doing this using the Azure RM module and Windows PowerShell, but as these are now deprecated, I am looking specifically for a solution that uses the new Az module and PowerShelll Core.
The solution should give a a PowerShell (Core) script to setup a Continuous Deployment directly from GitLab to Azure. It must make use of the Az module. Once the setup script is run, each subsequent commit/merge to the GitLab repository should then automatically be deployed to Azure. Preferably, this PowerShell script should work for both public and private repositories that are hosted on GitLab, but I'm willing to accept solutions that only work on public repositories.
I was playing around with gitlab and kudu rest APIs, and figured out how to automate manual solution you mentioned. The only extra step is to add gitlab api token to your code, but you just do it once for all projects. You can get it from your gitlab account settings under "Access Tokens". Some other notes:
To interact with kudu api the script is using autogenerated
deployment credentials. But you can create a separate user for
deployment and use it in all other projects (skipping that step). You
can do it in azure CLI:
az webapp deployment user set --user-name someUser --password somepassword
GitLab API is using project ID, not the project name. The script is
trying to retrieve project id automatically from repo URL, but you
might copy/paste it from the project general setting on gitlab to be
safe.
This solution works with private repos too. The only thing you'll see
some error while creating a resource (because ssh key is not set up
yet). But after script is completed it should be fine, so ignore the
error. For public repos you can skip that key set up stuff at all
Here is the script:
function log {param($memo); Write-Host "[$((get-date).ToString("HH:mm:ss"))]: $memo" -ForegroundColor Green}
# =============== App and GitLab settings ==============
$webapp="geekscodeStackOverflow"
$resgroup = $webapp + "Group"
$plan = $webapp + "Plan"
$location="centralus"
$gitToken = "yourGitLabTokenHere"
$repoUrl = "https://gitlab.com/MagicAndi/geekscode.net"
# $projID = "99..."
# ============== DEPLOYMENT SCRIPT ==========================#
log "Setting up the app on azure"
New-AzResourceGroup -Name $resgroup -Location $location
New-AzAppServicePlan -Name $plan -Location $location -ResourceGroupName $resgroup -Tier Free
New-AzWebApp -Name $webapp -Location $location -AppServicePlan $plan -ResourceGroupName $resgroup
$appInfo = Get-AzWebApp -Name $webapp
$appRef = #{Name=$appInfo.Name; ResourceGroupName = $appInfo.ResourceGroup}
if(!$appInfo){Write-Host "app deployment failed" -ForegroundColor Red; return} else {Write-Host "App created:" -ForegroundColor Green}
# ================= linking web app to gitlab =========================
# you can do this manually: app dashboard / Deployment Centrer / External / App Service Kudu / git
log "setting up deployment "
$deployment = #{
PropertyObject = #{ repoUrl = $repoUrl; branch = "master"; isMercurial= $false; isManualIntegration = $true }
ResourceGroupName = $appInfo.ResourceGroup
ResourceType = "Microsoft.Web/sites/sourcecontrols"
ResourceName = $appInfo.Name + "/web"
ApiVersion = "2018-02-01"
}
# you'll get error on this step for private repos because the key is not set up yet. You can ignore that error
Set-AzResource #deployment -Force
log "Extracting Deployment credentials"
# you can also create a user credentials in AZ CLI and skip this or manually get it in App's deployment center
$prof = Get-AzWebAppPublishingProfile #appRef | Select-Xml -XPath "//*[#publishMethod='MSDeploy']"
$deployCreds = $prof.node.userName + ":" + $prof.node.userPWD
log "Extracting Deployment key"
# Can skip for public repors
$keyUrl = "https://$webapp.scm.azurewebsites.net/api/sshkey?ensurePublicKey=1"
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($deployCreds))
$head = #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$deployKey = Invoke-RestMethod -Uri $keyUrl -Headers $head -Method Get
#============== Setting Up GIT LAB ================ #
$gitApi = "https://gitlab.com/api/v4"
$gitHead = #{'PRIVATE-TOKEN'= $gitToken; 'Content-Type'='application/json'}
# looking up project id by user/repo name. You can skip that and get the id from project general setting on GitLab
$repo = $repoUrl.Split("/")[-2,-1] -join "%2F"
$project = Invoke-RestMethod -Uri "$gitApi/projects/$repo" -Headers $head
$projID = $project.id
log "Setting up $repoUrl (project id $projID)"
# --- Adding deploy key to GitLab project (public repos can skip) ---
# You can copy the key manually - Go to Project / Settings / Repository / Deploy Keys
log "Adding deploy keys to GitLab project"
$keyBody = #{title="Azure_Key";key=$deployKey; can_push=$true} | ConvertTo-Json
Invoke-RestMethod "$gitApi/projects/$projID/deploy_keys/" -Headers $gitHead -Body $keyBody -Method Post
log "Setting up a webhook"
# this can be set manualy - go to Project / Settings / Integrations.
$whBody = #{url = "https://$deployCreds#$webapp.scm.azurewebsites.net/deploy"} | ConvertTo-Json
Invoke-RestMethod -Uri "$gitApi/projects/$projID/hooks/" -Headers $gitHead -Body $whBody -Method Post
log "deployment completed `ncheck out your app at https://$webapp.azurewebsites.net"
Try the command below for Az, my repository is public, it works fine on my side.
$gitrepo="your git repository url"
$webappname="joyazapp"
$location="centralus"
New-AzResourceGroup -Name joyazgroup -Location $location
New-AzAppServicePlan -Name joyazplan -Location $location -ResourceGroupName joyazgroup -Tier Free
New-AzWebApp -Name joyazapp -Location $location -AppServicePlan joyazplan -ResourceGroupName joyazgroup
$PropertiesObject = #{
repoUrl = "$gitrepo";
branch = "master";
isManualIntegration = $false
}
Set-AzResource -PropertyObject $PropertiesObject -ResourceGroupName joyazgroup -ResourceType Microsoft.Web/sites/sourcecontrols -ResourceName $webappname/web -ApiVersion 2018-02-01 -Force

Unable to download deployment content from private github repository URI

I created new GitHub private repository, in that I added ARM templates for Azure key vault. After that I am trying to deploy ARM template from my local machine using PowerShell tool.
This is PowerShell script I used for deploying ARM template into azure.
#Login-AzureRmAccount
#region Parameters
$resourceGroupName='KZEU-ARMTMP-SB-DEV-RGP-01'
$location='eastus'
$parametersUri='E:\Kishore\Kishore GitHub\ARMTemplates\Parameters\StorageAccount.parameters.json'
$templateUri='https://raw.githubusercontent.com/xxxxxxx/ARMTemplates/master/Templates/StorageAccount.json?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$clientID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx="
#endregion
#region Login into Azure
$SecurePassword = $key | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $clientID, $SecurePassword
Add-AzureRmAccount -Credential $cred -Tenant "xxxxxxxxxxxxxxxxxxxxxx" - ServicePrincipal
Set-AzureRmContext -SubscriptionID 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
#endregion
#region Check or Create Resource Group
Get-AzureRmResourceGroup -Name $resourceGroupName -ev notPresent -ea 0
if($notPresent){
Write-Host "Failover RG '$resourceGroupName' doesn't exist. Creating a new in $location...." -ForegroundColor Yellow
New-AzureRmResourceGroup -Name $resourceGroupName -Location $location
}else{
Write-Host "Using existing resource group '$resourceGroupName'" -ForegroundColor Yellow;
}
#endregion
#region Validate & Deploy ARM Templates
try{
$templateValidationResult= Test-AzureRmResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $templateUri -TemplateParameterFile $parametersUri -Verbose
if($templateValidationResult[0].Code-eq"InvalidTemplateDeployment"){
Write-Host "Failed to validate ARM template"
exit 1
}else{
Write-Host "Successfully completed to validate ARM template"
$deploymentResult= New-AzureRmResourceGroupDeployment -Name StorageAccount-Deployment -ResourceGroupName $resourceGroupName -TemplateFile $templateUri -TemplateParameterFile $parametersUri -Verbose
if($deploymentResult.ProvisioningState-eq"Succeeded"){
Write-Host "Successfully completed to deploy ARM template"
}else{
Write-Host "Failed to deploy ARM template"
exit 1
}
}
}
catch{
$ex = $_.Exception | Format-List -Force
Write-Host $ex
}
#endregion
When I run the above PowerShell script, then I am getting the error like
Unable to download deployment content from "https://raw.githubusercontent.com/xxxx/demo-in/master/xxxx/keyVault.json"
So, can anyone suggest me how to resolve the above issue?
Your issue is that you can't deploy from a private repo (see doc). What you are trying to do is pass a template URI for Azure to read and it doesn't have permission to read from your private repo. You have a couple options:
Do like the docs say and save the deploy.json to Azure Storage
and protect it with a SAS token.
You can clone your repo locally and
deploy from the local file.

Resources