azure clone bug workaround - powershell

Working on CD pipe line for our web applications on Azure,
Im trying to create a deploy slot with a copy of the production site .
I tried to work with Clone in powershell with this article :
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-app-cloning
$srcapps = Get-AzureRmWebApp -ResourceGroupName $ResourceGroupname -Name $webappname
$destapp = New-AzureRmWebAppSlot -ResourceGroupName $ResourceGroupname -Name $webappname -Slot SLOTNAME -SourceWebApp $srcapps
But when i execute it i get error:
New-AzureRmWebAppSlot : Parameter ServerFarmId is null or empty.
Googling this error got me to this :
https://github.com/Azure/azure-powershell/issues/3633
Saying :
Attempting to use output object from Get-AzureRmWebApp to direct
Get-AzureRmWebAppSlot fails due to a typing issue, although both types
appear to be identical.
Describing exactly my situation
Am i missing something ?
Did any one found a work around for it ?
Any other approaches to create a deploy slot with a copy of the production site ?
thanks !

In your command, you should add -AppServicePlan <your plan>.
But I test in my lab, it seems it is possible for you to do this, I suggest you should clone your app firstly, then use cloned app to create a slot.

Related

How do I update the IP whitelist for a staging slot via Azure Powershell from an Azure DevOps Release Pipeline?

