Create a consumption based App Service Plan with Powershell - azure

I found this answer for the question
Does anyone know how to create a Consumption app-service-plan with Azure?
When I look at the properties (using https://resources.azure.com/ ) of one I made (by the Gui), I see the following properties;
},
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
}
{
"id": "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/MyResourceGroup/providers/Microsoft.Web/serverfarms/MyHandMadeConsumptionAppServicePlan",
"name": "MyHandMadeConsumptionAppServicePlan",
"type": "Microsoft.Web/serverfarms",
"kind": "functionapp",
"location": "East US",
But if I try (the important part being "-Tier Dynamic")
$plan = New-AzureRmAppServicePlan -Name 'MyPowershellCreatedAppServicePlan' -ResourceGroupName 'MyResourceGroup' -Location 'PickALocation' -Tier Dynamic
I get the exception:
Exception - + Cannot validate argument on parameter 'Tier'. The
argument "Dynamic" does not belong to the set
"Free,Shared,Basic,Standard,Premium,PremiumV2" specified by the
ValidateSet attribute. Supply an argument that is in the set and then
try the command again.

Geeze Louise.
This has been racking me for 3 days. I finally found some help (urls I mention).
It looks like this cannot be accomplished (currently) with New-AzureRmAppServicePlan.
But you can fall back onto the more generic New-AzureRmResource.
The code I finally got to work:
function SafeCreateAppServicePlan(
[Parameter(Mandatory = $true)]
[System.String]$location,
[Parameter(Mandatory = $true)]
[System.String]$resourceGroupName,
[Parameter(Mandatory = $true)]
[String]$appServicePlanName
)
{
Write-Host "SafeCreateAppServicePlan.Parameter:location: $location"
Write-Host "SafeCreateAppServicePlan.Parameter:resourceGroupName: $resourceGroupName"
Write-Host "SafeCreateAppServicePlan.Parameter:appServicePlanName: $appServicePlanName"
$SkuName = "Y1"
$SkuTier = "Dynamic"
$WebAppApiVersion = "2015-08-01"
$fullObject = #{
location = $location
sku = #{
name = $SkuName
tier = $SkuTier
}
}
Write-Host "Ensuring the $appServicePlanName app service plan exists"
$plan = Get-AzureRmAppServicePlan -Name $appServicePlanName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if(-not $plan) {
Write-Host "Creating $appServicePlanName app service plan"
New-AzureRmResource -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/serverfarms -Name $appServicePlanName -IsFullObject -PropertyObject $fullObject -ApiVersion $WebAppApiVersion -Force
}
else {
Write-Host "$appServicePlanName app service plan already exists"
}
}
The help I got:
https://github.com/davidebbo/AzureWebsitesSamples/blob/master/PowerShell/HelperFunctions.ps1
(search the url above for "SkuName" to find the magic lines.
Please note, this is only part of the overall equation to deploy the INFRASTRUCTURE for azure functions (if you are not using arm templates). When I say the infrastructure, the code below does not deploy the azure-functions themselves, but the below will setup the infrastructure needed to do this.
This guy does a good job of explaining:
https://clouddeveloper.space/2017/10/26/deploy-azure-function-using-powershell/
"clouddeveloper" basically says that for consumption plan azure functions, you need to have a storage account. This lines up with the "info" button you get when you manually add a Function-App via the azure portal.
"A storage account that supports Blob, Queue, and Table Storage is
required. When using a Consumption plan function definitions are
stored in File Storage."
So my full code, that will create an App-Service-Plan, create a Storage Account, create an App-Service (that is azure functions/function app friendly) and match up the storage-account to the app-service is:
function SafeCreateAppServicePlan(
[Parameter(Mandatory = $true)]
[System.String]$location,
[Parameter(Mandatory = $true)]
[System.String]$resourceGroupName,
[Parameter(Mandatory = $true)]
[String]$appServicePlanName
)
{
Write-Host "SafeCreateAppServicePlan.Parameter:location: $location"
Write-Host "SafeCreateAppServicePlan.Parameter:resourceGroupName: $resourceGroupName"
Write-Host "SafeCreateAppServicePlan.Parameter:appServicePlanName: $appServicePlanName"
$SkuName = "Y1"
$SkuTier = "Dynamic"
$WebAppApiVersion = "2015-08-01"
$fullObject = #{
location = $location
sku = #{
name = $SkuName
tier = $SkuTier
}
}
Write-Host "Ensuring the $appServicePlanName app service plan exists"
$plan = Get-AzureRmAppServicePlan -Name $appServicePlanName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if(-not $plan) {
Write-Host "Creating $appServicePlanName app service plan"
New-AzureRmResource -ResourceGroupName $resourceGroupName -ResourceType Microsoft.Web/serverfarms -Name $appServicePlanName -IsFullObject -PropertyObject $fullObject -ApiVersion $WebAppApiVersion -Force
}
else {
Write-Host "$appServicePlanName app service plan already exists"
}
}
function SafeCreateAzureFunctionAppService(
[Parameter(Mandatory = $true)]
[System.String]$location,
[Parameter(Mandatory = $true)]
[System.String]$resourceGroupName,
[Parameter(Mandatory = $true)]
[String]$appServicePlanName,
[Parameter(Mandatory = $true)]
[String]$functionAppName
)
{
Write-Host "SafeCreateAzureFunctionAppService.Parameter:location: $location"
Write-Host "SafeCreateAzureFunctionAppService.Parameter:resourceGroupName: $resourceGroupName"
Write-Host "SafeCreateAzureFunctionAppService.Parameter:appServicePlanName: $appServicePlanName"
Write-Host "SafeCreateAzureFunctionAppService.Parameter:functionAppName: $functionAppName"
[String]$planId = ''
$plan = Get-AzureRmAppServicePlan -Name $appServicePlanName -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue
if(-not $plan) {
throw [System.ArgumentOutOfRangeException] "Missing App Service Plan. (ResourceGroupName='$resourceGroupName', AppServicePlan.Name = '$appServicePlanName')"
}
else {
Write-Host "START AzureRmAppServicePlan Properties"
$plan.PSObject.Properties
Write-Host "END AzureRmAppServicePlan Properties"
#get the planId, so that can be used as the backing-app-service-plan for this AppService
[String]$planId = $plan.Id
}
#wire up the necessary properties for this AppService
$props = #{
ServerFarmId = $planId
}
$functionAppResource = Get-AzureRmResource | Where-Object { $_.ResourceName -eq $functionAppName -And $_.ResourceType -eq 'Microsoft.Web/Sites' }
if ($functionAppResource -eq $null)
{
New-AzureRmResource -ResourceType 'Microsoft.Web/Sites' -ResourceName $functionAppName -kind 'functionapp' -Location $location -ResourceGroupName $resourceGroupName -Properties $props -force
}
}
function SafeCreateStorageAccountToBackConsumptionAzureFunctions(
[Parameter(Mandatory = $true)]
[System.String]$location,
[Parameter(Mandatory = $true)]
[System.String]$resourceGroupName,
[Parameter(Mandatory = $true)]
[String]$storageAccountName
)
{
Write-Host "SafeCreateStorageAccount.Parameter:location: $location"
Write-Host "SafeCreateStorageAccount.Parameter:resourceGroupName: $resourceGroupName"
Write-Host "SafeCreateStorageAccount.Parameter:storageAccountName: $storageAccountName"
$azureRmStorageAccountGetCheck = Get-AzureRmStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccountName -ErrorAction SilentlyContinue
if(-not $azureRmStorageAccountGetCheck)
{
New-AzureRmStorageAccount -ResourceGroupName $resourceGroupName -AccountName $storageAccountName -Location $location -SkuName 'Standard_LRS'
}
else
{
Write-Host "$storageAccountName storage account already exists"
}
}
function MatchStorageSettingsToAppService(
[Parameter(Mandatory = $true)]
[System.String]$location,
[Parameter(Mandatory = $true)]
[System.String]$resourceGroupName,
[Parameter(Mandatory = $true)]
[String]$functionAppName,
[Parameter(Mandatory = $true)]
[String]$storageAccountName
)
{
Write-Host "MatchStorageSettingsToAppService.Parameter:location: $location"
Write-Host "MatchStorageSettingsToAppService.Parameter:resourceGroupName: $resourceGroupName"
Write-Host "MatchStorageSettingsToAppService.Parameter:functionAppName: $functionAppName"
Write-Host "MatchStorageSettingsToAppService.Parameter:storageAccountName: $storageAccountName"
$keys = Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroupName -AccountName $storageAccountName
$accountKey = $keys | Where-Object { $_.KeyName -eq "Key1" } | Select Value
$storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=' + $storageAccountName + ';AccountKey=' + $accountKey.Value
$AppSettings = #{}
$AppSettings = #{'AzureWebJobsDashboard' = $storageAccountConnectionString;
'AzureWebJobsStorage' = $storageAccountConnectionString;
'FUNCTIONS_EXTENSION_VERSION' = '~1';
'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' = $storageAccountConnectionString;
'WEBSITE_CONTENTSHARE' = $storageAccountName;
}
Set-AzureRMWebApp -Name $functionAppName -ResourceGroupName $resourceGroupName -AppSettings $AppSettings
}
I got a few hints from this ARM template as well:
https://github.com/Azure/azure-quickstart-templates/blob/master/101-function-app-create-dynamic/azuredeploy.json

