From e4d9106fa861fe8df5f228063f23c4afa3d77491 Mon Sep 17 00:00:00 2001 From: Kristian Nese Date: Fri, 11 Aug 2017 14:47:21 +0200 Subject: [PATCH] initial commit --- azmgmt-demo/README.md | 81 ++ azmgmt-demo/azuredeploy.json | 355 +++++++++ azmgmt-demo/azuredeploy.parameters.json | 36 + azmgmt-demo/images/dashboard-new.png | Bin 0 -> 71873 bytes azmgmt-demo/metadata.json | 7 + azmgmt-demo/nestedtemplates/asrRunbooks.json | 195 +++++ azmgmt-demo/nestedtemplates/drEnablement.json | 270 +++++++ azmgmt-demo/nestedtemplates/dscConfigs.json | 259 ++++++ .../nestedtemplates/managedLinuxBackup.json | 54 ++ azmgmt-demo/nestedtemplates/managedVms.json | 406 ++++++++++ .../nestedtemplates/managedVmsBackup.json | 77 ++ .../nestedtemplates/mgmtDashboards.json | 274 +++++++ .../nestedtemplates/omsAutomation.json | 184 +++++ .../nestedtemplates/omsRecoveryServices.json | 148 ++++ azmgmt-demo/nestedtemplates/omsWorkspace.json | 754 ++++++++++++++++++ .../scripts/ASR-AddMultipleLoadBalancers.ps1 | 143 ++++ .../scripts/ASR-AddPublicIp.ps1 | 110 +++ .../scripts/ASR-AddSingleLoadBalancer.ps1 | 132 +++ .../scripts/ASR-AddSingleNSGPublicIp.ps1 | 135 ++++ .../scripts/ASR-DNS-UpdateIP.ps1 | 135 ++++ .../scripts/ASR-SQL-FailoverAG.ps1 | 124 +++ .../scripts/ASR-SQL-FailoverAGClassic.ps1 | 98 +++ .../ASR-Wordpress-ChangeMysqlConfig.ps1 | 89 +++ .../scripts/Automated-IaaS-Backup.ps1 | 90 +++ .../nestedtemplates/scripts/SQLAGFailover.ps1 | 6 + .../nestedtemplates/scripts/UpdateDNS.ps1 | 10 + azmgmt-demo/nestedtemplates/scripts/oms.ps1 | 32 + .../nestedtemplates/scripts/omsasr.ps1 | 48 ++ .../nestedtemplates/scripts/omsservice.ps1 | 13 + 29 files changed, 4265 insertions(+) create mode 100644 azmgmt-demo/README.md create mode 100644 azmgmt-demo/azuredeploy.json create mode 100644 azmgmt-demo/azuredeploy.parameters.json create mode 100644 azmgmt-demo/images/dashboard-new.png create mode 100644 azmgmt-demo/metadata.json create mode 100644 azmgmt-demo/nestedtemplates/asrRunbooks.json create mode 100644 azmgmt-demo/nestedtemplates/drEnablement.json create mode 100644 azmgmt-demo/nestedtemplates/dscConfigs.json create mode 100644 azmgmt-demo/nestedtemplates/managedLinuxBackup.json create mode 100644 azmgmt-demo/nestedtemplates/managedVms.json create mode 100644 azmgmt-demo/nestedtemplates/managedVmsBackup.json create mode 100644 azmgmt-demo/nestedtemplates/mgmtDashboards.json create mode 100644 azmgmt-demo/nestedtemplates/omsAutomation.json create mode 100644 azmgmt-demo/nestedtemplates/omsRecoveryServices.json create mode 100644 azmgmt-demo/nestedtemplates/omsWorkspace.json create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-AddMultipleLoadBalancers.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-AddPublicIp.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleLoadBalancer.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleNSGPublicIp.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-DNS-UpdateIP.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAG.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAGClassic.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/ASR-Wordpress-ChangeMysqlConfig.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/Automated-IaaS-Backup.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/SQLAGFailover.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/UpdateDNS.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/oms.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/omsasr.ps1 create mode 100644 azmgmt-demo/nestedtemplates/scripts/omsservice.ps1 diff --git a/azmgmt-demo/README.md b/azmgmt-demo/README.md new file mode 100644 index 000000000000..b259f583a96f --- /dev/null +++ b/azmgmt-demo/README.md @@ -0,0 +1,81 @@ +# Azure management demo + +>Note: The purpose of these templates, is to give you a kick-start, instantiating all of the Azure mgmt services in Azure. +The mgmt. services will be fully integrated, and you will have VM workloads (Windows or Linux) which will be attached - and fully managed as part of the deployment. +**Please note that this sample is for demo purposes only** + + + + + +## What is being deployed + +### Management services and artifacts + +* Azure Log Analytics + +A workspace is being created, with sample datasources for both Windows and Linux, together with multiple OMS solutions. + +* Azure Automation + +The automation account will include several DSC configurations, centered on management scenarios, such as keeping the OMS agent healthy and running, as well as deploying the ASR mobility agent. A PowerShell runbook is also created, which can iterate through the subscription to enable backup on unprotected virtual machines. + +* Recovery Services + +A recovery vault - to support both Azure 2 Azure DR protection, as well as IaaS backup. The automation account also includes multiple Runbooks that can be used as part of Recovery Plans for ASR. + +### IaaS workload + +You can specify the amount of virtual machines you want to create (1-10), where all the machines will be connected, protected, and attached to the management services. + +## How to deploy + +These templates should be deployed using PowerShell, as you need to create two resource groups prior to submitting the deployment. +The guidance below shows a sample script, where you only have to provide your unique values to the variables. + +```powershell + +# Create 2 resource groups, for mgmt and workload +$MgmtRgName = '' # Specify a name for the resource group containing the management services +$WorkloadRgName = '' # Specify a name for the resource group containing the virtual machine(s) + +$MgmtRg = New-AzureRmResourceGroup -Name $MgmtRgName -Location westeurope -Verbose +$WorkloadRg = New-AzureRmResourceGroup -Name $WorkloadRgName -Location westeurope -Verbose + +# Define parameters for template deployment - remember to change the values! + +$OMSWorkspaceName = '' # Specify the prefix for the OMS Workspace +$OMSWorkspaceRegion = '' # Select the region for your workspace +$OMSRecoveryVaultName = '' # Specify the prefix for the Recovery Vault +$OMSRecoveryVaultRegion = '' # Select the region for your Recovery Vault +$OMSAutomationName = '' # Specify the prefix for the Azure Automation account +$OMSAutomationRegion = '' # Select the region for the Automation account +$Platform = '' # Select either 'Windows' or 'Linux' +$userName = '' # username for the VM +$vmNameSuffix = '' # Specify the suffix for the virtual machine(s) that will be created +$instanceCount = '' # You can create 1-10 VMs +$deploymentName = '' # Specify the name of the main ARM template deployment job +$templateUri = 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/azmgmt-demo/azuredeploy.json' + +# Deploy template + +New-AzureRmResourceGroupDeployment -Name $deploymentName ` + -ResourceGroupName $MgmtRg.ResourceGroupName ` + -TemplateUri $templateUri ` + -vmResourceGroup $WorkloadRg.ResourceGroupName ` + -omsRecoveryVaultName $OMSRecoveryVaultName ` + -omsRecoveryVaultRegion $OMSRecoveryVaultRegion ` + -omsWorkspaceName $OMSWorkspaceName ` + -omsWorkspaceRegion $OMSWorkspaceRegion ` + -omsAutomationAccountName $OMSAutomationName ` + -omsAutomationRegion $OMSAutomationRegion ` + -vmNameSuffix $vmNameSuffix ` + -userName $userName ` + -platform $platform ` + -instanceCount $instanceCount ` + -verbose +``` + +Navigate to [Azure Portal](https://portal.azure.com) and find the newly created dashboard, which will have the following naming convention *AzureMgmt(uniqueString(deployment().name))*: + +![media](./images/dashboard-new.png) \ No newline at end of file diff --git a/azmgmt-demo/azuredeploy.json b/azmgmt-demo/azuredeploy.json new file mode 100644 index 000000000000..26ba859b72f5 --- /dev/null +++ b/azmgmt-demo/azuredeploy.json @@ -0,0 +1,355 @@ +{ + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", + "contentVersion": "1.0.0.0", + "parameters": { + "omsRecoveryVaultName": { + "type": "string", + "metadata": { + "description": "Assign a name for the ASR Recovery Vault" + } + }, + "omsRecoveryVaultRegion": { + "type": "string", + "defaultValue": "West Europe", + "allowedValues": [ + "West US", + "East US", + "North Europe", + "West Europe", + "Brazil South", + "East Asia", + "Southeast Asia", + "North Central US", + "South Central US", + "Japan East", + "Japan West", + "Australia East", + "Australia Southeast", + "Central US", + "East US 2", + "Central India", + "South India" + ], + "metadata": { + "description": "Specify the region for your Recovery Vault" + } + }, + "omsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Assign a name for the Log Analytic Workspace Name" + } + }, + "omsWorkspaceRegion": { + "type": "string", + "defaultValue": "West Europe", + "allowedValues": [ + "East US", + "West Europe", + "Southeast Asia", + "Australia Southeast" + ], + "metadata": { + "description": "Specify the region for your Workspace" + } + }, + "omsAutomationAccountName": { + "type": "string", + "metadata": { + "description": "Assign a name for the Automation account" + } + }, + "omsAutomationRegion": { + "type": "string", + "defaultValue": "West Europe", + "allowedValues": [ + "Japan East", + "East US 2", + "West Europe", + "Southeast Asia", + "South Central US", + "North Europe", + "Canada Central", + "Australia Southeast", + "Central India", + "Japan East" + ], + "metadata": { + "description": "Specify the region for your Automation account" + } + }, + "instanceCount": { + "type": "int", + "defaultValue": 2, + "maxValue": 10, + "metadata": { + "description": "Specify the number of VMs to create" + } + }, + "vmNameSuffix": { + "type": "string", + "defaultValue": "az1demo", + "metadata": { + "description": "Assing a suffix for the VMs you will create" + } + }, + "platform": { + "type": "string", + "defaultValue": "Windows", + "allowedValues": [ + "Windows", + "Linux" + ], + "metadata": { + "description": "Select the OS type to deploy" + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D1", + "allowedValues": [ + "Standard_A1", + "Standard_A2", + "Standard_A3", + "Standard_A4", + "Standard_A5", + "Standard_A6", + "Standard_D1", + "Standard_D2", + "Standard_D3_v2", + "Standard_D4_v2", + "Standard_D5_v2" + ] + }, + "username": { + "type": "string", + "defaultValue": "azureadmin" + }, + "pwd": { + "type": "securestring" + }, + "vmResourceGroup": { + "type": "string" + } + }, + "variables": { + "nestedTemplates": { + "omsRecoveryServices": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/omsRecoveryServices.json')]", + "omsAutomation": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/omsAutomation.json')]", + "omsWorkspace": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/omsWorkspace.json')]", + "managedVMs": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/managedVms.json')]", + "asrRunbooks": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/asrRunbooks.json')]", + "dscConfigs": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/dscConfigs.json')]", + "mgmtDashboards": "[uri(deployment().properties.templateLink.uri, 'nestedtemplates/mgmtDashboards.json')]" + }, + "resourceNames": { + "omsWorkspace": "[concat(parameters('omsWorkspaceName'), uniquestring(resourceGroup().name, '-oms'))]", + "azureAutomation": "[concat(parameters('omsAutomationAccountName'), uniquestring(resourceGroup().name, '-auto'))]", + "azureRecoveryServices": "[concat(parameters('omsRecoveryVaultName'), uniquestring(resourceGroup().name, '-recovery'))]" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "omsWorkspace", + "dependsOn": [], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').omsWorkspace]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "omsWorkspaceName": { + "value": "[variables('resourceNames').omsWorkspace]" + }, + "omsWorkspaceRegion": { + "value": "[parameters('omsWorkspaceRegion')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "omsRecoveryServices", + "dependsOn": [], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').omsRecoveryServices]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "omsRecoveryVaultName": { + "value": "[variables('resourceNames').azureRecoveryServices]" + }, + "omsRecoveryVaultRegion": { + "value": "[parameters('omsRecoveryVaultRegion')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "omsAutomation", + "dependsOn": [ + "[concat('Microsoft.Resources/deployments/', 'omsRecoveryServices')]", + "[concat('Microsoft.Resources/deployments/', 'omsWorkspace')]" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').omsAutomation]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "omsAutomationAccountName": { + "value": "[variables('resourceNames').azureAutomation]" + }, + "omsAutomationRegion": { + "value": "[parameters('omsAutomationRegion')]" + }, + "omsRecoveryVaultName": { + "value": "[variables('resourceNames').azureRecoveryServices]" + }, + "omsWorkspaceName": { + "value": "[variables('resourceNames').omsWorkspace]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "asrRunbooks", + "dependsOn": [ + "omsAutomation" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').asrRunbooks]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "automationAccountName": { + "value": "[variables('resourceNames').azureAutomation]" + }, + "automationRegion": { + "value": "[parameters('omsAutomationRegion')]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "dscConfigs", + "dependsOn": [ + "omsAutomation" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').dscConfigs]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "omsAutomationAccountName": { + "value": "[variables('resourceNames').azureAutomation]" + }, + "omsAutomationRegion": { + "value": "[parameters('omsAutomationRegion')]" + }, + "omsWorkspaceName": { + "value": "[variables('resourceNames').omsWorkspace]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "deployVMs", + "resourceGroup": "[parameters('vmResourceGroup')]", + "dependsOn": [ + "omsWorkspace", + "omsRecoveryServices" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').managedVMs]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "instanceCount": { + "value": "[parameters('instanceCount')]" + }, + "vmNameSuffix": { + "value": "[parameters('vmNameSuffix')]" + }, + "platform": { + "value": "[parameters('platform')]" + }, + "vmSize": { + "value": "[parameters('vmSize')]" + }, + "userName": { + "value": "[parameters('userName')]" + }, + "pwd": { + "value": "[parameters('pwd')]" + }, + "omsRecoveryVaultName": { + "value": "[variables('resourceNames').azureRecoveryServices]" + }, + "omsRecoveryVaultRegion": { + "value": "[parameters('omsRecoveryVaultRegion')]" + }, + "omsResourceGroup": { + "value": "[resourceGroup().name]" + }, + "omsWorkspaceName": { + "value": "[variables('resourceNames').omsWorkspace]" + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2017-05-10", + "name": "mgmtDashboards", + "dependsOn": [ + "omsAutomation", + "omsWorkspace", + "omsRecoveryServices" + ], + "properties": { + "mode": "Incremental", + "templateLink": { + "uri": "[variables('nestedTemplates').mgmtDashboards]", + "contentVersion": "1.0.0.0" + }, + "parameters": { + "omsWorkspaceName": { + "value": "[variables('resourceNames').omsWorkspace]" + }, + "omsRecoveryVaultName": { + "value": "[variables('resourceNames').azureRecoveryServices]" + }, + "omsAutomationAccountName": { + "value": "[variables('resourceNames').azureAutomation]" + }, + "vmResourceGroup": { + "value": "[parameters('vmResourceGroup')]" + } + } + } + } + ], + "outputs": {} +} \ No newline at end of file diff --git a/azmgmt-demo/azuredeploy.parameters.json b/azmgmt-demo/azuredeploy.parameters.json new file mode 100644 index 000000000000..20b3a1ca0e68 --- /dev/null +++ b/azmgmt-demo/azuredeploy.parameters.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "omsRecoveryVaultName": { + "value": "GEN-UNIQUE" + }, + "omsRecoveryVaultRegion": { + "value": "West Europe" + }, + "omsWorkspaceName": { + "value": "GEN-UNIQUE-20" + }, + "omsWorkspaceRegion": { + "value": "West Europe" + }, + "omsAutomationAccountName": { + "value": "GEN-UNIQUE-30" + }, + "omsAutomationRegion": { + "value": "West Europe" + }, + "pwd": { + "value": "GEN-PASSWORD" + }, + "username": { + "value": "azureadmin" + }, + "instanceCount": { + "value": 1 + }, + "platform": { + "value": "Linux" + } + } +} \ No newline at end of file diff --git a/azmgmt-demo/images/dashboard-new.png b/azmgmt-demo/images/dashboard-new.png new file mode 100644 index 0000000000000000000000000000000000000000..1a392645d6c7a9d337d9af60a1ef8494e7d1c1ba GIT binary patch literal 71873 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 O>b{beVu}23&;A!NOW-24HOURS | Measure Count() By Computer", + "displayName": "A Software Update Installation Failed", + "category": "Software Updates" + } + }, + { + "apiVersion": "2015-11-01-preview", + "name": "[concat(parameters('omsWorkspaceName'), '/', 'HyperV1')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "properties": { + "ETag": "*", + "category": "HyperV", + "displayName": "VMs created last 24 hours", + "query": "EventLog=\"Microsoft-Windows-Hyper-V-VMMS-Admin\" EventLevelName=information EventID=13002 TimeGenerated>NOW-1DAY " + } + }, + { + "apiVersion": "2015-11-01-preview", + "name": "[concat(parameters('omsWorkspaceName'), '/', 'HyperV2')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "properties": { + "ETag": "*", + "category": "HyperV", + "displayName": "VMs deleted last 24 hours", + "Query": "EventLog=\"Microsoft-Windows-Hyper-V-VMMS-Admin\" EventLevelName=information EventID=13003 TimeGenerated>NOW-1DAY" + } + }, + { + "apiVersion": "2015-11-01-preview", + "name": "[concat(parameters('omsWorkspaceName'), '/', 'HyperV3')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "properties": { + "ETag": "*", + "category": "HyperV", + "displayName": "Replication throughput per VM", + "query": "Type:Perf ObjectName=\"Hyper-V Azure Replication Agent\" CounterName=\"Replication Throughput\" TimeGenerated>NOW-8HOURS | measure avg(CounterValue) by InstanceName interval 15minutes" + } + }, + { + "name": "[concat(parameters('omsWorkspaceName'), '/', 'SoftwareUpdateFailed2')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2015-11-01-preview", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "tags": {}, + "properties": { + "ETag": "*", + "query": "Type=Event EventID=20 Source=\"Microsoft-Windows-WindowsUpdateClient\" EventLog=\"System\" TimeGenerated>NOW-168HOURS", + "displayName": "A Software Update Installation Failed", + "category": "Software Updates" + } + }, + { + "name": "[concat(parameters('omsWorkspaceName'), '/', 'Network1')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2015-11-01-preview", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "tags": {}, + "properties": { + "ETag": "*", + "query": "Type=Event EventID=4202 Source=\"TCPIP\" EventLog=\"System\" TimeGenerated>NOW-24HOURS | Measure Count() By Computer", + "displayName": "A Network adatper was disconnected from the network", + "category": "Networking" + } + }, + { + "name": "[concat(parameters('omsWorkspaceName'), '/', 'Network2')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2015-11-01-preview", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "tags": {}, + "properties": { + "ETag": "*", + "query": "Type=Event EventID=4198 OR EventID=4199 Source=\"TCPIP\" EventLog=\"System\" TimeGenerated>NOW-24HOURS", + "displayName": "Duplicate IP address has been detected", + "category": "Networking" + } + }, + { + "name": "[concat(parameters('omsWorkspaceName'), '/', 'NTFS1')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2015-11-01-preview", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "tags": {}, + "properties": { + "ETag": "*", + "query": "Type=Event EventID=98 Source=\"Microsoft-Windows-Ntfs\" EventLog=\"System\" TimeGenerated>NOW-24HOURS | Measure Count() By Computer", + "displayName": "NTFS File System Corruption", + "category": "NTFS" + } + }, + { + "name": "[concat(parameters('omsWorkspaceName'), '/', 'NTFS2')]", + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2015-11-01-preview", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "tags": {}, + "properties": { + "ETag": "*", + "query": "Type=Event EventID=40 OR EventID=36� Source=\"DISK\" EventLog=\"System\" TimeGenerated>NOW-24HOURS | Measure Count() By Compute", + "displayName": "NTFS Quouta treshold limit reached", + "category": "NTFS" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk1", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Avg Disk sec/Read" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk2", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Avg Disk sec/Write" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk3", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Current Disk Queue Lenght" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk4", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Disk Reads/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk5", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Disk Transfers/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk6", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Disk Writes/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk7", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Free Megabytes" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LogicalDisk8", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "LogicalDisk", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "% Free Space" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Memory1", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Memory", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Available MBytes" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Memory2", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Memory", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "% Committed Bytes In Use" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Network1", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Network Adapter", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Bytes Received/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Network2", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Network Adapter", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Bytes Sent/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Network3", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Network Adapter", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Bytes Total/sec" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "CPU1", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Processor", + "instanceName": "_Total", + "intervalSeconds": 10, + "counterName": "% Processor Time" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "CPU2", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "System", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Processor Queue Lenght" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "System", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsEvent", + "properties": { + "eventLogName": "System", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + } + ] + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Application", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsEvent", + "properties": { + "eventLogName": "Application", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + } + ] + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Microsoft-Windows-Hyper-V-VMMS-Admin", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsEvent", + "properties": { + "eventLogName": "Microsoft-Windows-Hyper-V-VMMS-Admin", + "eventTypes": [ + { + "eventType": "Error" + }, + { + "eventType": "Warning" + }, + { + "eventType": "Information" + } + ] + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent1", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Average Replication Size" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent2", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Replication Throughput" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent3", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Network Send Throughput" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent4", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Replication Count" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent5", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Network Bytes Sent" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent6", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Last Replication Size" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Hyper-VAzureReplicationAgent7", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "WindowsPerformanceCounter", + "properties": { + "objectName": "Hyper-V Azure Replication Agent", + "instanceName": "*", + "intervalSeconds": 10, + "counterName": "Resynchronized Bytes" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Linux", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "LinuxPerformanceObject", + "properties": { + "performanceCounters": [ + { + "counterName": "% Used Inodes" + }, + { + "counterName": "Free Megabytes" + }, + { + "counterName": "% Used Space" + }, + { + "counterName": "Disk Transfers/sec" + }, + { + "counterName": "Disk Reads/sec" + }, + { + "counterName": "Disk Writes/sec" + } + ], + "objectName": "Logical Disk", + "instanceName": "*", + "intervalSeconds": 10 + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "LinuxPerfCollection", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "LinuxPerformanceCollection", + "properties": { + "state": "Enabled" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "IISLog", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "IISLogs", + "properties": { + "state": "OnPremiseEnabled" + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "Syslog", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "LinuxSyslog", + "properties": { + "syslogName": "kern", + "syslogSeverities": [ + { + "severity": "emerg" + }, + { + "severity": "alert" + }, + { + "severity": "crit" + }, + { + "severity": "err" + }, + { + "severity": "warning" + } + ] + } + }, + { + "apiVersion": "2015-11-01-preview", + "type": "datasources", + "name": "SyslogCollection", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "kind": "LinuxSyslogCollection", + "properties": { + "state": "Enabled" + } + } + ] + }, + { + "apiVersion": "2015-11-01-preview", + "type": "Microsoft.OperationsManagement/solutions", + "name": "[concat(variables('batch1').solutions[copyIndex()].Name)]", + "location": "[parameters('omsWorkspaceRegion')]", + "dependsOn": [ + "[concat('Microsoft.OperationalInsights/workspaces/', parameters('omsWorkspaceName'))]" + ], + "copy": { + "name": "solutionCopy", + "count": "[length(variables('batch1').solutions)]" + }, + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('omsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('batch1').solutions[copyIndex()].name]", + "product": "[concat('OMSGallery/', variables('batch1').solutions[copyIndex()].marketplaceName)]", + "promotionCode": "", + "publisher": "Microsoft" + } + } + ], + "outputs": {} +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-AddMultipleLoadBalancers.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-AddMultipleLoadBalancers.ps1 new file mode 100644 index 000000000000..83c6e7c4c97f --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-AddMultipleLoadBalancers.ps1 @@ -0,0 +1,143 @@ +<# + .DESCRIPTION + This runbook will attach an existing load balancer to the vNics of the virtual machines, in the Recovery Plan during failover. + + This will create a Public IP address for the failed over VM(s). + + Pre-requisites + All resources involved are based on Azure Resource Manager (NOT Azure Classic) + + - A Load Balancer(s) with a backend pool + - A complex Automation Variable, containing the VMGUID for each VM, ResourceGroupName for the Load Balancer(s) and the Load Balancer(s) name. + Example: + + $RPdetails = @{"6949b3a9-ae82-5e90-882c-30e48dffdcd8"=@{"ResourceGroupName"="knlb";"LBName"="knextlb"};"6dce5d61-2416-546c-9bcd-c1bc79a5a678"=@{"ResourceGroupName"="knlb";"LBName"="knintlb"}} + + $myASRobject = New-Object -TypeName PSObject -Property $RPdetails + + $ASRVariable = $myASRobject | ConvertTo-Json + + New-AzureRmAutomationVariable -Name -ResourceGroupName -AutomationAccountName -Value $ASRVariable -Encrypted $false + + The following AzureRm Modules are required + - AzureRm.Profile + - AzureRm.Resources + - AzureRm.Compute + - AzureRm.Network + + How to add the script? + Add this script as a post action in boot up group where you need to associate the VMs with the existing Load Balancer + + .NOTES + AUTHOR: krnese@microsoft.com - AzureCAT + LASTEDIT: 20 March, 2017 +#> +param ( + [Object]$RecoveryPlanContext + ) + +Write-output $RecoveryPlanContext + +# Set Error Preference + +$ErrorActionPreference = "Stop" + +if ($RecoveryPlanContext.FailoverDirection -ne "PrimaryToSecondary") + { + Write-Output "Failover Direction is not Azure, and the script will stop." + } +else { + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + Write-Output ("Found the following VMGuid(s): `n" + $VMInfo) + if ($VMInfo -is [system.array]) + { + $VMinfo = $VMinfo[0] + Write-Output "Found multiple VMs in the Recovery Plan" + } + else + { + Write-Output "Found only a single VM in the Recovery Plan" + } +Try + { + #Logging in to Azure... + + "Logging in to Azure..." + $Conn = Get-AutomationConnection -Name AzureRunAsConnection + Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint + + "Selecting Azure subscription..." + Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID -TenantId $Conn.tenantid + } +Catch + { + $ErrorMessage = 'Login to Azure subscription failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +Try + { + $RPVariable = Get-AutomationVariable -Name $RecoveryPlanContext.RecoveryPlanName + + $RPVariable = $RPVariable | convertfrom-json + + Write-Output $RPVariable + } +Catch + { + $ErrorMessage = 'Failed to retrieve Load Balancer info from Automation variables.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + #Getting VM details from the Recovery Plan Group, and associate the vNics with the Load Balancer +Try + { + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + $VMs = $RecoveryPlanContext.VmMap + $vmMap = $RecoveryPlanContext.VmMap + foreach ($VMID in $VMinfo) + { + $VM = $vmMap.$VMID + $VMDetails = $RPVariable.$VMID + + if( !(($VM -eq $Null) -Or ($VM.ResourceGroupName -eq $Null) -Or ($VM.RoleName -eq $Null) -Or ($VMDetails -eq $Null) -Or ($VMDetails.ResourceGroupName -eq $Null) -Or ($VMDetails.LBName -eq $Null))) { + + $LoadBalancer = Get-AzureRmLoadBalancer -ResourceGroupName $RPVariable.$VMID.ResourceGroupName -Name $RPVariable.$VMID.LBName + Write-Output $LoadBalancer + $VM = $vmMap.$VMID + Write-Output $VM.ResourceGroupName + Write-Output $VM.RoleName + $AzureVm = Get-AzureRmVm -ResourceGroupName $VM.ResourceGroupName -Name $VM.RoleName + If ($AzureVm.AvailabilitySetReference -eq $null) + { + Write-Output "No Availability Set is present for VM: `n" $AzureVm.Name + } + else + { + Write-Output "Availability Set is present for VM: `n" $AzureVm.Name + } + #Join the VMs NICs to backend pool of the Load Balancer + $ARMNic = Get-AzureRmResource -ResourceId $AzureVm.NetworkInterfaceIDs[0] + $Nic = Get-AzureRmNetworkInterface -Name $ARMNic.Name -ResourceGroupName $ARMNic.ResourceGroupName + $Nic.IpConfigurations[0].LoadBalancerBackendAddressPools.Add($LoadBalancer.BackendAddressPools[0]); + $Nic | Set-AzureRmNetworkInterface + Write-Output "Done configuring Load Balancing for VM" $AzureVm.Name + } + } + } +Catch + { + $ErrorMessage = 'Failed to associate the VM with the Load Balancer.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-AddPublicIp.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-AddPublicIp.ps1 new file mode 100644 index 000000000000..fd278e52a56b --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-AddPublicIp.ps1 @@ -0,0 +1,110 @@ +<# + .DESCRIPTION + This will create a Public IP address for the failed over VM(s). + + Pre-requisites + All resources involved are based on Azure Resource Manager (NOT Azure Classic) + + The following AzureRm Modules are required + - AzureRm.Profile + - AzureRm.Resources + - AzureRm.Compute + - AzureRm.Network + + How to add the script? + Add the runbook as a post action in boot up group containing the VMs, where you want to assign a public IP.. + + Clean up test failover behavior + You must manually remove the Public IP interfaces + + .NOTES + AUTHOR: krnese@microsoft.com + LASTEDIT: 20 March, 2017 +#> +param ( + [Object]$RecoveryPlanContext + ) + +Write-Output $RecoveryPlanContext + +if($RecoveryPlanContext.FailoverDirection -ne 'PrimaryToSecondary') +{ + Write-Output 'Script is ignored since Azure is not the target' +} +else +{ + + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + + Write-Output ("Found the following VMGuid(s): `n" + $VMInfo) + + if ($VMInfo -is [system.array]) + { + $VMinfo = $VMinfo[0] + + Write-Output "Found multiple VMs in the Recovery Plan" + } + else + { + Write-Output "Found only a single VM in the Recovery Plan" + } + + $RGName = $RecoveryPlanContext.VmMap.$VMInfo.ResourceGroupName + + Write-OutPut ("Name of resource group: " + $RGName) +Try + { + "Logging in to Azure..." + $Conn = Get-AutomationConnection -Name AzureRunAsConnection + Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint + + "Selecting Azure subscription..." + Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID -TenantId $Conn.tenantid + } +Catch + { + $ErrorMessage = 'Login to Azure subscription failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + # Get VMs within the Resource Group +Try + { + $VMs = Get-AzureRmVm -ResourceGroupName $RGName + Write-Output ("Found the following VMs: `n " + $VMs.Name) + } +Catch + { + $ErrorMessage = 'Failed to find any VMs in the Resource Group.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +Try + { + foreach ($VM in $VMs) + { + $ARMNic = Get-AzureRmResource -ResourceId $VM.NetworkInterfaceIDs[0] + $NIC = Get-AzureRmNetworkInterface -Name $ARMNic.Name -ResourceGroupName $ARMNic.ResourceGroupName + $PIP = New-AzureRmPublicIpAddress -Name $VM.Name -ResourceGroupName $RGName -Location $VM.Location -AllocationMethod Dynamic + $NIC.IpConfigurations[0].PublicIpAddress = $PIP + Set-AzureRmNetworkInterface -NetworkInterface $NIC + Write-Output ("Added public IP address to the following VM: " + $VM.Name) + } + Write-Output ("Operation completed on the following VM(s): `n" + $VMs.Name) + } +Catch + { + $ErrorMessage = 'Failed to add public IP address to the VM.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +} diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleLoadBalancer.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleLoadBalancer.ps1 new file mode 100644 index 000000000000..bc0ae7e8bbf5 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleLoadBalancer.ps1 @@ -0,0 +1,132 @@ +<# + .DESCRIPTION + This runbook will attach an existing load balancer to the vNics of the virtual machines, in the Recovery Plan during failover. + + This will create a Public IP address for the failed over VM(s). + + Pre-requisites + All resources involved are based on Azure Resource Manager (NOT Azure Classic) + + - A Load Balancer with a backend pool + - Automation variables for the Load Balancer name, and the Resource Group containing the Load Balancer + + To create the variables and use it towards multiple recovery plans, you should follow this pattern: + + New-AzureRmAutomationVariable -ResourceGroupName -AutomationAccountName -Name -lb -Value -Encrypted $false + + New-AzureRmAutomationVariable -ResourceGroupName -AutomationAccountName -Name -lbrg -Value -Encrypted $false + + The following AzureRm Modules are required + - AzureRm.Profile + - AzureRm.Resources + - AzureRm.Compute + - AzureRm.Network + + How to add the script? + Add this script as a post action in boot up group where you need to associate the VMs with the existing Load Balancer + + .NOTES + AUTHOR: krnese@microsoft.com - AzureCAT + LASTEDIT: 20 March, 2017 +#> +param ( + [Object]$RecoveryPlanContext + ) + +Write-output $RecoveryPlanContext + +# Set Error Preference + +$ErrorActionPreference = "Stop" + +if ($RecoveryPlanContext.FailoverDirection -ne "PrimaryToSecondary") + { + Write-Output "Failover Direction is not Azure, and the script will stop." + } +else { + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + Write-Output ("Found the following VMGuid(s): `n" + $VMInfo) + if ($VMInfo -is [system.array]) + { + $VMinfo = $VMinfo[0] + Write-Output "Found multiple VMs in the Recovery Plan" + } + else + { + Write-Output "Found only a single VM in the Recovery Plan" + } +Try + { + #Logging in to Azure... + + "Logging in to Azure..." + $Conn = Get-AutomationConnection -Name AzureRunAsConnection + Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint + + "Selecting Azure subscription..." + Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID -TenantId $Conn.tenantid + } +Catch + { + $ErrorMessage = 'Login to Azure subscription failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +Try + { + $LBNameVariable = $RecoveryPlanContext.RecoveryPlanName + "-LB" + $LBRgVariable = $RecoveryPlanContext.RecoveryPlanName + "-LBRG" + $LBName = Get-AutomationVariable -Name $LBNameVariable + $LBRgName = Get-AutomationVariable -Name $LBRgVariable + $LoadBalancer = Get-AzureRmLoadBalancer -Name $LBName -ResourceGroupName $LBRgName + } +Catch + { + $ErrorMessage = 'Failed to retrieve Load Balancer info from Automation variables.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + #Getting VM details from the Recovery Plan Group, and associate the vNics with the Load Balancer +Try + { + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + $VMs = $RecoveryPlanContext.VmMap + $vmMap = $RecoveryPlanContext.VmMap + foreach ($VMID in $VMinfo) + { + $VM = $vmMap.$VMID + Write-Output $VM.ResourceGroupName + Write-Output $VM.RoleName + $AzureVm = Get-AzureRmVm -ResourceGroupName $VM.ResourceGroupName -Name $VM.RoleName + If ($AzureVm.AvailabilitySetReference -eq $null) + { + Write-Output "No Availability Set is present for VM: `n" $AzureVm.Name + } + else + { + Write-Output "Availability Set is present for VM: `n" $AzureVm.Name + } + #Join the VMs NICs to backend pool of the Load Balancer + $ARMNic = Get-AzureRmResource -ResourceId $AzureVm.NetworkInterfaceIDs[0] + $Nic = Get-AzureRmNetworkInterface -Name $ARMNic.Name -ResourceGroupName $ARMNic.ResourceGroupName + $Nic.IpConfigurations[0].LoadBalancerBackendAddressPools.Add($LoadBalancer.BackendAddressPools[0]); + $Nic | Set-AzureRmNetworkInterface + Write-Output "Done configuring Load Balancing for VM" $AzureVm.Name + } + } +Catch + { + $ErrorMessage = 'Failed to associate the VM with the Load Balancer.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleNSGPublicIp.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleNSGPublicIp.ps1 new file mode 100644 index 000000000000..4804508f04a4 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-AddSingleNSGPublicIp.ps1 @@ -0,0 +1,135 @@ +<# + .DESCRIPTION + This will create a Public IP address for the failed over VM - only in test failover. + + Pre-requisites + 1. when you create a new Automation Account, make sure you have chosen to create a run-as account with it. + 2. If you create a run as account on your own, give the Connection Name in the variable - $connectionName + + What all you need to change in this script? + 1. Give the name of the Automation account in the variable - $AutomationAccountName + 2. Give the Resource Group name of the Automation Account in $AutomationAccountRg + + Do you want to add a NSG to the failed over VM? If yes, follow the below steps - you can skip this step if you dont want to add an NSG. + 1. Create the NSG that you want to apply + 2. Create a new Azure automation string variable -NSG (example testrp-NSG). Save it with the value of the NSG you want to use. + 3. Create a new Azure automation string variable -NSGRG (example testrp-NSGRG). Save it with the value of the NSG's Resource group you want to use. + + How to add the script? + Add this script as a post action in boot up group for which you need a public IP. All the VMs in the group will get a public IP assigned. + If the NSG parameters are specified, all the VM's NICs will get the same NSG attached. + + Clean up test failover behavior + Clean up test failover will not delete the IP address. You will need to delete the IP address manually + + + .NOTES + AUTHOR: RuturajD@microsoft.com + LASTEDIT: 27 January, 2017 +#> + + + +workflow ASR-AddSingleNSGPublicIp { + param ( + [parameter(Mandatory=$false)] + [Object]$RecoveryPlanContext + ) + + $connectionName = "AzureRunAsConnection" + $AutomationAccountName = "" #Fill this up with you Azure Automation Account Name + $AutomationAccountRg = "" #Fill this up with you Azure Automation Account Resource Group + + # This is special code only added for this test run to avoid creating public IPs in S2S VPN network + if ($RecoveryPlanContext.FailoverType -ne "Test") { + exit + } + + try + { + # Get the connection "AzureRunAsConnection " + $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName + + + + "Logging in to Azure..." + #Add-AzureRmAccount ` + Login-AzureRmAccount ` + -ServicePrincipal ` + -TenantId $servicePrincipalConnection.TenantId ` + -ApplicationId $servicePrincipalConnection.ApplicationId ` + -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint + } + catch { + if (!$servicePrincipalConnection) + { + $ErrorMessage = "Connection $connectionName not found." + throw $ErrorMessage + } else{ + Write-Error -Message $_.Exception + throw $_.Exception + } + } + + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + + Write-output $RecoveryPlanContext.VmMap + Write-output $RecoveryPlanContext + + # Get the NSG based on the name + # if he has not passed this value just create the public IP and go ahead + + + $NSGValue = $RecoveryPlanContext.RecoveryPlanName + "-NSG" + $NSGRGValue = $RecoveryPlanContext.RecoveryPlanName + "-NSGRG" + Write-Output $NSGValue + Write-Output $NSGRGValue + + $NSGnameVar = Get-AzureRMAutomationVariable -AutomationAccountName $AutomationAccountName -Name $NSGValue -ResourceGroupName $AutomationAccountRg + $RGnameVar = Get-AzureRMAutomationVariable -AutomationAccountName $AutomationAccountName -Name $NSGRGValue -ResourceGroupName $AutomationAccountRg + + + $NSGname = $NSGnameVar.value + $NSGRGname = $RGnameVar.value + Write-Output $NSGname + Write-Output $NSGRGname + + #For all VMs in the group - loop and get the VMs + + $VMs = $RecoveryPlanContext.VmMap; + + $vmMap = $RecoveryPlanContext.VmMap + + foreach($VMID in $VMinfo) + { + $VM = $vmMap.$VMID + + if( !(($VM -eq $Null) -Or ($VM.ResourceGroupName -eq $Null) -Or ($VM.RoleName -eq $Null))) { + #this is when some data is anot available and it will fail + Write-output "Resource group name ", $VM.ResourceGroupName + Write-output "Rolename " = $VM.RoleName + + InlineScript { + + $azurevm = Get-AzureRMVM -ResourceGroupName $Using:VM.ResourceGroupName -Name $Using:VM.RoleName + write-output "Azure VM Id", $azurevm.Id + $NicArmObject = Get-AzureRmResource -ResourceId $azurevm.NetworkInterfaceIDs[0] + write-output "Nic Arm Object Id = ", $NicArmObject.Id + $VMNetworkInterfaceObject = Get-AzureRmNetworkInterface -Name $NicArmObject.Name -ResourceGroupName $NicArmObject.ResourceGroupName + write-output "Nic Interface Id", $VMNetworkInterfaceObject.Id + $PIP = New-AzureRmPublicIpAddress -Name $azurevm.Name -ResourceGroupName $Using:VM.ResourceGroupName -Location $azurevm.Location -AllocationMethod Dynamic -Confirm:$false + If($PIP -ne $Null) { + Write-output "Public IP Id = ", $PIP.Id + $VMNetworkInterfaceObject.IpConfigurations[0].PublicIpAddress = $PIP + } + if (($Using:NSGname -ne $Null) -And ($Using:NSGRGname -ne $Null)) { + $NSG = Get-AzureRmNetworkSecurityGroup -Name $Using:NSGname -ResourceGroupName $Using:NSGRGname + Write-output $NSG.Id + $VMNetworkInterfaceObject.NetworkSecurityGroup = $NSG + } + #Update the properties now + Set-AzureRmNetworkInterface -NetworkInterface $VMNetworkInterfaceObject + } + } + } +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-DNS-UpdateIP.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-DNS-UpdateIP.ps1 new file mode 100644 index 000000000000..b8e87c38ae4f --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-DNS-UpdateIP.ps1 @@ -0,0 +1,135 @@ +<# + .DESCRIPTION + This script updates the DNS of virtual machine being failed over + + Pre-requisites + 1. When you create a new Automation Account, make sure you have chosen to create a run-as account with it. + 2. If you create a run as account on your own, give the Connection Name in the variable - $connectionName + 3. Do a test failover of DNS virtual machine in the test network + + + What all you need to change in this script? + 1. Change the value of $Location in the runbook, with the region where the Azure VMs will be running + 2. Change the value of TestDNSVMName with the name of the DNS Azure virtual machine created in test network + 3. Change the value of TestDNSVMRG with the name resource group of the DNS Azure virtual machine created in test network + 4. Change the value of ProdDNSVMName with the name of the DNS Azure virtual machine in your Azure production network + 5. Change the value of ProdDNSVMRG with the name resource group of the DNS Azure virtual machine in your Azure production network + + + How to add the script? + Add this script as a post action in a recovery plan group which has the virtual machines for which DNS has to be updated + + Input Parameters + Create an input parameter using the following powershell script. + $InputObject = @{"#VMIdAsAvailableINASRVMProperties"=@{"Zone"="#ZoneFortheVirtualMachine";"VMName"="#HostNameofTheVirtualMachine"};"#VMIdAsAvailableINASRVMProperties2"=@{"Zone"="#ZoneFortheVirtualMachine2";"VMName"="#HostNameofTheVirtualMachine2"}} + $RPDetails = New-Object -TypeName PSObject -Property $InputObject | ConvertTo-Json + New-AzureRmAutomationVariable -Name "#RecoveryPlanName" -ResourceGroupName "#AutomationAccountResourceGroup" -AutomationAccountName "#AutomationAccountName" -Value $RPDetails -Encrypted $false + + Replace all strings starting with a '#' with appropriate value + + 1. VMIdAsAvailableINASRVMProperties : VM Id as shown in virtual machine properties inside Recovery services vault (https://docs.microsoft.com/en-in/azure/site-recovery/site-recovery-runbook-automation#using-complex-variable-to-store-more-information) + 2. ZoneFortheVirtualMachine : Zone of the virtual machine + 3. HostNameofTheVirtualMachine : Host name of the virtual machine. For example for a virtual machine with FQDN myvm.contoso.com HostNameofTheVirtualMachine is myvm and Zone is contoso.com. You can add more such blocks if there are more virtual machines being failed over as part of the recovery plan. + 4. RecoveryPlanName : Name of the RecoveryPlanName where this script will be added. + 5. AutomationAccountName : Name of the Automation Account where this script is stored. + 6. AutomationAccountResourceGroup : Name of the Resource Group of Automation Account where this script is stored. + + + .NOTES + AUTHOR: Prateek.Sharma@microsoft.com + LASTEDIT: 20 April, 2017 +#> + + + +workflow ASR-DNS-UpdateIP +{ + param ( + [parameter(Mandatory=$false)] + [Object]$RecoveryPlanContext + ) + + $connectionName = "AzureRunAsConnection" + $scriptpath = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/asr-automation-recovery/scripts/UpdateDNS.ps1" + + $Location = "" + $TestDNSVMName = "" + $TestDNSVMRG = "" + $ProdDNSVMName = "" + $ProdDNSVMRG = "" + +Try + { + #Logging in to Azure... + + "Logging in to Azure..." + $Conn = Get-AutomationConnection -Name AzureRunAsConnection + Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint + + "Selecting Azure subscription..." + Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID -TenantId $Conn.tenantid + } +Catch + { + $ErrorMessage = 'Login to Azure subscription failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + + + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + $vmMap = $RecoveryPlanContext.VmMap + + if ($RecoveryPlanContext.FailoverType -ne "Test") { + $DNSVMRG = $ProdDNSVMRG + $DNSVMName = $ProdDNSVMName + } + else { + $DNSVMRG = $TestDNSVMRG + $DNSVMName = $TestDNSVMName + + } + + $RPVariable = Get-AutomationVariable -Name $RecoveryPlanContext.RecoveryPlanName + + $RPVariable = $RPVariable | convertfrom-json + + Write-Output $RPVariable + + foreach($VMID in $VMinfo) + { + + $VM = $vmMap.$VMID + $VMDetails = $RPVariable.$VMID + Write-output "VMDetails:" $VMDetails + if( !(($VM -eq $Null) -Or ($VM.ResourceGroupName -eq $Null) -Or ($VM.RoleName -eq $Null) -Or ($VMDetails -eq $Null) -Or ($VMDetails.zone -eq $Null) -Or ($VMDetails.VMName -eq $Null))) { + #this is when some data is not available and it will fail + + InlineScript{ + $azurevm = Get-AzureRMVM -ResourceGroupName $Using:VM.ResourceGroupName -Name $Using:VM.RoleName + write-output "Updating DNS for" $azurevm.Id + $NicArmObject = Get-AzureRmResource -ResourceId $azurevm.NetworkInterfaceIDs[0] + $VMNetworkInterfaceObject = Get-AzureRmNetworkInterface -Name $NicArmObject.Name -ResourceGroupName $NicArmObject.ResourceGroupName + $IPconfiguration = $VMNetworkInterfaceObject.IpConfigurations[0] + $IP = $IPconfiguration.PrivateIpAddress + $zone = $Using:VMDetails.Zone + $VMName = $Using:VMDetails.VMName + + $argument = "-Zone " + $Zone + " -name " + $VMName + " -IP " + $IP + + Write-Output "Removing older custom script extension" + $DNSVM = Get-AzureRMVM -ResourceGroupName $Using:DNSVMRG -Name $Using:DNSVMName + $csextension = $DNSVM.Extensions | Where-Object {$_.VirtualMachineExtensionType -eq "CustomScriptExtension"} + Remove-AzureRmVMCustomScriptExtension -ResourceGroupName $Using:DNSVMRG -VMName $Using:DNSVMName -Name $csextension.Name -Force + + Write-output "Updating DNS with arguments:" $argument + Set-AzureRmVMCustomScriptExtension -ResourceGroupName $Using:DNSVMRG -VMName $Using:DNSVMName -Location $Using:Location -FileUri $Using:scriptpath -Run UpdateDNS.ps1 -Name UpdateDNSCustomScript -Argument $argument + Write-output "Completed DNS Update" + } + } + + } +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAG.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAG.ps1 new file mode 100644 index 000000000000..55d9625ff1f7 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAG.ps1 @@ -0,0 +1,124 @@ +<# + .DESCRIPTION + This script fails over SQL Always On Availability Group inside an Azure virtual machine + + Pre-requisites + 1. When you create a new Automation Account, make sure you have chosen to create a run-as account with it. + 2. If you create a run as account on your own, give the Connection Name in the variable - $connectionName + 3. Setup Azure Backup on the SQL Always On Azure virtual machine + 4. Before doing a test failover, restore a copy of the SQL Always On Azure virtual machine in the test network + + + What all you need to change in this script? + 1. Change the value of $Locaton with the region where SQl Always On Azure virtual machine is running + + How to add the script? + Add this script as a pre action of the first group of the recovery plan + + Input Parameters + Create an input parameter using the following powershell script. + $InputObject = @{"TestSQLVMName" = "#TestSQLVMName" ; "TestSQLVMRG" = "#TestSQLVMRG" ; "ProdSQLVMName" = "#ProdSQLVMName" ; "ProdSQLVMRG" = "#ProdSQLVMRG"; "Paths" = @{"1"="#sqlserver:\sql\sqlazureVM\default\availabilitygroups\ag1";"2"="#sqlserver:\sql\sqlazureVM\default\availabilitygroups\ag2"}} + $RPDetails = New-Object -TypeName PSObject -Property $InputObject | ConvertTo-Json + New-AzureRmAutomationVariable -Name "#RecoveryPlanName" -ResourceGroupName "#AutomationAccountResourceGroup" -AutomationAccountName "#AutomationAccountName" -Value $RPDetails -Encrypted $false + + Replace all strings starting with a '#' with appropriate value + + 1. TestSQLVMName : Name of the Azure virtual machine where you will restore SQL Always On Azure virtual machine using Azure Backup. + 2. TestSQLVMRG : Name of Resource Group of the Azure virtual machine where you will restore SQL Always On Azure virtual machine using Azure Backup. + 3. ProdSQLVMName : Name of the SQL Always On Azure virtual machine. + 4. ProdSQLVMRG : Name of Resource Group of the SQL Always On Azure virtual machine. + 5. Paths : Fully qualified paths of the availability groups. You can add more such blocks if there are more availability groups to be failed over. This example shows two availability groups. + 6. RecoveryPlanName : Name of the RecoveryPlanName where this script will be added. + 7. AutomationAccountName : Name of the Automation Account where this script is stored. + 8. AutomationAccountResourceGroup : Name of the Resource Group of Automation Account where this script is stored. + + + .NOTES + AUTHOR: Prateek.Sharma@microsoft.com + LASTEDIT: 27 March, 2017 +#> + + + + +workflow ASR-SQL-FailoverAG +{ + param ( + [parameter(Mandatory=$false)] + [Object]$RecoveryPlanContext + ) + + $connectionName = "AzureRunAsConnection" + $scriptpath = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/asr-automation-recovery/scripts/SQLAGFailover.ps1" + $Location = "Southeast Asia" + + +Try + { + #Logging in to Azure... + + "Logging in to Azure..." + $Conn = Get-AutomationConnection -Name AzureRunAsConnection + Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint + + "Selecting Azure subscription..." + Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID -TenantId $Conn.tenantid + } +Catch + { + $ErrorMessage = 'Login to Azure subscription failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + + + $RPVariable = Get-AutomationVariable -Name $RecoveryPlanContext.RecoveryPlanName + $RPVariable = $RPVariable | convertfrom-json + + Write-Output $RPVariable + + if ($RecoveryPlanContext.FailoverType -ne "Test") { + $SQLVMRG = $RPVariable.ProdSQLVMRG + $SQLVMName = $RPVariable.ProdSQLVMName + } + else { + $SQLVMRG = $RPVariable.TestSQLVMRG + $SQLVMName = $RPVariable.TestSQLVMName + } + + + $PathSqno = $RPVariable.Paths | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + $PathDetails = $RPVariable.Paths + + + foreach($sqno in $PathSqno) + { + + + If(!(($sqno -eq "PSComputerName") -Or ($sqno -eq "PSShowComputerName") -Or ($sqno -eq "PSSourceJobInstanceId"))) + { + + $AGPath = $PathDetails.$sqno + if(!($AGPath -eq $Null)){ + #this is when some data is not available and it will fail + + InlineScript{ + + Write-Output "Removing older custom script extension" + $SQLVM = Get-AzureRMVM -ResourceGroupName $Using:SQLVMRG -Name $Using:SQLVMName + $csextension = $SQLVM.Extensions | Where-Object {$_.VirtualMachineExtensionType -eq "CustomScriptExtension"} + Remove-AzureRmVMCustomScriptExtension -ResourceGroupName $Using:SQLVMRG -VMName $Using:SQLVMName -Name $csextension.Name -Force + + $argument = "-Path " + $Using:AGPath + + Write-output "Failing over:" $argument + Set-AzureRmVMCustomScriptExtension -ResourceGroupName $Using:SQLVMRG -VMName $Using:SQLVMName -Location $Using:Location -FileUri $Using:scriptpath -Run SQLAGFailover.ps1 -Name SQLAGCustomscript -Argument $argument + Write-output "Completed AG Failover" + } + } + } + } +} diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAGClassic.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAGClassic.ps1 new file mode 100644 index 000000000000..c8a5fd0e9ed6 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-SQL-FailoverAGClassic.ps1 @@ -0,0 +1,98 @@ +<# + .DESCRIPTION + This script fails over SQL Always On Availability Group inside a Classic Azure virtual machine + + Pre-requisites + The script below assumes that the SQL Availability Group is hosted in a classic Azure VM + + and that the name of restored virtual machine in Step-2 is SQLAzureVM-Test. Modify the script, based on the name you use for the recovered virtual machine. + + + What all you need to change in this script? + 1. Change the name of the Azure virtual machine. This script assumes that the SQL virtual machine created for test failover is named SQLAzureVM-Test and the SQL virtual machine that will be used in failvoer is named SQLAzureVM-Test + 2. Change service + 3. Change the IP address to be used for load balancer. + 4. Change the path of the availability group. + + How to add the script? + Add this script as a pre action of the first group of the recovery plan + + .NOTES + AUTHOR: Prateek.Sharma@microsoft.com + LASTEDIT: 15 May, 2017 +#> + + + +workflow ASR-SQL-FailoverAGClassic + { + + param ( + [Object]$RecoveryPlanContext + ) + + $Cred = Get-AutomationPSCredential -name 'AzureCredential' + + #Connect to Azure + $AzureAccount = Add-AzureAccount -Credential $Cred + $AzureSubscriptionName = Get-AutomationVariable –Name ‘AzureSubscriptionName’ + Select-AzureSubscription -SubscriptionName $AzureSubscriptionName + + InLineScript + { + $scriptpath = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/asr-automation-recovery/scripts/SQLAGFailover.ps1" + + + + Write-output "failovertype " + $Using:RecoveryPlanContext.FailoverType; + + if ($Using:RecoveryPlanContext.FailoverType -eq "Test") + { + Write-output "tfo" + + Write-Output "Creating ILB" + Add-AzureInternalLoadBalancer -InternalLoadBalancerName SQLAGILB -SubnetName Subnet-1 -ServiceName SQLAzureVM-Test -StaticVNetIPAddress #IP + Write-Output "ILB Created" + + #Update the script with name of the virtual machine recovered using Azure Backup + Write-Output "Adding SQL AG Endpoint" + Get-AzureVM -ServiceName "SQLAzureVM-Test" -Name "SQLAzureVM-Test"| Add-AzureEndpoint -Name sqlag -LBSetName sqlagset -Protocol tcp -LocalPort 1433 -PublicPort 1433 -ProbePort 59999 -ProbeProtocol tcp -ProbeIntervalInSeconds 10 -InternalLoadBalancerName SQLAGILB | Update-AzureVM + + Write-Output "Added Endpoint" + + $VM = Get-AzureVM -Name "SQLAzureVM-Test" -ServiceName "SQLAzureVM-Test" + + Write-Output "UnInstalling custom script extension" + Set-AzureVMCustomScriptExtension -Uninstall -ReferenceName CustomScriptExtension -VM $VM |Update-AzureVM + Write-Output "Installing custom script extension" + Set-AzureVMExtension -ExtensionName CustomScriptExtension -VM $vm -Publisher Microsoft.Compute -Version 1.*| Update-AzureVM + + Write-output "Starting AG Failover" + Set-AzureVMCustomScriptExtension -VM $VM -FileUri $scriptpath -Run "SQLAGFailover.ps1" -Argument "-Path sqlserver:\sql\sqlazureVM\default\availabilitygroups\testag" | Update-AzureVM + Write-output "Completed AG Failover" + } + else + { + Write-output "pfo/ufo"; + #Get the SQL Azure Replica VM. + #Update the script to use the name of your VM and Cloud Service + $VM = Get-AzureVM -Name "SQLAzureVM" -ServiceName "SQLAzureReplica"; + + Write-Output "Installing custom script extension" + #Install the Custom Script Extension on teh SQL Replica VM + Set-AzureVMExtension -ExtensionName CustomScriptExtension -VM $VM -Publisher Microsoft.Compute -Version 1.*| Update-AzureVM; + + Write-output "Starting AG Failover"; + #Execute the SQL Failover script + #Pass the SQL AG path as the argument. + + $AGArgs="-SQLAvailabilityGroupPath sqlserver:\sql\sqlazureVM\default\availabilitygroups\testag"; + + Set-AzureVMCustomScriptExtension -VM $VM -FileUri $scriptpath -Run "SQLAGFailover.ps1" -Argument $AGArgs | Update-AzureVM; + + Write-output "Completed AG Failover"; + + } + + } + } \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/ASR-Wordpress-ChangeMysqlConfig.ps1 b/azmgmt-demo/nestedtemplates/scripts/ASR-Wordpress-ChangeMysqlConfig.ps1 new file mode 100644 index 000000000000..244097e40c2b --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/ASR-Wordpress-ChangeMysqlConfig.ps1 @@ -0,0 +1,89 @@ +<# + .DESCRIPTION + This Runbook changes the WordPress configuration by replacing the wp-config.php and replace it with wp-config.php.Azure. + The old file will get renamed as wp-config.php.onprem + This is an example script used in blog https://azure.microsoft.com/en-us/blog/one-click-failover-of-application-to-microsoft-azure-using-site-recovery + + This runbook uses an external powershellscript located at https://raw.githubusercontent.com/ruturaj/RecoveryPlanScripts/master/ChangeWPDBHostIP.ps1 + and runs it inside all of the VMs of the group this script is added to. + + Parameter to change - + $recoveryLocation - change this to the location to which the VM is recovering to + + .NOTES + AUTHOR: RuturajD@microsoft.com + LASTEDIT: 27 March, 2017 +#> + + +workflow ASR-Wordpress-ChangeMysqlConfig +{ + param ( + [parameter(Mandatory=$false)] + [Object]$RecoveryPlanContext + ) + + $connectionName = "AzureRunAsConnection" + $recoveryLocation = "southeastasia" + + # This is special code only added for this test run to avoid creating public IPs in S2S VPN network + #if ($RecoveryPlanContext.FailoverType -ne "Test") { + # exit + #} + + try + { + # Get the connection "AzureRunAsConnection " + $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName + + + + "Logging in to Azure..." + #Add-AzureRmAccount ` + Login-AzureRmAccount ` + -ServicePrincipal ` + -TenantId $servicePrincipalConnection.TenantId ` + -ApplicationId $servicePrincipalConnection.ApplicationId ` + -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint + } + catch { + if (!$servicePrincipalConnection) + { + $ErrorMessage = "Connection $connectionName not found." + throw $ErrorMessage + } else{ + Write-Error -Message $_.Exception + throw $_.Exception + } + } + + $VMinfo = $RecoveryPlanContext.VmMap | Get-Member | Where-Object MemberType -EQ NoteProperty | select -ExpandProperty Name + + Write-output $RecoveryPlanContext.VmMap + Write-output $RecoveryPlanContext + + + $VMs = $RecoveryPlanContext.VmMap; + + $vmMap = $RecoveryPlanContext.VmMap + + foreach($VMID in $VMinfo) + { + $VM = $vmMap.$VMID + + if( !(($VM -eq $Null) -Or ($VM.ResourceGroupName -eq $Null) -Or ($VM.RoleName -eq $Null))) { + #this is when some data is anot available and it will fail + Write-output "Resource group name ", $VM.ResourceGroupName + Write-output "Rolename " = $VM.RoleName + + InlineScript { + + Set-AzureRmVMCustomScriptExtension -ResourceGroupName $Using:VM.ResourceGroupName ` + -VMName $Using:VM.RoleName ` + -Name "myCustomScript" ` + -FileUri "https://raw.githubusercontent.com/ruturaj/RecoveryPlanScripts/master/ChangeWPDBHostIP.ps1" ` + -Run "ChangeWPDBHostIP.ps1" -Location $recoveryLocation + } + } + } +} \ No newline at end of file diff --git a/azmgmt-demo/nestedtemplates/scripts/Automated-IaaS-Backup.ps1 b/azmgmt-demo/nestedtemplates/scripts/Automated-IaaS-Backup.ps1 new file mode 100644 index 000000000000..9881bfdb37b4 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/Automated-IaaS-Backup.ps1 @@ -0,0 +1,90 @@ +<# +.Synopsis + Runbook for automated IaaS VM Backup in Azure using Backup and Site Recovery (OMS) +.DESCRIPTION + This Runbook will enable Backup on existing Azure IaaS VMs. + You need to provide input to the Resource Group name that contains the Backup and Site Recovery (OMS) Resourcem the name of the recovery vault, + Fabric type, preferred policy and the template URI where the ARM template is located. Have fun! +#> + +$credential = Get-AutomationPSCredential -Name 'AzureCredentials' +$subscriptionId = Get-AutomationVariable -Name 'AzureSubscriptionID' +$OMSWorkspaceId = Get-AutomationVariable -Name 'OMSWorkspaceId' +$OMSWorkspaceKey = Get-AutomationVariable -Name 'OMSWorkspaceKey' +$OMSWorkspaceName = Get-AutomationVariable -Name 'OMSWorkspaceName' +$OMSResourceGroupName = Get-AutomationVariable -Name 'OMSResourceGroupName' +$TemplateUri='https://raw.githubusercontent.com/krnese/AzureDeploy/master/OMS/MSOMS/AzureIaaSBackup/azuredeploy.json' +$OMSRecoveryVault = Get-AutomationVariable -Name 'OMSRecoveryVault' + +$ErrorActionPreference = 'Stop' + +Try { + Login-AzureRmAccount -credential $credential + Select-AzureRmSubscription -SubscriptionId $subscriptionId + + } + +Catch { + $ErrorMessage = 'Login to Azure failed.' + $ErrorMessage += " `n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + +Try { + + $Location = Get-AzureRmRecoveryServicesVault -Name $OMSRecoveryVault -ResourceGroupName $OMSResourceGroupName | select -ExpandProperty Location + } + +Catch { + $ErrorMessage = 'Failed to retrieve the OMS Recovery Location property' + $ErrorMessage += "`n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + +Try { + $VMs = Get-AzureRmVM | Where-Object {$_.Location -eq $Location} + } + +Catch { + $ErrorMessage = 'Failed to retrieve the VMs.' + $ErrorMessage += "`n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + +# Enable Backup + +Try { + Foreach ($vm in $vms) + { + New-AzureRmResourceGroupDeployment -Name $vm.name ` + -ResourceGroupName $OMSResourceGroupName ` + -TemplateUri $TemplateUri ` + -omsRecoveryResourceGroupName $OMSResourceGroupName ` + -vmResourceGroupName $vm.ResourceGroupName ` + -vaultName $OMSRecoveryVault ` + -vmName $vm.name ` + -Verbose + } + } + +Catch { + $ErrorMessage = 'Failed to enable backup using ARM template.' + $ErrorMessage += "`n" + $ErrorMessage += 'Error: ' + $ErrorMessage += $_ + Write-Error -Message $ErrorMessage ` + -ErrorAction Stop + } + + + + diff --git a/azmgmt-demo/nestedtemplates/scripts/SQLAGFailover.ps1 b/azmgmt-demo/nestedtemplates/scripts/SQLAGFailover.ps1 new file mode 100644 index 000000000000..c72d0d5f729c --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/SQLAGFailover.ps1 @@ -0,0 +1,6 @@ +# This script gets called from Automation Runbook ASR-SQL-FailoverAG +Param( + [string] $Path + ) + import-module sqlps + Switch-SqlAvailabilityGroup -Path $Path -AllowDataLoss -force diff --git a/azmgmt-demo/nestedtemplates/scripts/UpdateDNS.ps1 b/azmgmt-demo/nestedtemplates/scripts/UpdateDNS.ps1 new file mode 100644 index 000000000000..39ce48e9ca2c --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/UpdateDNS.ps1 @@ -0,0 +1,10 @@ + #This script is used by Azure Automation Runbook ASR-DNS-UpdateIP + Param( + [string]$Zone, + [string]$name, + [string]$IP + ) + $Record = Get-DnsServerResourceRecord -ZoneName $zone -Name $name + $newrecord = $record.clone() + $newrecord.RecordData[0].IPv4Address = $IP + Set-DnsServerResourceRecord -zonename $zone -OldInputObject $record -NewInputObject $Newrecord diff --git a/azmgmt-demo/nestedtemplates/scripts/oms.ps1 b/azmgmt-demo/nestedtemplates/scripts/oms.ps1 new file mode 100644 index 000000000000..6440c7511074 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/oms.ps1 @@ -0,0 +1,32 @@ +Configuration OMS +{ + + $OMSPackageLocalPath = 'C:\MMA\MMASetup-AMD64.exe' + $OMSWorkspaceId = Get-AutomationVariable -Name 'OMSWorkspaceId' + $OMSWorkspaceKey = Get-AutomationVariable -Name 'OMSWorkspaceKey' + + + Import-DscResource -ModuleName xPSDesiredStateConfiguration + + Node localhost { + Service OMSService + { + Name = "HealthService" + State = "Running" + } + + xRemoteFile OMSPackage { + Uri = "https://go.microsoft.com/fwlink/?LinkID=517476" + DestinationPath = $OMSPackageLocalPath + } + + Package OMS { + Ensure = "Present" + Path = $OMSPackageLocalPath + Name = 'Microsoft Monitoring Agent' + ProductId = '8A7F2C51-4C7D-4BFD-9014-91D11F24AAE2' + Arguments = '/C:"setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=' + $OMSWorkspaceId + ' OPINSIGHTS_WORKSPACE_KEY=' + $OMSWorkspaceKey + ' AcceptEndUserLicenseAgreement=1"' + DependsOn = '[xRemoteFile]OMSPackage' + } + } +} diff --git a/azmgmt-demo/nestedtemplates/scripts/omsasr.ps1 b/azmgmt-demo/nestedtemplates/scripts/omsasr.ps1 new file mode 100644 index 000000000000..a70902e10a26 --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/omsasr.ps1 @@ -0,0 +1,48 @@ +Configuration OMSASR +{ + + $RemoteAzureAgent = 'http://go.microsoft.com/fwlink/p/?LinkId=394789' + $LocalAzureAgent = 'C:\Temp\AzureVmAgent.msi' + $OMSPackageLocalPath = 'C:\MMA\MMASetup-AMD64.exe' + $OMSWorkspaceId = Get-AutomationVariable -Name 'OMSWorkspaceId' + $OMSWorkspaceKey = Get-AutomationVariable -Name 'OMSWorkspaceKey' + + + Import-DscResource -ModuleName xPSDesiredStateConfiguration + + Node localhost { + Service OMSService + { + Name = "HealthService" + State = "Running" + } + + xRemoteFile OMSPackage { + Uri = "https://go.microsoft.com/fwlink/?LinkID=517476" + DestinationPath = $OMSPackageLocalPath + } + + xRemoteFile AzureAgent { + URI = $RemoteAzureAgent + DestinationPath = $LocalAzureAgent + } + + Package AzureAgent { + Path = 'C:\Temp\AzureVmAgent.msi' + Ensure = 'Present' + Name = "Windows Azure VM Agent - 2.7.1198.778" + ProductId = "5CF4D04A-F16C-4892-9196-6025EA61F964" + Arguments = '/q /l "c:\temp\agentlog.txt' + DependsOn = '[xRemoteFile]AzureAgent' + } + + Package OMS { + Ensure = "Present" + Path = $OMSPackageLocalPath + Name = 'Microsoft Monitoring Agent' + ProductId = '8A7F2C51-4C7D-4BFD-9014-91D11F24AAE2' + Arguments = '/C:"setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=' + $OMSWorkspaceId + ' OPINSIGHTS_WORKSPACE_KEY=' + $OMSWorkspaceKey + ' AcceptEndUserLicenseAgreement=1"' + DependsOn = '[xRemoteFile]OMSPackage' + } + } +} diff --git a/azmgmt-demo/nestedtemplates/scripts/omsservice.ps1 b/azmgmt-demo/nestedtemplates/scripts/omsservice.ps1 new file mode 100644 index 000000000000..02c16c9cf90e --- /dev/null +++ b/azmgmt-demo/nestedtemplates/scripts/omsservice.ps1 @@ -0,0 +1,13 @@ +Configuration OMSSERVICE +{ + + Import-DscResource -ModuleName xPSDesiredStateConfiguration + + Node localhost { + Service OMSService + { + Name = "HealthService" + State = "Running" + } + } +}