I have an application hosted in Azure, and I use Azure DevOps to manage my build and release pipelines. As part of the release, I warm up the application by making a request to the root url (e.g. https://myapp.azurewebsites.net). In order to make this request I must first make sure the hosted build agent running the deployment has access to that url (or I will get a 403). I have written a short powershell script to achieve this, and put it in an Azure Powershell task. It adds the IP of the build agent to the IpSecurityConfiguration of the app service. So far so good. It works perfectly for apps that are just apps. Where it falls down is when I try to use it against a staging environment. When we release to production we first push the code to a staging slot, then flip it over to live when we've run our tests and made sure everything is good. The powershell script that correctly handles the IpSecurityConfiguration for the app services does not work on the staging slot. To access a staging slot, we use myappname/slots/staging for the variable $(WebApiName), normally it would just be the name of the app service itself. Again, this works perfectly if I run the script from my local environment, it only fails in the pipeline. The code is below:
# Whitelist Azure Agent IPs
$agentIP = Invoke-RestMethod http://ipinfo.io/json | Select -exp ip
Write-Host "Connecting to Azure"
$APIVersion = ((Get-AzureRmResourceProvider -ProviderNamespace Microsoft.Web).ResourceTypes | Where-Object ResourceTypeName -eq sites).ApiVersions[0]
Write-Host "API Version is $APIVersion. Getting web app config for $(WebApiName) in $(ResourceGroupName)"
$WebApiConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/config -ResourceName $(WebApiName) -ResourceGroupName $(ResourceGroupName) -ApiVersion $APIVersion)
Write-Host "Got web app config: $WebApiConfig"
$webIP = [PSCustomObject]#{
ipAddress = "$agentIP/32";
action = "Allow";
tag = 'Default';
priority = 300;
name = $agentIP.ToString();
description = $agentIP.ToString()
}
Write-Host "Adding $agentIP to security restrictions"
$WebApiConfig.Properties.ipSecurityRestrictions += $webIP
Write-Host "Updating security restrictions"
# update app restrictions, do not prompt for confirmation
$result = Set-AzureRmResource -ResourceId $WebApiConfig.ResourceId -Properties $WebApiConfig.Properties -ApiVersion $APIVersion -Force
To muddy the water somewhat, I can get the exact same code to work perfectly with the staging slot locally by changing
$WebApiConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/config -ResourceName $(WebApiName) -ResourceGroupName $(ResourceGroupName) -ApiVersion $APIVersion)
to
$WebApiConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites -ResourceName $(WebApiName)/config -ResourceGroupName $(ResourceGroupName) -ApiVersion $APIVersion)
but this doesn't work in the Azure Powershell task. Instead I can't deploy to any environment because the task fails while trying to access IpSecurityRestrictions on the $WebApiConfig object. The exception is "Exception setting "ipSecurityRestrictions": "The property 'ipSecurityRestrictions' cannot be found on this object. Verify that the property exists and can be set."
As I said earlier, if I run the script in exactly this form locally, it works perfectly. Obviously I have to manually replace the variables that come from the build pipeline, but otherwise there is no difference between code that works exactly as I want it to on my local machine and code that fails in the release. You can verify this by swapping out $(WebApiName) for a valid app service name and $(ResourceGroupName) for the resource group that app service is in. I put a line in about halfway down that outputs $WebApiConfig so that I can see what it is, and on my local machine I see a valid object, while in the output of the task I get nothing. The line just says "Got web app config:"
Anyone got any ideas?
I've tried changing the version of powershell used by the task to
match the version I've got.
I've tried using the preview version of the task (v4, otherwise I've been using v3).
I've tried every permutation of /sites/config everywhere I can think of in the call to Get-AzureRmResource (since that was what allowed it to work locally on the slot).
Just one final thing in case anyone wonders. I'm doing it this way instead of whitelisting all the IPs in Microsoft's list (https://www.microsoft.com/en-us/download/confirmation.aspx?id=41653) for two reasons, firstly it's a lot easier to maintain a short list of our own IPs, and secondly there seems to be a bug somewhere in the way Azure handles those CIDR definitions because IPs that are categorically in those ranges are frequently blocked during our deployments even when we have the entire file whitelisted. This way I just add whichever IP is currently being used dynamically to the whitelist, and remove it after we're done. Assuming I can get it to work...
Finally figured out the solution to this. In order to work with slots the resource type has to be subtly different. This line works in an Azure Powershell task:
$WebApiConfig = (Get-AzureRmResource -ResourceType Microsoft.Web/sites/slots/config -ResourceName $(WebApiName) -ResourceGroupName $(ResourceGroupName) -ApiVersion $APIVersion)
Posting in case it helps anyone else with the same issue. I can confirm that the approach I've taken works great in managing access to Azure sites by build agents, and saves a lot of messing around with Microsoft's build agent xml file.

Switch-AzureWebsiteSlot issue when swapping with PowerShell

I try to perform a swap between 2 Azure slots (Staging and Production) on a QA environment. For that I use PowerShell and use Switch-AzureWebsiteSlot cmdlet.
Below what I execute:
*`
Switch-AzureWebsiteSlot -Name "http://qa-2.cloudapp.net/" -Slot1
"Production" -Slot2 "Staging" -Force -Verbose -Debug
`*
But I got the following error:
Switch-AzureWebsiteSlot : The website must have at least two slots to
apply swap At
C:\PrivateAgents\agent2_work\r6\a\MyCompany-CI-Template\drop#1129\mycompany-swapslots-azure.ps1:222
char:2
+ Switch-AzureWebsiteSlot -Name "http://qa-2.cloudapp.net/" -Slot1 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Switch-AzureWebsiteSlot], PSInvalidOperationException
+ FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Websites.SwitchAzureWebsiteSlotCommand
DEBUG: AzureQoSEvent: CommandName - Switch-AzureWebsiteSlot; IsSuccess
- False; Duration - 00:01:02.5624486; Exception - System.Management.Automation.PSInvalidOperationException: The website
must have at least two slots to apply swap at
Microsoft.WindowsAzure.Commands.Websites.SwitchAzureWebsiteSlotCommand.ExecuteCmdlet()
at
Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePSCmdlet.ProcessRecord();
I use Debug mode to have more details but I don't understand what does it mean. I am a newbie in Azure and Powershell as well.
I made sure the right AzureSubscription is set as current one before to execute my cmdlet.
Anyone got the same issue as me before?
I have a doubt about the "-Name" value I used. I use site URL I found on the Azure portal. I don't know if it is correct.
To get the name of your websites in the subscription use the below PowerShell cmdlet:
Get-AzureWebsite
Note: The website should be something like this "constosoweb" and azure website looks like contosoweb.cloudapp.net.
For more details, you may refer "Swap Slots in Azure Web Site when there are 2 or more staging slots using Azure PowerShell".
I have a doubt about the "-Name" value I used. I use site URL I found
on the Azure portal. I don't know if it is correct.
-Name is the name of the website, we can use ARM powershell to get it:
Get-AzureRmWebApp -ResourceGroupName <resourcegroupname> -Name <webappname>
Like this:
Switch-AzureWebsiteSlot : The website must have at least two slots
According to this error message, we should add at least two slots to that website:
Then we can run Switch-AzureWebsiteSlot -Name jasonapp3 -Slot1 jasonapp32 -Slot2 jasonapp4, here is the result:
Hi Pradeep and Jason,
Thanks a lot for your help.
Thanks to your advices I figured out where was my issue. In fact we use Azure Cloud Service and not WebSite. That's why my cmdet failed.
I looked for cmdlet suit to Cloud Service and I found Move-AzureDeployment that works perfectly for me.
Thanks

Still requiring Login-RmAzureAccount even after importing PublishSettings in Azure

I am attempting to login to an Azure account through a PowerShell script by means of making use of a publishsettings file; However, I am still finding that it is requiring me to login to my account using Login-AzureRmAccount, regardless of having those credentials.
My step-by step looks something like this:
Clear out all accounts that may be available:
Get-AzureAccount | ForEach-Object { Remove-AzureAccount $_.ID -Force }
Download the PublishSettings file: Import-AzurePublishSettingsFile –PublishSettingsFile $PublishSettingsFileNameWithPath
Select the Azure subscription using the subscription ID:
Select-AzureRMSubscription -SubscriptionId $SubscriptionId
And finally, create a new resource group in the subscription before deploying it: New-AzureRmResourceGroup -Name $ResourceGroupName -Location $ResourceGroupLocation -Verbose -Force 2>> .\errorCIMS_RG.txt | Out-File .\rgDetailsCIMS_RG.txt
However, this is when an error is thrown: Run Login-AzureRmAccount to login.
Assuming I have the PublishSettings file, and it hasnt expired, why would this be giving back an error?
As Mihail said, we should check Azure PowerShell version first, and install the latest version.
We can run this command to list Azure PowerShell version:
Get-Module -ListAvailable -Name Azure -Refresh
By the way, Import-AzurePublishSettingsFile work for ASM, New-AzureRmResourceGroup is ARM command, so if you want to create resource group, you should Login-AzureRmAccount first.
Note:
The AzureResourceManager module does not support publish settings
files.
More information about Import-AzurePublishSettingsFile, please refer to this link.
I solved this problem by updating to last version of azure powershell cmdlet.
You can find last one here:
https://github.com/Azure/azure-powershell/releases