This is not really an answer to your questions, but just some research...
You will notice that in older Microsoft.Web schemas, there was no support for "Dynamic". Instead, we see a list similar to what you see in the error message.
https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2015-08-01/Microsoft.Web.json#L37
In the newer schema (from 2016-09-01), which is what I'm seeing when I view my Comsumption App Service Plan in resources.azure.com, you'll find "Dynamic" as a valid value under computeMode: https://github.com/Azure/azure-resource-manager-schemas/blob/master/schemas/2016-09-01/Microsoft.Web.json#L189
I'm not sure how you can set the computeMode value in PowerShell, since the documentation doesn't show that this is exposed:
https://learn.microsoft.com/en-us/powershell/module/azurerm.websites/new-azurermappserviceplan?view=azurermps-5.0.0

Related

Setup and deploy Azure function using PowerShell

I try to setup and deploy Azure Function by using PowerShell script based on this topic: Setup Azure Function from PowerShell
My script looks like this:
#=============Defining All Variables=========
$location = 'Central US'
$resourceGroupName = 'MyResourceGroup'
$subscriptionId = 'MysubscriptionId'
$functionAppName = 'MyfunctionAppName'
$appServicePlanName = 'ASP-test-8b50'
$tier = 'Dynamic'
$archivePath = 'd:\TestAzureFunc.zip'
Connect-AzAccount
#========Creating Azure Resource Group========
$resourceGroup = Get-AzResourceGroup | Where-Object { $_.ResourceGroupName -eq $resourceGroupName }
if ($resourceGroup -eq $null)
{
New-AzResourceGroup -Name $resourceGroupName -Location $location -force
}
#selecting default azure subscription by name
Select-AzSubscription -SubscriptionID $subscriptionId
Set-AzContext $subscriptionId
#========Creating App Service Plan============
New-AzAppServicePlan -ResourceGroupName $resourceGroupName -Name $appServicePlanName -Location $location -Tier $tier
$functionAppSettings = #{
ServerFarmId="/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Web/serverfarms/$appServicePlanName";
alwaysOn=$True;
}
#========Creating Azure Function========
$functionAppResource = Get-AzResource | Where-Object { $_.ResourceName -eq $functionAppName -And $_.ResourceType -eq "Microsoft.Web/Sites" }
if ($functionAppResource -eq $null)
{
New-AzResource -ResourceType 'Microsoft.Web/Sites' -ResourceName $functionAppName -kind 'functionapp' -Location $location -ResourceGroupName $resourceGroupName -Properties $functionAppSettings -force
}
#========Defining Azure Function Settings========
$AppSettings =#{}
$AppSettings =#{'FUNCTIONS_EXTENSION_VERSION' = '~2';
'FUNCTIONS_WORKER_RUNTIME' = 'dotnet';}
Set-AzWebApp -Name $functionAppName -ResourceGroupName $resourceGroupName -AppSettings $AppSettings
#========Deploy Azure Function from zip========
Publish-AzWebapp -ResourceGroupName $resourceGroupName -Name $functionAppName -ArchivePath $archivePath
The script works without errors. Resource group and Function App created as needed. But the list of functions of the Function App is empty.
Function details here:
My intuition tells me that I've forgotten something. But I don't know what.
Could you advise me on how to deploy my Azure function properly?
One of the workaround you can follow ,
Looking at your script we need to ensure that we are providing function app configuration as below cmdlts the link you followed:-
$AzFunctionAppSettings = #{
APPINSIGHTS_INSTRUMENTATIONKEY = $AppInsightsKey;
AzureWebJobsDashboard = $AzFunctionAppStorageAccountConnectionString;
AzureWebJobsStorage = $AzFunctionAppStorageAccountConnectionString;
FUNCTIONS_EXTENSION_VERSION = "~4";
FUNCTIONS_WORKER_RUNTIME = "dotnet";
}
And also make sure that the storage account connection string you provided in the function is same as here providing.
And then you can navigate to Kudu API to check the wwwroot folder is exist or not.
For more information please refer the below links:-
SO THREAD|Powershell command Publish-AzWebApp not publishing apllication
BLOG|How to Deploy Azure Function Apps With Powershell.

Do we need to dispose azure powershell commands?

