We have more than 1000 Azure subscriptions and some subscriptions have 1000+ resources. We are running powershell script from automation account to collect using graph explorer module to collect information about all resource in each subscription. There is a default limit where powershell can only collect data from 1000 subscriptions and also 100 reources and to overcome this limit we have put togather following script but it is giving us an error. I believe the issue is within for loop somwhere.
Import-Module Az.Accounts
Import-Module Az.Automation
Import-Module Az.Storage
Import-Module Az.ResourceGraph
$resourceGroup = "rg-xxxxx"
$storageAccount = "stxxxxxxxxxx"
$subscriptionid = "xxxx-xxxx-xxxx"
$storageAccountContainer = "azure"
$connectionName = "AzureRunAsConnection" # Run using Run As account
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
$connectionResult = Connect-AzAccount -Tenant $servicePrincipalConnection.TenantID `
-ApplicationId $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint `
-ServicePrincipal
"Logged in."
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$date = get-date -format dd-MM-yyyy
$query = Search-AzGraph -Query 'Resources'
$subscriptions = Get-AzSubscription
$SubscriptionIds = $subscriptions.Id
$counter = [PSCustomObject] #{ Value = 0 }
$batchSize = 1000
$response = #()
$data = #()
$subscriptionsBatch = $subscriptionIds | Group -Property { [math]::Floor($counter.Value++ / $batchSize) }
foreach ($batch in $subscriptionsBatch){
$skipToken = $null;
$queryResult = $null;
do {
if ($null -eq $skipToken){
$queryResult = Search-Azgraph -Query $query -first 1000 -subscription $batch.Group;
$data = $data + $queryResult;
}
else{
$queryResult = Search-AzGraph -Query $query -SkipToken $skipToken -subscription $batch.Group;
$data = $data + $queryResult;
}
$skipToken = $queryResult.SkipToken;
}
while ($null -ne $skipToken);
}
$data | Export-Csv "$Env:temp/Azure-temp-totalresources.csv" -notypeinformation
Set-AzContext -SubscriptionId $subscriptionid
Set-AzCurrentStorageAccount -StorageAccountName $storageAccount -ResourceGroupName $resourceGroup
Remove-AzStorageBlob -Blob 'Azure-Azure-totalresources.csv' -Container $storageAccountContainer
Set-AzStorageBlobContent -Container $storageAccountContainer -file "$Env:temp/Azure-temp-totalresources.csv" -Blob "Azure-totalresources.csv" -force
Error we are getting is below
Search-AzGraph: C:\Temp\z11pylt2.z2k\8a832791-6abe-4a38-b4b5-0c4eea1a215d.ps1:61
Line |
61 | … eryResult = Search-AzGraph -Query $query -SkipToken $skipToken -subsc …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot process argument because the value of argument "name" is not
| valid. Change the value of the "name" argument and run the operation
| again.
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"
I want daily backup data in Azure SQL Database then save as a file in Blob and when my system has an error I can import a backup in Blob to recover the database. In the export case, I found DataFactory to do that but, It is hard to import data. What is the best way to resolve my problem?
Thanks for your help.
The best way to do this is to schedule a daily job using Azure Automation. Below you will find a PowerShell runbook you can use on Azure Automation to backup your database to an Azure storage account.
<#
.SYNOPSIS
This Azure Automation runbook automates Azure SQL database backup to Blob storage and deletes old backups from blob storage.
.DESCRIPTION
You should use this Runbook if you want manage Azure SQL database backups in Blob storage.
This runbook can be used together with Azure SQL Point-In-Time-Restore.
This is a PowerShell runbook, as opposed to a PowerShell Workflow runbook.
.PARAMETER ResourceGroupName
Specifies the name of the resource group where the Azure SQL Database server is located
.PARAMETER DatabaseServerName
Specifies the name of the Azure SQL Database Server which script will backup
.PARAMETER DatabaseAdminUsername
Specifies the administrator username of the Azure SQL Database Server
.PARAMETER DatabaseAdminPassword
Specifies the administrator password of the Azure SQL Database Server
.PARAMETER DatabaseNames
Comma separated list of databases script will backup
.PARAMETER StorageAccountName
Specifies the name of the storage account where backup file will be uploaded
.PARAMETER BlobStorageEndpoint
Specifies the base URL of the storage account
.PARAMETER StorageKey
Specifies the storage key of the storage account
.PARAMETER BlobContainerName
Specifies the container name of the storage account where backup file will be uploaded. Container will be created if it does not exist.
.PARAMETER RetentionDays
Specifies the number of days how long backups are kept in blob storage. Script will remove all older files from container.
For this reason dedicated container should be only used for this script.
.INPUTS
None.
.OUTPUTS
Human-readable informational and error messages produced during the job. Not intended to be consumed by another runbook.
#>
param(
[parameter(Mandatory=$true)]
[String] $ResourceGroupName,
[parameter(Mandatory=$true)]
[String] $DatabaseServerName,
[parameter(Mandatory=$true)]
[String]$DatabaseAdminUsername,
[parameter(Mandatory=$true)]
[String]$DatabaseAdminPassword,
[parameter(Mandatory=$true)]
[String]$DatabaseNames,
[parameter(Mandatory=$true)]
[String]$StorageAccountName,
[parameter(Mandatory=$true)]
[String]$BlobStorageEndpoint,
[parameter(Mandatory=$true)]
[String]$StorageKey,
[parameter(Mandatory=$true)]
[string]$BlobContainerName,
[parameter(Mandatory=$true)]
[Int32]$RetentionDays
)
$ErrorActionPreference = 'stop'
function Login() {
$connectionName = "AzureRunAsConnection"
try
{
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
Write-Verbose "Logging in to Azure..." -Verbose
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint | Out-Null
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
}
function Create-Blob-Container([string]$blobContainerName, $storageContext) {
Write-Verbose "Checking if blob container '$blobContainerName' already exists" -Verbose
if (Get-AzureStorageContainer -ErrorAction "Stop" -Context $storageContext | Where-Object { $_.Name -eq $blobContainerName }) {
Write-Verbose "Container '$blobContainerName' already exists" -Verbose
} else {
New-AzureStorageContainer -ErrorAction "Stop" -Name $blobContainerName -Permission Off -Context $storageContext
Write-Verbose "Container '$blobContainerName' created" -Verbose
}
}
function Export-To-Blob-Storage([string]$resourceGroupName, [string]$databaseServerName, [string]$databaseAdminUsername, [string]$databaseAdminPassword, [string[]]$databaseNames, [string]$storageKey, [string]$blobStorageEndpoint, [string]$blobContainerName) {
Write-Verbose "Starting database export to databases '$databaseNames'" -Verbose
$securePassword = ConvertTo-SecureString –String $databaseAdminPassword –AsPlainText -Force
$creds = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $databaseAdminUsername, $securePassword
foreach ($databaseName in $databaseNames.Split(",").Trim()) {
Write-Output "Creating request to backup database '$databaseName'"
$bacpacFilename = $databaseName + (Get-Date).ToString("yyyyMMddHHmm") + ".bacpac"
$bacpacUri = $blobStorageEndpoint + $blobContainerName + "/" + $bacpacFilename
$exportRequest = New-AzureRmSqlDatabaseExport -ResourceGroupName $resourceGroupName –ServerName $databaseServerName `
–DatabaseName $databaseName –StorageKeytype "StorageAccessKey" –storageKey $storageKey -StorageUri $BacpacUri `
–AdministratorLogin $creds.UserName –AdministratorLoginPassword $creds.Password -ErrorAction "Stop"
# Print status of the export
Get-AzureRmSqlDatabaseImportExportStatus -OperationStatusLink $exportRequest.OperationStatusLink -ErrorAction "Stop"
}
}
function Delete-Old-Backups([int]$retentionDays, [string]$blobContainerName, $storageContext) {
Write-Output "Removing backups older than '$retentionDays' days from blob: '$blobContainerName'"
$isOldDate = [DateTime]::UtcNow.AddDays(-$retentionDays)
$blobs = Get-AzureStorageBlob -Container $blobContainerName -Context $storageContext
foreach ($blob in ($blobs | Where-Object { $_.LastModified.UtcDateTime -lt $isOldDate -and $_.BlobType -eq "BlockBlob" })) {
Write-Verbose ("Removing blob: " + $blob.Name) -Verbose
Remove-AzureStorageBlob -Blob $blob.Name -Container $blobContainerName -Context $storageContext
}
}
Write-Verbose "Starting database backup" -Verbose
$StorageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageKey
Login
Create-Blob-Container `
-blobContainerName $blobContainerName `
-storageContext $storageContext
Export-To-Blob-Storage `
-resourceGroupName $ResourceGroupName `
-databaseServerName $DatabaseServerName `
-databaseAdminUsername $DatabaseAdminUsername `
-databaseAdminPassword $DatabaseAdminPassword `
-databaseNames $DatabaseNames `
-storageKey $StorageKey `
-blobStorageEndpoint $BlobStorageEndpoint `
-blobContainerName $BlobContainerName
Delete-Old-Backups `
-retentionDays $RetentionDays `
-storageContext $StorageContext `
-blobContainerName $BlobContainerName
Write-Verbose "Database backup script finished" -Verbose
We have multiple VM's in our azure environment with multiple resourcegroups. Some of the resourcegroups have multiple VM's. We are now using an URL triggers webhook that will start or stop VM's. This is working, but when a resourcegroup contains multiple VM's all the VM's will start or all the VM's will stop instead of the one you want to start/stop.
Tried multiple scripts but it's isn't working or give me errors.
param(
[Parameter(Mandatory=$false)]
[object]
$WebHookData
)
write output "Data WebHook $WebHookData"
#retrieve ResourceGroup
$ResourceGroupName = $WebHookData.RequestBody
write output "Data ResourceGroup $ResourceGroupName"
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzureRmAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
$VMs = Get-AzureRmVM -ResourceGroupName $ResourceGroupName
if(!$VMs)
{
Write-Output -InputObject 'No VMs were found in the specified Resource Group.'
}
else
{
ForEach ($VM in $VMs)
{
$StartVM = Stop-AzureRmVM -ResourceGroupName $ResourceGroupName -Name $VM.Name -Force #-ErrorAction SilentlyContinue
}
}
$message = ConvertTo-Json -Compress -InputObject ([ordered]#{
headers = #{'content-type' = 'text/plain'}
body = ''
statusCode = 200
})
You could try below script for Start/Stop Virtual machine.
Start VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Start-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Verbose
}
}
Stop VM
$connectionName = "AzureRunAsConnection"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
$null = Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
$VMs = Get-AzureRmResource|Where-Object {$_.Tags.Keys -eq "owner" -and $_.Tags.Values -eq "daneum"}
foreach ($VM in $VMs) {
if ($VM.ResourceType -eq "Microsoft.Compute/virtualMachines") {
Stop-AzureRmVM -ResourceGroupName $VM.ResourceGroupName -Name $VM.Name -Force -Verbose
}
}
For webhook integration procedure you could take a look here
I've created a script which deletes blobs which are older than a set date, I'm trying to run this using an automation account, however when I test it using the "test pane" it gives the desired output, which is a list of blobs to be deleted, however when it actually runs using the automation account it doesn't display a list of blobs to be deleted.
The code is below:
### delete blobs older than 30 days
param(
[parameter(mandatory=$true)]
[int32]$daysToKeep,
[parameter(mandatory=$true)]
[string]$storageAccount,
[parameter(mandatory=$true)]
[string]$storageContainer,
[parameter(mandatory=$true)]
[string]$storageAccessKey
)
$connectionName = "AzureRunAsConnection"
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
Write-Host "logged into Azure"
$context = New-AzureStorageContext -StorageAccountName $storageAccount -StorageAccountKey $storageAccessKey
New-AzureStorageContainer -Name $storageContainer -Context $context -Permission Blob -ErrorAction SilentlyContinue
$EGBlobs = Get-AzureStorageBlob -Container $storageContainer -Context $context | sort-object LastModified | select lastmodified, name
foreach($blob in $EGBlobs)
{
if($blob.lastmodified -lt (get-date).AddDays($daysToKeep*-1))
{
$blob_date = [datetime]$blob.LastModified.UtcDateTime
Write-Output "-----------------------------------"
write-output "Purging blob from Storage: " $blob.name
write-output "----------------------------------- "
write-output "Last Modified Date of the Blob: " $blob_date
Write-Output "-----------------------------------"
Remove-AzureStorageBlob -Blob $blob.name -Container $storageContainer -Context $context
}
}
Can't see where I'm going wrong, is this a setting within Azure Automation account.
Thanks in advance
Not sure why it is, but in fact it is.
Just move the line Remove-AzureStorageBlob -Blob $blob.name -Container $storageContainer -Context $context to the top in the loop, it will work fine.
It should be:
foreach($blob in $EGBlobs)
{
if($blob.lastmodified -lt (get-date).AddDays(2))
{
Remove-AzureStorageBlob -Blob $blob.name -Container $storageContainer -Context $context
$blob_date = [datetime]$blob.LastModified.UtcDateTime
Write-Output "-----------------------------------"
write-output "Purging blob from Storage: " $blob.name
write-output "----------------------------------- "
write-output "Last Modified Date of the Blob: " $blob_date
Write-Output "-----------------------------------"
}
}