Azure swap not working

I am trying to use Switch-AzureWebsiteSlot as it follows:
Switch-AzureWebsiteSlot -Name 'sitename' -slot1 'Staging' -slot2 'Production' -f
orce -verbose
However even though my website has 2 slots, Staging and the default Production I still receive the following error from Power Shell.
Switch-AzureWebsiteSlot : The website must have at least two slots to apply swap
At line:1 char:1
+ Switch-AzureWebsiteSlot -Name 'sitename' -slot1 'St ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Switch-AzureWebsiteSlot], PSInvalidOperationException
+ FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Websites.SwitchAzureWebsiteSlotCommand
Do you have any ideas why? Did you also encounter this during your code journeys?
Switch-AzureWebsiteSlot is for ASM websites. In your case, I think you have created an ARM website, hence Switch-AzureWebsiteSlot is not suitable here.
To swap slot for ARM websites, you need to use below script:
$ParametersObject = #{targetSlot = "[slot name – e.g. “production”]"}
Invoke-AzureRmResourceAction -ResourceGroupName [resource group name]-ResourceType Microsoft.Web/sites/slots -ResourceName [web app name]/[slot name] -Action slotsswap -Parameters $ParametersObject -ApiVersion 2015-07-01
You can check this article for details.
Update:
Switch-AzureWebsiteSlot also works for ARM web app. My problem is that I have two subscriptions, I didn't select the correct subscription when testing the command previously. Thanks to Flemin!
Before:
Now with the right subscription:
This command works even if you have created app in ARM.
Switch-AzureWebsiteSlot -Name 'siteName' -slot1 'StagingDeploymentName' -slot2 'Production' -force -verbose
Please check the names that you have given and if the slots are up and running.
I tested this by stopping one of the deployment slots and go the same error as you got. So, I'm sure now that in your case either one slot is not in running state.
For an ARM web app, Switch-AzureWebsiteSlot does not work for me at all. Get the following error message:
Switch-AzureWebsiteSlot : No default subscription has been designated.
Use Select-AzureSubscription -Default to set the
default subscription.
From what I understand, Select-AzureSubscription is an ASM command so it's not applicable. (Instead, for ARM I need to use Select-AzureRmSubscription.)
The command Swap-AzureRmWebAppSlot is what worked for me:
Swap-AzureRmWebAppSlot -Name "sitename" -SourceSlotName "Staging" -DestinationSlotName "Production" -ResourceGroupName "<Your Resource Group Name"

Invoke Sync with Powershell

Normally, I integrate the deployment source to webapp, and then run the 'Sync' button found in the webapp dashboard as and when required to sync the Azure webapp with my onedrive folder.
But, if I want to give a non-Azure user, I mean , who need not be logged in to Azure portal itself, rather could invoke with a demo credential or sort, what should I do? Or, If I want to run it myself from shell, how to approach?
Would it be possible to run the sync from power-shell with service principal or similar ways ( runbooks, http trigger with azure functions for sync ) without actually giving the user a login credential itself?
Update:
1. I read this blog on Kudu but not sure whether it is what I am actually looking for. Please suggest. https://dzimchuk.net/post/azure-web-apps-continuous-deployment
Update 31/Aug:
My workflow got 3 slots dev/stage/mirror. I aim to integrate dev with source repo. So, Sync is enabled at lowest environment.
SiteName : YourWebApp(dev)
State : Running
DefaultHostName : YourWebApp-dev.azurewebsites.net
Id : /subscriptions/1234567890-{my}-{subscription}_{id}/resourceGroups/Default-Web/providers/Microsoft.Web/sites/YourWebApp/slots/dev
Name : YourWebApp/dev
Location : East US
Type : Microsoft.Web/sites/slots
If you install the latest Azure PowerShell, you can run this command to trigger a sync:
Invoke-AzureRmResourceAction -ResourceGroupName {YourResourceGroup} -ResourceType Microsoft.Web/sites -ResourceName YourWebApp -Action sync -ApiVersion 2015-08-01 -Force
Or if you're dealing with a slot, it will look like this:
Invoke-AzureRmResourceAction -ResourceGroupName {YourResourceGroup} -ResourceType Microsoft.Web/sites/slots -ResourceName YourWebApp/YourSlot -Action sync -ApiVersion 2015-08-01 -Force
As far as letting some other user authenticate, you have a couple options:
You can make them a Contributor on that Web App (using RBAC - Role Based Access Control)
You can set up a Service Principal