We have over 400 app services and we are creating a deployment tool to deploy to all of these instances as soon as possible.
We have 4 projects running in separate app service and each customer need to have all 4 projects up and running so we have distributed the instances by customer name and each instance deploy to 4 app services internally (See the code snippet below)
We've created a powershell function app with queue trigger that is calling azure powershell commands to do the deployment. The deployment steps are:
Create deployment slot
Publish to the deployment slot
Version check (Have an endpoint in all projects which returns assembly version)
Swap slot
Version check again
Delete slot
The steps are straight forward but when I deploy to single instance it runs pretty quickly but when I am trying to deploy to multiple instances (5+) then it starts becoming really slow and eventually stops execution. My assumption is that there is a memory issue. I am using premium (EP1) plan for my function so it shouldn't be that slow.
I am totally new to powershell so the question is do I need to dispose the azure powershell stuff? Or anything else to freed the memory. If yes, how can I call dispose to azure powershell commands?
Update
Adding the code snippets.
Some more context:
So the run.ps1 file has the code that downloads the ps1 script file from blob storage and dynamically executes it:
run.ps1
# Input bindings are passed in via param block.
param($QueueItem, $TriggerMetadata)
# Write out the queue message and insertion time to the information log.
Write-Host "PowerShell queue trigger function processed work item: $QueueItem"
Write-Host "Queue item insertion time: $($TriggerMetadata.InsertionTime)"
$currentContext = Get-AzContext -ListAvailable | Where-Object {$_.Name -contains 'Subscriptionname'}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "<ResourceGroup>" -Name "<ResourceName>" -DefaultProfile $currentContext
$Context = $storageAccount.Context
$queue = Get-AzStorageQueue -Name logs -Context $Context
function Log {
param (
[string]$message, [string]$isDetailed, [string]$hasError = "false"
)
$jsonMessge = #"
{
"InstanceId": "$instanceId",
"TaskId": "$taskId",
"Note": "$message",
"IsDetailed": $isDetailed,
"HasError": $hasError
}
"#
# Create a new message using a constructor of the CloudQueueMessage class
$queueMessage = [Microsoft.Azure.Storage.Queue.CloudQueueMessage]::new($jsonMessge)
# # Add a new message to the queue
$queue.CloudQueue.AddMessageAsync($queueMessage)
}
try {
#Extracting data from Queue message
$queueMessage = $QueueItem
$instanceId = $queueMessage.instanceId
$taskId = $queueMessage.taskId
$siteName = $queueMessage.siteName
$buildNo = $queueMessage.buildNo
$pass = $queueMessage.password
$dbPassword = convertto-securestring "$pass" -asplaintext -force
$servicePlanName = $queueMessage.servicePlanName
$subscription = $queueMessage.subscription
$key = $queueMessage.key
$rg = $queueMessage.resourceGroup
$sqlServerName = $queueMessage.sqlServerName
Log -message "Deployment started for $($siteName)" -isDetailed "false"
$tempFolder = $env:temp
# $artifactFolderPath = "$($tempFolder)\$($siteName)\$($buildNo)"
#$artifactFilePath = "$($tempFolder)\$($siteName)\$($buildNo).zip"
$tempDownloadPath = "$($tempFolder)\$($siteName)"
$scriptFileName = "DeployScripts.ps1"
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "KineticNorthEurope" -Name "KineticDeployment" -DefaultProfile $currentContext
New-Item -Path $tempFolder -Name $siteName -ItemType "directory"
$Context = $storageAccount.Context
$blobContent = #{
Blob = "DeployScripts.ps1"
Container = 'builds'
Destination = "$($tempDownloadPath)\$($scriptFileName)"
Context = $Context
}
Get-AzStorageBlobContent #blobContent -DefaultProfile $currentContext
#[System.IO.Compression.ZipFile]::ExtractToDirectory($artifactFilePath, $artifactFolderPath)
$arguments = "-rg $rg -site $siteName -buildNo $buildNo -dbPassword `$dbPassword -instanceId $instanceId -taskId $taskId -sqlServerName $sqlServerName -subscription $subscription"
$path = "$($tempDownloadPath)\$($scriptFileName)"
Unblock-File -Path $path
"$path $ScriptFilePath $arguments" | Invoke-Expression
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
Log -message "Resources cleaned up" -isDetailed "false"
}
catch {
Log -message $_.Exception.message -isDetailed "false" -hasError "true"
if (Test-Path $tempDownloadPath) {
Remove-Item $tempDownloadPath -Force -Recurse
}
}
And here is the actual DeployScripts.ps1 file:
param($rg, $site, $buildNo, [SecureString] $dbPassword, $instanceId, $taskId, $sqlServerName, $subscription)
$siteNameWeb = "${site}"
$siteNamePortal = "${site}Portal"
$siteNamePortalService = "${site}PortalService"
$siteNameSyncService = "${site}SyncService"
$kineticNorthContext = Get-AzContext -ListAvailable | Where-Object {$_.Name -contains 'SubscriptionName'}
$storageAccount = Get-AzStorageAccount -ResourceGroupName "<ResourceGroup>" -Name "<ResourceName>" -DefaultProfile $kineticNorthContext
$Context = $storageAccount.Context
$queue = Get-AzStorageQueue -Name logs -Context $Context
Set-AzContext -SubscriptionName $subscription
Function CreateDeploymentSlots() {
Log -message "Creating deployment slots" -isDetailed "false"
Log -message "Creating deployment slot for web" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNameWeb -slot develop
Log -message "Creating deployment slot for portal" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNamePortal -slot develop
Log -message "Creating deployment slot for portal service" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNamePortalService -slot develop
Log -message "Creating deployment slot for sync service" -isDetailed "true"
New-AzWebAppSlot -ResourceGroupName $rg -name $siteNameSyncService -slot develop
Log -message "Deployment slots created" -isDetailed "false"
}
Function DeleteDeploymentSlots() {
Log -message "Deleting deployment slots" -isDetailed "false"
Log -message "Deleting slot web" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNameWeb -Slot "develop"
Log -message "Deleting slot portal" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNamePortal -Slot "develop"
Log -message "Deleting slot portal service" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNamePortalService -Slot "develop"
Log -message "Deleting slot sync service" -isDetailed "true"
Remove-AzWebAppSlot -ResourceGroupName $rg -Name $siteNameSyncService -Slot "develop"
Log -message "Slots deployment deleted" -isDetailed "false"
}
Function SwapDeploymentSlots {
Log -message "Switching deployment slots" -isDetailed "false"
Log -message "Switch slot web" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNameWeb
Log -message "Switch slot portal" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNamePortal
Log -message "Switch slot portal service" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNamePortalService
Log -message "Switch slot sync service" -isDetailed "true"
Switch-AzWebAppSlot -SourceSlotName "develop" -DestinationSlotName "production" -ResourceGroupName $rg -Name $siteNameSyncService
Log -message "Deployment slots switched" -isDetailed "false"
}
function Log {
param (
[string]$message, [string]$isDetailed, [string]$isDeployed = "false", [string]$hasError = "false"
)
$jsonMessge = #"
{
"InstanceId": "$instanceId",
"TaskId": "$taskId",
"Note": "$message",
"IsDetailed": $isDetailed,
"IsDeployed": $isDeployed,
"HasError": $hasError
}
"#
# Create a new message using a constructor of the CloudQueueMessage class
$queueMessage = [Microsoft.Azure.Storage.Queue.CloudQueueMessage]::new($jsonMessge)
# # Add a new message to the queue
$queue.CloudQueue.AddMessageAsync($queueMessage)
}
function VersionCheckWeb() {
$tls = Invoke-WebRequest -URI "https://${site}.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortal() {
$tls = Invoke-WebRequest -URI "https://${site}portal.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalService() {
$tls = Invoke-WebRequest -URI "https://${site}portalservice.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSyncService() {
$tls = Invoke-WebRequest -URI "https://${site}syncservice.net/SyncService.svc/Info" -UseBasicParsing
$tls = $tls -replace '[?]', ""
$content = "$tls" | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheck() {
$versionCheckWeb = VersionCheckWeb
$versionCheckPortal = VersionCheckPortal
$versionCheckPortalService = VersionCheckPortalService
$versionCheckSyncService = VersionCheckSyncService
if (($versionCheckWeb -eq "True") -and ($versionCheckPortal -eq "True") -and ($versionCheckPortalService -eq "True") -and ($versionCheckSyncService -eq "True")) {
Log -message "Version correct" -isDetailed "false"
}
else {
Log -message "Version check failed, exception not thrown" -isDetailed "false"
}
}
function VersionCheckWebSlot() {
$tls = Invoke-WebRequest -URI "https://${site}-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalSlot() {
$tls = Invoke-WebRequest -URI "https://${site}portal-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckPortalServiceSlot() {
$tls = Invoke-WebRequest -URI "https://${site}portalservice-develop.azurewebsites.net/Home/Info" -UseBasicParsing
$content = $tls.Content | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSyncServiceSlot() {
$tls = Invoke-WebRequest -URI "https://${site}syncservice-develop.azurewebsites.net/SyncService.svc/Info" -UseBasicParsing
$tls = $tls -replace '[?]', ""
$content = "$tls" | ConvertFrom-Json
$versionCheck = $content.VersionNo -eq $buildNo
return $versionCheck
}
function VersionCheckSlot() {
$versionCheckWeb = VersionCheckWebSlot
$versionCheckPortal = VersionCheckPortalSlot
$versionCheckPortalService = VersionCheckPortalServiceSlot
$versionCheckSyncService = VersionCheckSyncServiceSlot
if (($versionCheckWeb -eq "True") -and ($versionCheckPortal -eq "True") -and ($versionCheckPortalService -eq "True") -and ($versionCheckSyncService -eq "True")) {
Log -message "Slot version correct" -isDetailed "false"
}
else {
Log -message "Slot version check failed, exception not thrown" -isDetailed "false"
}
}
function PublishToAzure() {
$webPublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNameWeb
$webXml = $webPublishProfile -as [Xml]
$webUserName = $webXml.publishData.publishProfile[0].userName
$webUserPwd = $webXml.publishData.publishProfile[0].userPWD
$webpair = "$($webUserName):$($webUserPwd)"
$webencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($webpair))
$webauthHeader = "Basic $webencodedCreds"
$webHeaders = #{
Authorization = $webauthHeader
}
$portalPublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNamePortal
$portalXml = $portalPublishProfile -as [Xml]
$portalUserName = $portalXml.publishData.publishProfile[0].userName
$portalUserPwd = $portalXml.publishData.publishProfile[0].userPWD
$portalpair = "$($portalUserName):$($portalUserPwd)"
$portalencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($portalpair))
$portalauthHeader = "Basic $portalencodedCreds"
$portalHeaders = #{
Authorization = $portalauthHeader
}
$portalServicePublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNamePortalService
$portalServiceXml = $portalServicePublishProfile -as [Xml]
$portalServiceUserName = $portalServiceXml.publishData.publishProfile[0].userName
$portalServiceUserPwd = $portalServiceXml.publishData.publishProfile[0].userPWD
$portalServicepair = "$($portalServiceUserName):$($portalServiceUserPwd)"
$portalServiceencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($portalServicepair))
$portalServiceauthHeader = "Basic $portalServiceencodedCreds"
$portalServiceHeaders = #{
Authorization = $portalServiceauthHeader
}
$syncServicePublishProfile = Get-AzWebAppPublishingProfile -ResourceGroupName $rg -Name $siteNameSyncService
$syncServiceXml = $syncServicePublishProfile -as [Xml]
$syncServiceUserName = $syncServiceXml.publishData.publishProfile[0].userName
$syncServiceUserPwd = $syncServiceXml.publishData.publishProfile[0].userPWD
$syncServicepair = "$($syncServiceUserName):$($syncServiceUserPwd)"
$syncServiceencodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($syncServicepair))
$syncServiceauthHeader = "Basic $syncServiceencodedCreds"
$syncServiceHeaders = #{
Authorization = $syncServiceauthHeader
}
$bodyWeb = '{"packageUri": "<blobUrl>"}'
$bodyPortal = '{"packageUri": "blobUrl"}'
$bodyPortalService = '{"packageUri": "blobUrl"}'
$bodySyncService = '{"packageUri": "blobUrl"}'
$web = Invoke-RestMethod -URI "https://${siteNameWeb}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyWeb -Headers $webHeaders -ContentType "application/json"
Log -message "Published to Web" -isDetailed "false"
$portal = Invoke-RestMethod -URI "https://${siteNamePortal}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyPortal -Headers $portalHeaders -ContentType "application/json"
Log -message "Published to Portal" -isDetailed "false"
$portalService = Invoke-RestMethod -URI "https://${siteNamePortalService}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodyPortalService -Headers $portalServiceHeaders -ContentType "application/json"
Log -message "Published to PortalService" -isDetailed "false"
$syncService = Invoke-RestMethod -URI "https://${siteNameSyncService}.scm.azurewebsites.net/api/publish?type=zip" -Method POST -Body $bodySyncService -Headers $syncServiceHeaders -ContentType "application/json"
Log -message "Published to SyncService" -isDetailed "false"
}
try {
CreateDeploymentSlots
PublishToAzure
VersionCheckSlot
SwapDeploymentSlots
VersionCheck
DeleteDeploymentSlots
Log -message "Instance deployed successfully" -isDetailed "false" -isDeployed "true"
}
catch {
Log -message $_.Exception.message -isDetailed "false" -hasError "true"
}
I know the code is little mess right now and that's because I've changed the implementation to faster the process but no major luck.
Question2
I actually have another question as well. We've multiple subscriptions and appservices are distributed accordingly. So when function app tries to deploy to a instance exists in another subscription, it throws error. I'm setting AzContext before starting the processing and it seems to be working fine. But i also have to put message into a queue after each step and the queue exists in a storage account that belongs to same subscription as of the function app. Currently i'm getting the AzContent and passing it as -DefaultProfile while getting the storage account. Is there a better way to handle this?
Also I am writing powershell for the first time so any suggestion would be appreciated. Thanks.

Powershell script to automate azure linux VM backup and restore from azure devops pipeline

I tried multiple powershell script to do azure VM backup and restore but none of them are seems working or not so effective. Could any one please share the powershell script to create backup of VM and restore in azure via azure devops pipeline.
PowerShell Script:
<#
.SYNOPSIS
Written By John Lewis
email: jonos#live.com
Ver 1.1
v 1.2 updates - minor fixes
v 1.1 updates - Added Pre-Checks
v 1.0 updates - RTM
Deploys Azure Backup Vault and configures Azure VMs to leverage vault. Provides automated restore to new VM.
.PARAMETER Action
.PARAMETER backupvmname
.PARAMETER backupvmrg
.PARAMETER rg
.PARAMETER policyname
.PARAMETER containertype
.PARAMETER Location
.PARAMETER wrkloadtype
.PARAMETER vaultname
.PARAMETER createvmname
.PARAMETER createvmrg
.PARAMETER vaultrg
.PARAMETER vnet
.PARAMETER vnetrg
.PARAMETER createvmsubnet
.EXAMPLE
.\AZRM-VMBackup.ps1 -csvimport -csvfile C:\temp\backupservers.csv
.EXAMPLE
.\AZRM-VMBackup.ps1 -action createpolicy -vaultname myvault -vaultrg myres -policyname mypolicy
.EXAMPLE
.\AZRM-VMBackup.ps1 -action createvault -vaultname myvault -vaultrg myres
.EXAMPLE
.\AZRM-VMBackup.ps1 -action addvmcreatevault -backupvmname myvm -backupvmrg myres -vaultname myvault -vaultrg myres
.EXAMPLE
.\AZRM-VMBackup.ps1 -action restorevm -createvmname myvm -createvmrg myres -vaultrg backuprg -vaultname myvaultname -vnet vnet -vnetrg myvnetrg
#>
[CmdletBinding(DefaultParameterSetName = 'default')]
Param(
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[ValidateSet("createpolicy","createvault","addvmcreatevault","addvmtovault","restorevm","executebackup","getstatus")]
[string]
$Action = 'createvault',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$vaultrg = "vault",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$storeagerg = $createvmrg,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[string]
$location = "East US",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$vaultname = "vault",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$backupvmname = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$backupvmrg = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[string]
$backupvmlocation = $location,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$createvmname = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$createvmrg = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[string]
$createvmlocation = $location,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true,Position=4)]
[ValidateNotNullorEmpty()]
[Alias("createvmvnet")]
[string]
$VNetName = 'vnet',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[string]
$vnetrg = $createvmrg,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$policyname = 'policy',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$containertype = 'AzureVM',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$wrkloadtype = 'AzureVM',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$provider = "Microsoft.RecoveryServices",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$Profile = "profile",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$csvfile = -join $workfolder + "\azrm-vmbackup.csv",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[Alias("csv")]
[switch]
$csvimport,
[Parameter(Mandatory=$False)]
[string]
$GenerateName = -join ((65..90) + (97..122) | Get-Random -Count 6 | % {[char]$_}) + "rmp",
[Parameter(Mandatory=$False)]
[string]
$StorageName = $createvmname + 'str',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateSet("Standard_LRS","Standard_GRS")]
[string]
$StorageType = 'Standard_GRS',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateNotNullorEmpty()]
[Alias("int1")]
[string]
$InterfaceName1 = $createvmname + '_nic1',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[Alias("int2")]
[string]
$InterfaceName2 = $createvmname + "_nic2",
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$SubscriptionID = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$TenantID = '',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateSet("InProgress","Completed")]
[string]
$status = 'InProgress',
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[ValidateRange(0,8)]
[ValidateNotNullorEmpty()]
[Alias("createvmsubnet")]
[Int]
$Subnet1 = 4
)
$workfolder = Split-Path $script:MyInvocation.MyCommand.Path
$ProfileFile = $workfolder+'\'+$profile+'.json'
$restorejson = $workfolder+'\'+ 'config.json'
Function validate-profile {
$comparedate = (Get-Date).AddDays(-14)
$fileexist = Test-Path $ProfileFile -NewerThan $comparedate
if($fileexist)
{
$az = Import-AzureRmContext -Path $ProfileFile
$subid = $az.Context.Subscription.Id
Set-AzureRmContext -SubscriptionId $subid | Out-Null
Write-Host "Using $ProfileFile"
}
else
{
Write-Host "Please enter your credentials"
Add-AzureRmAccount
Save-AzureRmContext -Path $ProfileFile -Force
Write-Host "Saved Profile to $ProfileFile"
exit
}
}
Function csv-run {
param(
[string] $csvin = $csvfile
)
$GetPath = test-path -Path $csvin
if(!$csvin)
{exit}
else {
Write-Host $GetPath "File Exists"
import-csv -Path $csvin -Delimiter ',' -ErrorAction SilentlyContinue -InformationAction SilentlyContinue | ForEach-Object{.\AZRM-VMBackup.ps1 -VMName $_.VMName -rg $_.rg -Action $_.Action -vmrg $_.vmrg -servaultname $_.servaultname }
}
}
Function Check-StorageName
{
param(
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]$StorageName = $StorageName
)
$checkname = Get-AzureRmStorageAccountNameAvailability -Name $StorageName | Select-Object -ExpandProperty NameAvailable
if($checkname -ne 'False') {
Write-Host "Storage Account Found..."
$script:StorageNameVerified = $StorageName.ToLower()
}
else
{
$script:StorageNameVerified = $StorageName.ToLower()
Create-Storage
}
}
#region Create Storage
Function Create-Storage {
param(
[string]$StorageName = $script:StorageNameVerified,
[string]$StorageType = $StorageType,
[string]$containerName = 'vhds',
[string]$Location = $Location,
[string]$storeagerg = $storeagerg
)
Write-Host "Starting Storage Creation..."
$script:StorageAccount = New-AzureRmStorageAccount -ResourceGroupName $storeagerg -Name $StorageName.ToLower() -Type $StorageType -Location $Location -ErrorAction Stop -WarningAction SilentlyContinue
Write-Host "Completed Storage Creation" -ForegroundColor White
}
Function Check-Vnet {
$vnetexists = Get-AzureRmVirtualNetwork -Name $VNetName -ResourceGroupName $vnetrg -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
if(!$vnetexists)
{
Write-Host "$VNetName does not exists!"
break
}
else
{ $existvnet = Get-AzureRmVirtualNetwork -Name $VNetName -ResourceGroupName $vnetrg
$addspace = $existvnet.AddressSpace | Select-Object -ExpandProperty AddressPrefixes
$namespace = $existvnet.Name
$existvnet = Get-AzureRmVirtualNetwork -Name $VNetName -ResourceGroupName $vnetrg
$addsubnet = Get-AzureRmVirtualNetworkSubnetConfig -VirtualNetwork $existvnet
$sub = $addsubnet.AddressPrefix
$subname = $addsubnet.Name
$nsg = $addsubnet.NetworkSecurityGroup
$subnet = Get-AzureRmVirtualNetworkSubnetConfig -VirtualNetwork $existvnet | ft Name,AddressPrefix -AutoSize -Wrap -HideTableHeaders
Write-Host " "
Write-Host "VNET CONFIGURATION - Existing VNET" -ForegroundColor Cyan
Write-Host " "
Write-Host "Active VNET: $VnetName in resource group $vnetrg"
Write-Host "Address Space: $addspace "
Write-Host "Subnet Ranges: $sub "
Write-Host "Subnet Names: $subname "
}
}
Function Check-VaultExists {
$vaultexists = Get-AzureRmRecoveryServicesVault -Name $vaultname -ResourceGroupName $vaultrg -ErrorAction Stop -WarningAction SilentlyContinue -InformationAction SilentlyContinue
if(!$vaultexists)
{
Write-Host "Specified vault $vaultname does not exist!" -ForegroundColor Red
break
}
}
function Check-VaultNullValues {
if(!$vaultrg) {
Write-Host "Please select -vaultrg" -ForegroundColor Red
exit
}
elseif(!$vaultname) {
Write-Host "Please Enter -vaultname" -ForegroundColor Red
exit
}
elseif(!$Location) {
Write-Host "Please Enter -Location" -ForegroundColor Red
exit
}
}
function Check-BackupVMNullValues {
if(!$backupvmrg) {
Write-Host "Please select -backupvmrg" -ForegroundColor Red
exit
}
elseif(!$backupvmname) {
Write-Host "Please Enter -backupvmname" -ForegroundColor Red
exit
}
elseif(!$Location) {
Write-Host "Please Enter -Location" -ForegroundColor Red
exit
}
}
function Check-CreateVMNullValues {
if(!$createvmrg) {
Write-Host "Please select -createvmrg" -ForegroundColor Red
exit
}
elseif(!$createvmname) {
Write-Host "Please Enter -createvmname" -ForegroundColor Red
exit
}
if(!$backupvmrg) {
Write-Host "Please select -backupvmrg" -ForegroundColor Red
exit
}
elseif(!$backupvmname) {
Write-Host "Please Enter -backupvmname" -ForegroundColor Red
exit
}
elseif(!$Location) {
Write-Host "Please Enter -Location" -ForegroundColor Red
exit
}
}
function Check-StorageNullValues {
if(!$storeagerg) {
Write-Host "Please select -storage" -ForegroundColor Red
exit
}
elseif(!$StorageName) {
Write-Host "Please Enter -createvmname" -ForegroundColor Red
exit
}
elseif(!$Location) {
Write-Host "Please Enter -Location" -ForegroundColor Red
exit
}
}
function Check-VNETNullValues {
if(!$vnetrg) {
Write-Host "Please select -vnetrg" -ForegroundColor Red
exit
}
elseif(!$VNetName) {
Write-Host "Please Enter -vnetname" -ForegroundColor Red
exit
}
elseif(!$Location) {
Write-Host "Please Enter -Location" -ForegroundColor Red
exit
}
}
function Reg-Provider {
param($provider = $provider)
Register-AzureRmResourceProvider -ProviderNamespace $provider
}
Function Provision-RG
{
Param(
[string]$rg = $vaultrg
)
New-AzureRmResourceGroup -Name $rg -Location $Location –Confirm:$false -WarningAction SilentlyContinue -Force | Out-Null
}
Function Check-VMExists {
param(
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$Location = $Location,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$rg = $backupvmrg,
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$VMName = $backupvmname
)
$extvm = Get-AzureRmVm -Name $VMName -ResourceGroupName $rg -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
if(!$extvm)
{
Write-Host "$VMName does not exist, please verify the VM exists" -ForegroundColor Yellow
Break
}
else {Write-Host "Restoration VM found" -ForegroundColor Green}
} #
#endregion
Function Configure-Backup {
param(
[Parameter(Mandatory=$False,ValueFromPipelinebyPropertyName=$true)]
[string]
$action = $action
)
switch ($action)
{
"createvault" {
Check-VaultNullValues
Write-Host "Creating new Backup Vault $vaultname"
Write-Config
Provision-RG
Create-Vault
Get-CurrentPolicies
Create-Policy
Write-Completion
}
"createpolicy" {
Write-Host "Creating new Policy"
Write-Config
Check-VaultExists
Get-CurrentPolicies
Create-Policy
Write-Completion
}
"addvmtovault" {
Check-VMExists
Check-VaultExists
Write-Host "Adding VM $backupvmname to $vaultname"
Write-Config
Get-CurrentPolicies
AddVM-Vault
Write-Completion
}
"executebackup" {
Write-Host "Executing backup of $backupvmname to $vaultname"
Check-VMExists
Write-Config
Check-BackupVMNullValues
Get-CurrentPolicies
TriggerBackup-Vault
Write-Completion
}
"addvmcreatevault" {
Check-VaultNullValues
Write-Host "Creating new Backup Vault $vaultname"
Write-Config
Provision-RG
Create-Vault
Create-Policy
Check-BackupVMNullValues
Check-VaultExists
Check-VMExists
Write-Host "Adding VM $backupvmname to $vaultname"
Get-CurrentPolicies
AddVM-Vault
Write-Completion
}
"restorevm" {
Check-CreateVMNullValues
Check-VNETNullValues
Check-Vnet
Check-StorageNullValues
Check-VMExists
Check-StorageName
Write-Host "Restoring VM Backup from $backupvmname to $createvmname"
Write-Config
Restore-VMVHD
Create-VM
Write-Completion
}
"getstatus" {
Write-Host "Obtaining current job information"
Get-JobProgress
}
default{"An unsupported backup command was used"}
}
exit
}
Function Get-JobProgress {
param(
$status = $status
)
Get-AzureRmRecoveryservicesBackupJob –Status $status
}
function Create-Vault {
New-AzureRmResourceGroup -Name $vaultrg -Location $Location –Confirm:$false -WarningAction SilentlyContinue -Force | Out-Null
New-AzureRmRecoveryServicesVault -Name $vaultname -ResourceGroupName $vaultrg -Location $location
$vault1 = Get-AzureRmRecoveryServicesVault –Name $vaultname
Set-AzureRmRecoveryServicesBackupProperties -Vault $vault1 -BackupStorageRedundancy GeoRedundant
}
function Get-Context {
param($vaultname = $vaultname)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
}
function Get-CurrentPolicies {
param(
$vaultname = $vaultname,
$wrkloadtype = $wrkloadtype
)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$schPol = Get-AzureRmRecoveryServicesBackupSchedulePolicyObject -WorkloadType $wrkloadtype
$retPol = Get-AzureRmRecoveryServicesBackupRetentionPolicyObject -WorkloadType $wrkloadtype
}
function Create-Policy {
param(
$vaultname = $vaultname,
$policyname = $policyname,
$wrkloadtype = $wrkloadtype
)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$schPol = Get-AzureRmRecoveryServicesBackupSchedulePolicyObject -WorkloadType $wrkloadtype
$retPol = Get-AzureRmRecoveryServicesBackupRetentionPolicyObject -WorkloadType $wrkloadtype
New-AzureRmRecoveryServicesBackupProtectionPolicy -Name $policyname -WorkloadType $wrkloadtype -RetentionPolicy $retPol -SchedulePolicy $schPol -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -InformationAction SilentlyContinue
$script:pol = Get-AzureRmRecoveryServicesBackupProtectionPolicy -Name $policyname
}
function Modify-Policy {
param(
$vaultname = $vaultname,
$policyname = $policyname,
$wrkloadtype = $wrkloadtype
)
$retPol = Get-AzureRmRecoveryServicesBackupRetentionPolicyObject -WorkloadType "AzureVM"
$retPol.DailySchedule.DurationCountInDays = 365
$pol= Get-AzureRmRecoveryServicesBackupProtectionPolicy -Name $policyname
Set-AzureRmRecoveryServicesBackupProtectionPolicy -Policy $pol -RetentionPolicy $RetPol
}
function TriggerBackup-Vault {
param(
$vaultname = $vaultname,
$backupvmname = $backupvmname,
$containertype = "AzureVM"
)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$namedContainer = Get-AzureRmRecoveryServicesBackupContainer -ContainerType $containertype -Status "Registered" -FriendlyName $backupvmname
$item = Get-AzureRmRecoveryServicesBackupItem -Container $namedContainer -WorkloadType "AzureVM"
$job = Backup-AzureRmRecoveryServicesBackupItem -Item $item
}
function AddVM-Vault {
param(
$vaultname = $vaultname,
$backupvmname = $backupvmname,
$containertype = "AzureVM",
$vaultrg = $backupvmrg,
$policyname = $policyname
)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$script:pol = Get-AzureRmRecoveryServicesBackupProtectionPolicy -Name $policyname
Enable-AzureRmRecoveryServicesBackupProtection -Policy $script:pol -Name $backupvmname -ResourceGroupName $vaultrg
$namedContainer = Get-AzureRmRecoveryServicesBackupContainer -ContainerType $containertype -Status "Registered" -FriendlyName $backupvmname
$item = Get-AzureRmRecoveryServicesBackupItem -Container $namedContainer -WorkloadType "AzureVM"
$job = Backup-AzureRmRecoveryServicesBackupItem -Item $item
$job
}
Function Get-RestorePoint {
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$startDate = (Get-Date).AddDays(-7)
$endDate = Get-Date
$rp = Get-AzureRmRecoveryServicesBackupRecoveryPoint -Item $backupitem -StartDate $startdate.ToUniversalTime() -EndDate $enddate.ToUniversalTime()
$rp[0]
}
Function Write-Config {
param(
)
Write-Host " "
$time = " Start Time " + (Get-Date -UFormat "%d-%m-%Y %H:%M:%S")
Write-Host BACKUP/RESTORE CONFIGURATION - $time -ForegroundColor Cyan
Write-Host " "
Write-Host "Operation: $Action " -ForegroundColor White
Write-Host " "
}
Function Write-Completion {
param(
)
Write-Host " "
$time = " End Time " + (Get-Date -UFormat "%d-%m-%Y %H:%M:%S")
Write-Host BACKUP/RESTORE CONFIGURATION - $time -ForegroundColor Cyan
Write-Host " "
Write-Host "Completed operation: $Action " -ForegroundColor White
Write-Host " "
}
function Restore-VMVHD {
param(
$vaultname = $vaultname,
$storeagerg = $storeagerg,
$StorageName = $script:StorageNameVerified,
$backupvmname = $backupvmname
)
Get-AzureRmRecoveryServicesVault -Name $vaultname | Set-AzureRmRecoveryServicesVaultContext
$namedContainer = Get-AzureRmRecoveryServicesBackupContainer -ContainerType "AzureVM" –Status "Registered" -FriendlyName $backupvmname -WarningAction SilentlyContinue -InformationAction SilentlyContinue -ErrorAction Stop
$backupitem = Get-AzureRmRecoveryServicesBackupItem –Container $namedContainer –WorkloadType "AzureVM" -InformationAction SilentlyContinue -WarningAction SilentlyContinue -ErrorAction Stop
$startDate = (Get-Date).AddDays(-7)
$endDate = Get-Date
$rp = Get-AzureRmRecoveryServicesBackupRecoveryPoint -Item $backupitem -StartDate $startdate.ToUniversalTime() -EndDate $enddate.ToUniversalTime() -WarningAction SilentlyContinue -ErrorAction Stop -InformationAction SilentlyContinue
$rp[0]
Write-Host "Preparing Restore Job"
$restorejob = Restore-AzureRmRecoveryServicesBackupItem -RecoveryPoint $rp[0] -StorageAccountName $StorageName -StorageAccountResourceGroupName $storeagerg -WarningAction SilentlyContinue -InformationAction SilentlyContinue -ErrorAction Stop
Wait-AzureRmRecoveryServicesBackupJob -Job $restorejob -Timeout 43200 -WarningAction SilentlyContinue -InformationAction SilentlyContinue -ErrorAction Stop
Write-Host "Restore Job Running"
$script:restorejob = $restorejob
$restorejob = Get-AzureRmRecoveryServicesBackupJob -Job $script:restorejob -InformationAction SilentlyContinue -WarningAction SilentlyContinue -ErrorAction Stop
$JobDetails = Get-AzureRmRecoveryServicesBackupJobDetails -Job $restorejob -InformationAction SilentlyContinue -WarningAction SilentlyContinue -ErrorAction Stop
$properties = $JobDetails.properties
$properties
$storageAccountName = $properties["Target Storage Account Name"]
$containerName = $properties["Config Blob Container Name"]
$blobName = $properties["Config Blob Name"]
Write-Host $storageAccountName
Write-Host $blobName
Write-Host $containerName
Write-Host "Completed restore job"
Set-AzureRmCurrentStorageAccount -Name $storageaccountname -ResourceGroupName $storeagerg
$destination_path = $restorejson
Get-AzureStorageBlobContent -Container $containerName -Blob $blobName -Destination $destination_path -ErrorAction Stop -WarningAction SilentlyContinue -InformationAction SilentlyContinue -Force -Confirm:$false
$obj = ((Get-Content -Path $destination_path -Raw -Encoding Unicode)).TrimEnd([char]0x00) | ConvertFrom-Json
Write-Host "Exported json configuration file to $destination_path"
$vm = New-AzureRmVMConfig -VMSize $obj.'properties.hardwareProfile'.vmSize -VMName $createvmname -ErrorAction Stop -WarningAction SilentlyContinue -InformationAction SilentlyContinue
Set-AzureRmVMOSDisk -VM $vm -Name "osdisk" -VhdUri $obj.'properties.StorageProfile'.osDisk.vhd.Uri -CreateOption "Attach" -WarningAction SilentlyContinue -ErrorAction Stop -InformationAction SilentlyContinue
$vm.StorageProfile.OsDisk.OsType = $obj.'properties.StorageProfile'.OsDisk.OsType
foreach($dd in $obj.'properties.StorageProfile'.DataDisks)
{
$vm = Add-AzureRmVMDataDisk -VM $vm -Name "datadisk1" -VhdUri $dd.vhd.Uri -DiskSizeInGB 128 -Lun $dd.Lun -CreateOption "Attach"
}
Write-Host "Completed data disk configuration"
$pip = New-AzureRmPublicIpAddress -Name $InterfaceName1 -ResourceGroupName $createvmrg -Location $createvmlocation -AllocationMethod "Dynamic" –Confirm:$false -WarningAction SilentlyContinue -ErrorAction Stop -Force -InformationAction SilentlyContinue
Write-Host "Completed public ip creation"
$script:VNet = Get-AzureRMVirtualNetwork -Name $VNetName -ResourceGroupName $vnetrg | Set-AzureRmVirtualNetwork
$script:Interface1 = New-AzureRmNetworkInterface -Name $InterfaceName1 -ResourceGroupName $createvmrg -Location $createvmlocation -SubnetId $VNet.Subnets[$Subnet1].Id -PublicIpAddressId $pip.Id –Confirm:$false -WarningAction SilentlyContinue -ErrorAction Stop -EnableIPForwarding -Force
$script:VirtualMachine = Add-AzureRmVMNetworkInterface -VM $vm -Id $script:Interface1.Id -Primary -WarningAction SilentlyContinue -ErrorAction Stop -InformationAction SilentlyContinue
Write-Host "Completed vm prep"
}
Function Login-AddAzureRmProfile
{
Add-AzureRmAccount -WarningAction SilentlyContinue
}
Function Create-VM
{
Write-Host "Creating VM"
New-AzureRmVM -ResourceGroupName $createvmrg -Location $createvmlocation -VM $script:VirtualMachine
}
try {
Get-AzureRmResourceGroup -Location $Location -ErrorAction Stop | Out-Null
}
catch {
Write-Host -foregroundcolor Yellow `
"User has not authenticated, use Add-AzureRmAccount or $($_.Exception.Message)"; `
Login-AddAzureRmProfile
}
Reg-Provider
if($csvimport) {
try {
csv-run
}
catch {
Write-Host -foregroundcolor Yellow `
"$($_.Exception.Message)"; `
break
}
}
try {
Configure-Backup
}
catch {
Write-Host -foregroundcolor Yellow `
"$($_.Exception.Message)"; `
break
}
Error Message:
The below error is coming while I run from Run books automation account. provided runtime parameters to run the above script and left the value for CSVIMPORT parameter.
System.Management.Automation.ParameterBindingValidationException: Cannot bind argument to parameter 'Path' because it is null.
at System.Management.Automation.ParameterBinderController.BindPositionalParametersInSet(UInt32 validParameterSets, Dictionary`2 nextPositionalParameters, CommandParameterInternal argument, ParameterBindingFlags flags, ParameterBindingException& bindingException)
at System.Management.Automation.ParameterBinderController.BindPositionalParameters(Collection`1 unboundArguments, UInt32 validParameterSets, UInt32 defaultParameterSet, ParameterBindingException& outgoingBindingException)
at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParametersNoValidation(Collection`1 arguments)
at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParameters(Collection`1 arguments)
at System.Management.Automation.CommandProcessor.BindCommandLineParameters()
at System.Management.Automation.CommandProcessorBase.DoPrepare(IDictionary psDefaultParameterValues)
at System.Management.Automation.Internal.PipelineProcessor.Start(Boolean incomingStream)
at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext)
at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
Environments Context
------------ -------
{[AzureCloud, AzureCloud], [AzureChinaCloud, AzureChinaCloud], [AzureUSGovernment, AzureUSGovernment]} Microsoft.Azur...
A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: Are you sure you want to register the provider 'Microsoft.RecoveryServices'
param (
[Parameter(Mandatory=$false)][String]$ResourceGroupName,
[Parameter(Mandatory=$false)][String]$ServicePrincipalName,
[Parameter(Mandatory=$false)][String]$ServicePrincipalPass,
[Parameter(Mandatory=$false)][String]$SubscriptionId,
[Parameter(Mandatory=$false)][String]$TenantId,
[Parameter(Mandatory=$false)][String]$VMname,
[Parameter(Mandatory=$false)][String]$vaultname
)
$targetVault = Get-AzRecoveryServicesVault -ResourceGroupName $ResourceGroupName -Name $vaultname
$targetVault.ID
Get-AzRecoveryServicesBackupProtectionPolicy -WorkloadType "AzureVM" -VaultId $targetVault.ID
Get-AzRecoveryServicesVault -Name $vaultname | Set-AzRecoveryServicesVaultContext
$policy = Get-AzRecoveryServicesBackupProtectionPolicy -Name $policyname
Enable-AzRecoveryServicesBackupProtection -ResourceGroupName $ResourceGroupName -Name $VMname -Policy $policy
$backupcontainer = Get-AzRecoveryServicesBackupContainer -ContainerType "AzureVM" -FriendlyName $VMname
$item = Get-AzRecoveryServicesBackupItem -Container $backupcontainer -WorkloadType "AzureVM"
$backupjob=Backup-AzRecoveryServicesBackupItem -Item $item
echo $backupjob
#$Backupstatus=Get-AzRecoveryservicesBackupJob
#Wait-AzRecoveryServicesBackupJob -Job $joblist[0] -Timeout 43200 -VaultId $targetVault.ID
Get-AzRecoveryservicesBackupJob
$namedContainer = Get-AzRecoveryServicesBackupContainer -ContainerType "AzureVM" -Status "Registered" -FriendlyName $VMname -VaultId $targetVault.ID
$backupitem = Get-AzRecoveryServicesBackupItem -Container $namedContainer -WorkloadType "AzureVM" -VaultId $targetVault.ID
echo "Please wait for backup to complete - Backup is in progress"
start-sleep -s 30
$joblist = Get-AzRecoveryservicesBackupJob –Status "InProgress" -VaultId $targetVault.ID
$joblist[0]
while (!$rp.ContainerName)
{
$startDate = (Get-Date).AddDays(-7)
$endDate = Get-Date
$rp = Get-AzRecoveryServicesBackupRecoveryPoint -Item $backupitem -StartDate $startdate.ToUniversalTime() -EndDate $enddate.ToUniversalTime() -VaultId $targetVault.ID
start-sleep -s 30
$rp[0]
Write-Host -NoNewline "Waiting 30 seconds for" $VMName "VM to backup"
}
Get-AzRecoveryservicesBackupJob
echo "Backup is completed successfully"

Lock azure resource with PowerShell

I've been trying to run a script to create a lock on azure resource to prevent resources being deleted inadvertently.
I get an error message and I can't figure out why it's showing me this error message.
Script:
#Sign in to Azure account
Login-AzAccount
#Select the subscription you want to work on
Select-AzSubscription -Subscription "test.subscription"
#Get All Resources in a resource group
$Resources = Get-AzResource -ResourceGroupName dummy_rg | Format-Table
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($null -eq $lck)
{
Write-Host "$ResourceName has no lock"
New-AzResourceLock -resourceGroupName $rg -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
Error message:
Gaurav request result:
#Start logging
Start-Transcript -Path "C:\Windows\Logs\Lock - $(((get-date).ToUniversalTime()).ToString("yyyy-MM-dd_hh-mm-ss")).log" -Force
#Connect to Azure account
Login-AzAccount
#Select Azure subscription
Set-AzContext -Subscription "subscription_id_numbers"
#Deny rule on Azure Data Factory and Azure Machine Learning
$Resources = Get-AzResource | Where-Object {$_.Name -NotLike '*adf*' -and $_.Name -NotLike '*aml*'}
# Create lock "delete" on each Resource if it doesn't exist
foreach($Resource in $Resources) {
$ResourceName = $Resource.Name
$lck = Get-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType
if ($lck -eq $null)
{
Write-Host "$ResourceName has no lock"
Set-AzResourceLock -ResourceGroupName $Resource.ResourceGroupName -ResourceName $ResourceName -ResourceType $Resource.ResourceType -LockName "$ResourceName-lck" -LockLevel CanNotDelete -Force
Write-Host "$ResourceName has been locked"
}
else
{
Write-host "$ResourceName already locked"
}
}
#Stop Logging
Stop-Transcript
This will loop on every ressources except azure data factory in the tenant and create a "delete" type lock to make sure resources aren't deleted inadvertently.
Read comments in each section to understand the code.

Attempting to enable web server logging on multiple on Azure web apps with quota and retention specified

Can someone please help me with my powershell script below? The issue that I'm facing is the "ResourceName" flag is the name of the web app that is being configured, so I need to have an array for that and have the ForEach-Object loop run against that array.
$ResourceGroupName = 'webapptestrg'
$webapps = Get-AzWebApp -ResourceGroupName 'webapptestrg'
$ResourceName = foreach ($webapp in $webapps) {$webapp.name}
$PropertiesObject = #{
httpLogs = #{
fileSystem = #{
enabled = $TRUE;
retentionInMb = 35;
retentionInDays = 7;
}
}
}
Get-AzResource -ResourceGroupName $ResourceGroupName | ForEach-Object {
Set-AzResource -Properties $PropertiesObject `
-ResourceGroupName $ResourceGroupName -ResourceType Microsoft.Web/sites/config `
-ResourceName $ResourceName.name/logs -ApiVersion 2018-11-01 -Force
}
Update. I had some help internally and we got it figured out. For anyone that needs this in the future, here's the updated code.
$ResourceGroupName = 'rgname'
$webapps = Get-AzWebApp -ResourceGroupName 'rgname'
$ResourceName = foreach ($webapp in $webapps) {$webapp.name}
$PropertiesObject = #{
httpLogs = #{
fileSystem = #{
enabled = $TRUE;
retentionInMb = 35;
retentionInDays = 7;
}
}
}
Foreach ($resource in $ResourceName) {
Set-AzResource -Properties $PropertiesObject `
-ResourceGroupName $ResourceGroupName -ResourceType Microsoft.Web/sites/config `
-ResourceName "$resource/logs" -ApiVersion 2018-11-01 -Force
}

Resources