public override void ExecuteCmdlet()
        {
            this._Helper = new AEMHelper((err) => this.WriteError(err), (msg) => this.WriteVerbose(msg), (msg) => this.WriteWarning(msg),
                this.CommandRuntime.Host.UI, AzureSession.ClientFactory.CreateClient<StorageManagementClient>(DefaultProfile.Context, AzureEnvironment.Endpoint.ResourceManager), this.DefaultContext.Subscription);

            base.ExecuteCmdlet();

            ExecuteClientAction(() =>
            {
                this._Helper.WriteVerbose("Retrieving VM...");

                var selectedVM = ComputeClient.ComputeManagementClient.VirtualMachines.Get(this.ResourceGroupName, this.VMName);
                var selectedVMStatus = ComputeClient.ComputeManagementClient.VirtualMachines.GetWithInstanceView(this.ResourceGroupName, this.VMName);

                if (selectedVM == null)
                {
                    var subscriptionId = this.DefaultContext.Subscription.Id;
                    this._Helper.WriteError("No virtual machine with name {0} in resource group {1} in subscription {2} found", this.VMName, this.ResourceGroupName, subscriptionId);
                    return;
                }

                var osdisk = selectedVM.StorageProfile.OsDisk;

                if (String.IsNullOrEmpty(this.OSType))
                {
                    this.OSType = osdisk.OsType;
                }
                if (String.IsNullOrEmpty(this.OSType))
                {
                    this._Helper.WriteError("Could not determine Operating System of the VM. Please provide the Operating System type ({0} or {1}) via parameter OSType",
                        AEMExtensionConstants.OSTypeWindows, AEMExtensionConstants.OSTypeLinux);
                    return;
                }

                var disks = selectedVM.StorageProfile.DataDisks;

                var sapmonPublicConfig = new List<KeyValuePair>();
                var sapmonPrivateConfig = new List<KeyValuePair>();
                var cpuOvercommit = 0;
                var memOvercommit = 0;
                var vmsize = selectedVM.HardwareProfile.VmSize;
                switch (vmsize)
                {
                    case AEMExtensionConstants.VMSizeExtraSmall:
                    case AEMExtensionConstants.VMSizeStandard_A0:
                    case AEMExtensionConstants.VMSizeBasic_A0:
                        vmsize = "ExtraSmall (A0)";
                        WriteVerbose("VM Size is ExtraSmall - setting overcommitted setting");
                        cpuOvercommit = 1;
                        break;
                    case "Small":
                        vmsize = "Small (A1)";
                        break;
                    case "Medium":
                        vmsize = "Medium (A2)";
                        break;
                    case "Large":
                        vmsize = "Large (A3)";
                        break;
                    case "ExtraLarge":
                        vmsize = "ExtraLarge (A4)";
                        break;
                }
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "vmsize", Value = vmsize });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "vm.memory.isovercommitted", Value = memOvercommit.ToString() });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "vm.cpu.isovercommitted", Value = cpuOvercommit.ToString() });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "script.version", Value = AEMExtensionConstants.CurrentScriptVersion });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "verbose", Value = "1" });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "href", Value = "http://aka.ms/sapaem" });

                var vmSLA = this._Helper.GetVMSLA(selectedVM);
                if (vmSLA.HasSLA)
                {
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "vm.sla.throughput", Value = vmSLA.TP });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "vm.sla.iops", Value = vmSLA.IOPS });
                }

                // Get Disks
                var accounts = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
                var accountName = this._Helper.GetStorageAccountFromUri(osdisk.Vhd.Uri);
                var storageKey = this._Helper.GetAzureStorageKeyFromCache(accountName);
                accounts.Add(accountName, storageKey);

                this._Helper.WriteHost("[INFO] Adding configuration for OS disk");

                var caching = osdisk.Caching;
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.name", Value = osdisk.Name });
                sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.caching", Value = caching });
                if (this._Helper.IsPremiumStorageAccount(accountName))
                {
                    WriteVerbose("OS Disk Storage Account is a premium account - adding SLAs for OS disk");
                    var sla = this._Helper.GetDiskSLA(osdisk);
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.type", Value = AEMExtensionConstants.DISK_TYPE_PREMIUM });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.sla.throughput", Value = sla.TP });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.sla.iops", Value = sla.IOPS });
                }
                else
                {
                    WriteVerbose("OS Disk Storage Account is a standard account");
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.type", Value = AEMExtensionConstants.DISK_TYPE_STANDARD });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.connminute", Value = (accountName + ".minute") });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "osdisk.connhour", Value = (accountName + ".hour") });
                }

                // Get Storage accounts from disks
                var diskNumber = 1;
                foreach (var disk in disks)
                {
                    accountName = this._Helper.GetStorageAccountFromUri(disk.Vhd.Uri);
                    if (!accounts.ContainsKey(accountName))
                    {
                        storageKey = this._Helper.GetAzureStorageKeyFromCache(accountName);
                        accounts.Add(accountName, storageKey);
                    }

                    this._Helper.WriteHost("[INFO] Adding configuration for data disk {0}", disk.Name);
                    caching = disk.Caching;
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.lun." + diskNumber, Value = disk.Lun.ToString() });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.name." + diskNumber, Value = disk.Name });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.caching." + diskNumber, Value = caching });

                    if (this._Helper.IsPremiumStorageAccount(accountName))
                    {
                        this._Helper.WriteVerbose("Data Disk {0} Storage Account is a premium account - adding SLAs for disk", diskNumber.ToString());
                        var sla = this._Helper.GetDiskSLA(disk);
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.type." + diskNumber, Value = AEMExtensionConstants.DISK_TYPE_PREMIUM });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.sla.throughput." + diskNumber, Value = sla.TP });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.sla.iops." + diskNumber, Value = sla.IOPS });
                        this._Helper.WriteVerbose("Done - Data Disk {0} Storage Account is a premium account - adding SLAs for disk", diskNumber.ToString());

                    }
                    else
                    {
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.type." + diskNumber, Value = AEMExtensionConstants.DISK_TYPE_STANDARD });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.connminute." + diskNumber, Value = (accountName + ".minute") });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = "disk.connhour." + diskNumber, Value = (accountName + ".hour") });
                    }

                    diskNumber += 1;
                }

                //Check storage accounts for analytics
                foreach (var account in accounts)
                {
                    this._Helper.WriteVerbose("Testing Storage Metrics for {0}", account.Key);

                    var storage = this._Helper.GetStorageAccountFromCache(account.Key);

                    if (!this._Helper.IsPremiumStorageAccount(storage))
                    {
                        if (!this.SkipStorage.IsPresent)
                        {
                            var currentConfig = this._Helper.GetStorageAnalytics(storage.Name);

                            if (!this._Helper.CheckStorageAnalytics(storage.Name, currentConfig))
                            {
                                this._Helper.WriteHost("[INFO] Enabling Storage Account Metrics for storage account {0}", storage.Name);

                                // Enable analytics on storage accounts
                                this.SetStorageAnalytics(storage.Name);
                            }
                        }

                        var endpoint = this._Helper.GetAzureSAPTableEndpoint(storage);
                        var hourUri = endpoint + "$MetricsHourPrimaryTransactionsBlob";
                        var minuteUri = endpoint + "$MetricsMinutePrimaryTransactionsBlob";

                        this._Helper.WriteHost("[INFO] Adding Storage Account Metric information for storage account {0}", storage.Name);

                        sapmonPrivateConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".hour.key"), Value = account.Value });
                        sapmonPrivateConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".minute.key"), Value = account.Value });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".hour.uri"), Value = hourUri });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".minute.uri"), Value = minuteUri });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".hour.name"), Value = storage.Name });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".minute.name"), Value = storage.Name });
                    }
                    else
                    {
                        this._Helper.WriteHost("[INFO] {0} is of type {1} - Storage Account Metrics are not available for Premium Type Storage.", storage.Name, storage.AccountType.Value.ToString());
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".hour.ispremium"), Value = "1" });
                        sapmonPublicConfig.Add(new KeyValuePair() { Key = ((storage.Name) + ".minute.ispremium"), Value = "1" });
                    }
                }

                WriteVerbose("Chechking if WAD needs to be configured");
                // Enable VM Diagnostics
                if (!this.DisableWAD.IsPresent)
                {
                    this._Helper.WriteHost("[INFO] Enabling IaaSDiagnostics for VM {0}", selectedVM.Name);
                    KeyValuePair wadstorage = null;
                    if (String.IsNullOrEmpty(this.WADStorageAccountName))
                    {
                        KeyValuePair<string, string>? wadstorageTemp = accounts.Cast<KeyValuePair<string, string>?>().
                            FirstOrDefault(accTemp => !this._Helper.IsPremiumStorageAccount(accTemp.Value.Key));
                        if (wadstorageTemp.HasValue)
                        {
                            wadstorage = new KeyValuePair(wadstorageTemp.Value.Key, wadstorageTemp.Value.Value);
                        }
                    }
                    else
                    {
                        wadstorage = new KeyValuePair(this.WADStorageAccountName, this._Helper.GetAzureStorageKeyFromCache(WADStorageAccountName));
                    }

                    if (wadstorage == null)
                    {
                        this._Helper.WriteError("A Standard Storage Account is required.");
                        return;
                    }

                    selectedVM = SetAzureVMDiagnosticsExtensionC(selectedVM, wadstorage.Key, wadstorage.Value);

                    var storage = this._Helper.GetStorageAccountFromCache(wadstorage.Key);
                    var endpoint = this._Helper.GetAzureSAPTableEndpoint(storage);
                    var wadUri = endpoint + AEMExtensionConstants.WadTableName;

                    sapmonPrivateConfig.Add(new KeyValuePair() { Key = "wad.key", Value = wadstorage.Value });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "wad.name", Value = wadstorage.Key });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "wad.isenabled", Value = "1" });
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "wad.uri", Value = wadUri });
                }
                else
                {
                    sapmonPublicConfig.Add(new KeyValuePair() { Key = "wad.isenabled", Value = "0" });
                }

                ExtensionConfig jsonPublicConfig = new ExtensionConfig();
                jsonPublicConfig.Config = sapmonPublicConfig;

                ExtensionConfig jsonPrivateConfig = new ExtensionConfig();
                jsonPrivateConfig.Config = sapmonPrivateConfig;

                this._Helper.WriteHost("[INFO] Updating Azure Enhanced Monitoring Extension for SAP configuration - Please wait...");

                WriteVerbose("Installing AEM extension");
                var op = this.VirtualMachineExtensionClient.CreateOrUpdateWithHttpMessagesAsync(
                    this.ResourceGroupName, this.VMName, AEMExtensionConstants.AEMExtensionDefaultName[OSType],
                    new VirtualMachineExtension()
                    {
                        Publisher = AEMExtensionConstants.AEMExtensionPublisher[OSType],
                        VirtualMachineExtensionType = AEMExtensionConstants.AEMExtensionType[OSType],
                        TypeHandlerVersion = AEMExtensionConstants.AEMExtensionVersion[OSType],
                        Settings = jsonPublicConfig,
                        ProtectedSettings = jsonPrivateConfig,
                        Location = selectedVM.Location,
                        AutoUpgradeMinorVersion = true
                    }).GetAwaiter().GetResult();

                this._Helper.WriteHost("[INFO] Azure Enhanced Monitoring Extension for SAP configuration updated. It can take up to 15 Minutes for the monitoring data to appear in the SAP system.");
                this._Helper.WriteHost("[INFO] You can check the configuration of a virtual machine by calling the Test-AzureRmVMAEMExtension commandlet.");

                var result = Mapper.Map<PSAzureOperationResponse>(op);
                WriteObject(result);
            });
        }
        public override void ExecuteCmdlet()
        {
            this._Helper = new AEMHelper((err) => this.WriteError(err), (msg) => this.WriteVerbose(msg), (msg) => this.WriteWarning(msg),
                                         this.CommandRuntime.Host.UI, AzureSession.Instance.ClientFactory.CreateArmClient <StorageManagementClient>(DefaultProfile.DefaultContext, AzureEnvironment.Endpoint.ResourceManager), this.DefaultContext.Subscription);

            base.ExecuteCmdlet();

            ExecuteClientAction(() =>
            {
                this._Helper.WriteVerbose("Retrieving VM...");

                var selectedVM       = ComputeClient.ComputeManagementClient.VirtualMachines.Get(this.ResourceGroupName, this.VMName);
                var selectedVMStatus = ComputeClient.ComputeManagementClient.VirtualMachines.GetWithInstanceView(this.ResourceGroupName, this.VMName).Body.InstanceView;

                if (selectedVM == null)
                {
                    var subscriptionId = this.DefaultContext.Subscription.Id;
                    this._Helper.WriteError("No virtual machine with name {0} in resource group {1} in subscription {2} found", this.VMName, this.ResourceGroupName, subscriptionId);
                    return;
                }

                var osdisk = selectedVM.StorageProfile.OsDisk;

                if (String.IsNullOrEmpty(this.OSType))
                {
                    this.OSType = osdisk.OsType.ToString();
                }
                if (String.IsNullOrEmpty(this.OSType))
                {
                    this._Helper.WriteError("Could not determine Operating System of the VM. Please provide the Operating System type ({0} or {1}) via parameter OSType",
                                            AEMExtensionConstants.OSTypeWindows, AEMExtensionConstants.OSTypeLinux);
                    return;
                }

                var disks = selectedVM.StorageProfile.DataDisks;

                var sapmonPublicConfig  = new List <KeyValuePair>();
                var sapmonPrivateConfig = new List <KeyValuePair>();
                var cpuOvercommit       = 0;
                var memOvercommit       = 0;
                var vmsize = selectedVM.HardwareProfile.VmSize;
                switch (vmsize)
                {
                case AEMExtensionConstants.VMSizeExtraSmall:
                case AEMExtensionConstants.VMSizeStandard_A0:
                case AEMExtensionConstants.VMSizeBasic_A0:
                    vmsize = "ExtraSmall (A0)";
                    WriteVerbose("VM Size is ExtraSmall - setting overcommitted setting");
                    cpuOvercommit = 1;
                    break;

                case "Small":
                    vmsize = "Small (A1)";
                    break;

                case "Medium":
                    vmsize = "Medium (A2)";
                    break;

                case "Large":
                    vmsize = "Large (A3)";
                    break;

                case "ExtraLarge":
                    vmsize = "ExtraLarge (A4)";
                    break;
                }
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "vmsize", Value = vmsize
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "vm.role", Value = "IaaS"
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "vm.memory.isovercommitted", Value = memOvercommit
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "vm.cpu.isovercommitted", Value = cpuOvercommit
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "script.version", Value = AEMExtensionConstants.CurrentScriptVersion
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "verbose", Value = "0"
                });
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "href", Value = "http://aka.ms/sapaem"
                });

                var vmSLA = this._Helper.GetVMSLA(selectedVM);
                if (vmSLA.HasSLA)
                {
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "vm.sla.throughput", Value = vmSLA.TP
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "vm.sla.iops", Value = vmSLA.IOPS
                    });
                }

                // Get Disks
                var accounts = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);
                if (osdisk.ManagedDisk == null)
                {
                    var accountName = this._Helper.GetStorageAccountFromUri(osdisk.Vhd.Uri);
                    var storageKey  = this._Helper.GetAzureStorageKeyFromCache(accountName);
                    accounts.Add(accountName, storageKey);

                    this._Helper.WriteHost("[INFO] Adding configuration for OS disk");

                    var caching = osdisk.Caching;
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "osdisk.name", Value = this._Helper.GetDiskName(osdisk.Vhd.Uri)
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "osdisk.caching", Value = caching
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "osdisk.account", Value = accountName
                    });
                    if (this._Helper.IsPremiumStorageAccount(accountName))
                    {
                        WriteVerbose("OS Disk Storage Account is a premium account - adding SLAs for OS disk");
                        var sla = this._Helper.GetDiskSLA(osdisk);
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.type", Value = AEMExtensionConstants.DISK_TYPE_PREMIUM
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.sla.throughput", Value = sla.TP
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.sla.iops", Value = sla.IOPS
                        });
                    }
                    else
                    {
                        WriteVerbose("OS Disk Storage Account is a standard account");
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.type", Value = AEMExtensionConstants.DISK_TYPE_STANDARD
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.connminute", Value = (accountName + ".minute")
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.connhour", Value = (accountName + ".hour")
                        });
                    }
                }
                else
                {
                    var osDiskMD = ComputeClient.ComputeManagementClient.Disks.Get(this._Helper.GetResourceGroupFromId(osdisk.ManagedDisk.Id),
                                                                                   this._Helper.GetResourceNameFromId(osdisk.ManagedDisk.Id));
                    if (osDiskMD.Sku.Name == StorageAccountTypes.PremiumLRS)
                    {
                        WriteVerbose("OS Disk Storage Account is a premium account - adding SLAs for OS disk");
                        var sla     = this._Helper.GetDiskSLA(osDiskMD.DiskSizeGB, null);
                        var caching = osdisk.Caching;
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.name", Value = this._Helper.GetResourceNameFromId(osdisk.ManagedDisk.Id)
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.caching", Value = caching
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.type", Value = AEMExtensionConstants.DISK_TYPE_PREMIUM_MD
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.sla.throughput", Value = sla.TP
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "osdisk.sla.iops", Value = sla.IOPS
                        });
                    }
                    else
                    {
                        this._Helper.WriteWarning("[WARN] Standard Managed Disks are not supported. Extension will be installed but no disk metrics will be available.");
                    }
                }

                // Get Storage accounts from disks
                var diskNumber = 1;
                foreach (var disk in disks)
                {
                    if (disk.ManagedDisk != null)
                    {
                        var diskMD = ComputeClient.ComputeManagementClient.Disks.Get(this._Helper.GetResourceGroupFromId(disk.ManagedDisk.Id),
                                                                                     this._Helper.GetResourceNameFromId(disk.ManagedDisk.Id));

                        if (diskMD.Sku.Name == StorageAccountTypes.PremiumLRS)
                        {
                            this._Helper.WriteVerbose("Data Disk {0} is a Premium Managed Disk - adding SLAs for disk", diskNumber.ToString());
                            var sla       = this._Helper.GetDiskSLA(diskMD.DiskSizeGB, null);
                            var cachingMD = disk.Caching;
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.lun." + diskNumber, Value = disk.Lun
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.name." + diskNumber, Value = this._Helper.GetResourceNameFromId(disk.ManagedDisk.Id)
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.caching." + diskNumber, Value = cachingMD
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.type." + diskNumber, Value = AEMExtensionConstants.DISK_TYPE_PREMIUM_MD
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.sla.throughput." + diskNumber, Value = sla.TP
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.sla.iops." + diskNumber, Value = sla.IOPS
                            });
                            this._Helper.WriteVerbose("Done - Data Disk {0} is a Premium Managed Disk - adding SLAs for disk", diskNumber.ToString());
                        }
                        else
                        {
                            this._Helper.WriteWarning("[WARN] Standard Managed Disks are not supported. Extension will be installed but no disk metrics will be available.");
                        }
                    }
                    else
                    {
                        var accountName = this._Helper.GetStorageAccountFromUri(disk.Vhd.Uri);
                        if (!accounts.ContainsKey(accountName))
                        {
                            var storageKey = this._Helper.GetAzureStorageKeyFromCache(accountName);
                            accounts.Add(accountName, storageKey);
                        }

                        this._Helper.WriteHost("[INFO] Adding configuration for data disk {0}", disk.Name);
                        var caching = disk.Caching;
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "disk.lun." + diskNumber, Value = disk.Lun
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "disk.name." + diskNumber, Value = this._Helper.GetDiskName(disk.Vhd.Uri)
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "disk.caching." + diskNumber, Value = caching
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = "disk.account." + diskNumber, Value = accountName
                        });

                        if (this._Helper.IsPremiumStorageAccount(accountName))
                        {
                            this._Helper.WriteVerbose("Data Disk {0} Storage Account is a premium account - adding SLAs for disk", diskNumber.ToString());
                            var sla = this._Helper.GetDiskSLA(disk);
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.type." + diskNumber, Value = AEMExtensionConstants.DISK_TYPE_PREMIUM
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.sla.throughput." + diskNumber, Value = sla.TP
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.sla.iops." + diskNumber, Value = sla.IOPS
                            });
                            this._Helper.WriteVerbose("Done - Data Disk {0} Storage Account is a premium account - adding SLAs for disk", diskNumber.ToString());
                        }
                        else
                        {
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.type." + diskNumber, Value = AEMExtensionConstants.DISK_TYPE_STANDARD
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.connminute." + diskNumber, Value = (accountName + ".minute")
                            });
                            sapmonPublicConfig.Add(new KeyValuePair()
                            {
                                Key = "disk.connhour." + diskNumber, Value = (accountName + ".hour")
                            });
                        }
                    }
                    diskNumber += 1;
                }

                //Check storage accounts for analytics
                foreach (var account in accounts)
                {
                    this._Helper.WriteVerbose("Testing Storage Metrics for {0}", account.Key);

                    var storage = this._Helper.GetStorageAccountFromCache(account.Key);

                    if (!this._Helper.IsPremiumStorageAccount(storage))
                    {
                        if (!this.SkipStorage.IsPresent)
                        {
                            var currentConfig = this._Helper.GetStorageAnalytics(storage.Name);

                            if (!this._Helper.CheckStorageAnalytics(storage.Name, currentConfig))
                            {
                                this._Helper.WriteHost("[INFO] Enabling Storage Account Metrics for storage account {0}", storage.Name);

                                // Enable analytics on storage accounts
                                this.SetStorageAnalytics(storage.Name);
                            }
                        }

                        var endpoint  = this._Helper.GetAzureSAPTableEndpoint(storage);
                        var hourUri   = endpoint + "$MetricsHourPrimaryTransactionsBlob";
                        var minuteUri = endpoint + "$MetricsMinutePrimaryTransactionsBlob";

                        this._Helper.WriteHost("[INFO] Adding Storage Account Metric information for storage account {0}", storage.Name);

                        sapmonPrivateConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".hour.key"), Value = account.Value
                        });
                        sapmonPrivateConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".minute.key"), Value = account.Value
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".hour.uri"), Value = hourUri
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".minute.uri"), Value = minuteUri
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".hour.name"), Value = storage.Name
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".minute.name"), Value = storage.Name
                        });
                    }
                    else
                    {
                        this._Helper.WriteHost("[INFO] {0} is of type {1} - Storage Account Metrics are not available for Premium Type Storage.", storage.Name, storage.SkuName());
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".hour.ispremium"), Value = 1
                        });
                        sapmonPublicConfig.Add(new KeyValuePair()
                        {
                            Key = ((storage.Name) + ".minute.ispremium"), Value = 1
                        });
                    }
                }

                WriteVerbose("Chechking if WAD needs to be configured");
                // Enable VM Diagnostics
                if (this.EnableWAD.IsPresent)
                {
                    this._Helper.WriteHost("[INFO] Enabling IaaSDiagnostics for VM {0}", selectedVM.Name);
                    KeyValuePair wadstorage = null;
                    if (String.IsNullOrEmpty(this.WADStorageAccountName))
                    {
                        KeyValuePair <string, string>?wadstorageTemp = accounts.Cast <KeyValuePair <string, string>?>().
                                                                       FirstOrDefault(accTemp => !this._Helper.IsPremiumStorageAccount(accTemp.Value.Key));
                        if (wadstorageTemp.HasValue)
                        {
                            wadstorage = new KeyValuePair(wadstorageTemp.Value.Key, wadstorageTemp.Value.Value);
                        }
                    }
                    else
                    {
                        wadstorage = new KeyValuePair(this.WADStorageAccountName, this._Helper.GetAzureStorageKeyFromCache(WADStorageAccountName));
                    }

                    if (wadstorage == null)
                    {
                        this._Helper.WriteError("A standard storage account is required. Please use parameter WADStorageAccountName to specify a standard storage account you want to use for this VM.");
                        return;
                    }

                    selectedVM = SetAzureVMDiagnosticsExtensionC(selectedVM, selectedVMStatus, wadstorage.Key, wadstorage.Value as string);

                    var storage  = this._Helper.GetStorageAccountFromCache(wadstorage.Key);
                    var endpoint = this._Helper.GetAzureSAPTableEndpoint(storage);
                    var wadUri   = endpoint + AEMExtensionConstants.WadTableName;

                    sapmonPrivateConfig.Add(new KeyValuePair()
                    {
                        Key = "wad.key", Value = wadstorage.Value
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "wad.name", Value = wadstorage.Key
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "wad.isenabled", Value = 1
                    });
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "wad.uri", Value = wadUri
                    });
                }
                else
                {
                    sapmonPublicConfig.Add(new KeyValuePair()
                    {
                        Key = "wad.isenabled", Value = 0
                    });
                }

                ExtensionConfig jsonPublicConfig = new ExtensionConfig();
                jsonPublicConfig.Config          = sapmonPublicConfig;

                ExtensionConfig jsonPrivateConfig = new ExtensionConfig();
                jsonPrivateConfig.Config          = sapmonPrivateConfig;

                this._Helper.WriteHost("[INFO] Updating Azure Enhanced Monitoring Extension for SAP configuration - Please wait...");

                WriteVerbose("Installing AEM extension");

                Version aemVersion = this._Helper.GetExtensionVersion(selectedVM, selectedVMStatus, OSType, AEMExtensionConstants.AEMExtensionType[OSType], AEMExtensionConstants.AEMExtensionPublisher[OSType]);

                var op = this.VirtualMachineExtensionClient.CreateOrUpdateWithHttpMessagesAsync(
                    this.ResourceGroupName, this.VMName, AEMExtensionConstants.AEMExtensionDefaultName[OSType],
                    new VirtualMachineExtension()
                {
                    Publisher = AEMExtensionConstants.AEMExtensionPublisher[OSType],
                    VirtualMachineExtensionType = AEMExtensionConstants.AEMExtensionType[OSType],
                    TypeHandlerVersion          = aemVersion.ToString(2),
                    Settings                = jsonPublicConfig,
                    ProtectedSettings       = jsonPrivateConfig,
                    Location                = selectedVM.Location,
                    AutoUpgradeMinorVersion = true,
                    ForceUpdateTag          = DateTime.Now.Ticks.ToString()
                }).GetAwaiter().GetResult();

                this._Helper.WriteHost("[INFO] Azure Enhanced Monitoring Extension for SAP configuration updated. It can take up to 15 Minutes for the monitoring data to appear in the SAP system.");
                this._Helper.WriteHost("[INFO] You can check the configuration of a virtual machine by calling the Test-AzureRmVMAEMExtension commandlet.");

                var result = ComputeAutoMapperProfile.Mapper.Map <PSAzureOperationResponse>(op);
                WriteObject(result);
            });
        }
        private void SetNewExtension(VirtualMachine selectedVM, VirtualMachineInstanceView selectedVMStatus)
        {
            // check VM identity
            // give VM idenity access to resources/resource groups
            // deploy extension on VM

            //TODO should we allow user assigned identity?
            if (selectedVM.Identity == null)
            {
                selectedVM.Identity = new VirtualMachineIdentity(type: ResourceIdentityType.SystemAssigned);
                selectedVM          = this.ComputeClient.ComputeManagementClient.VirtualMachines.
                                      CreateOrUpdate(this.ResourceGroupName, this.VMName, selectedVM);
            }
            else if (selectedVM.Identity.Type == ResourceIdentityType.UserAssigned)
            {
                selectedVM.Identity.Type = ResourceIdentityType.SystemAssignedUserAssigned;
                selectedVM = this.ComputeClient.ComputeManagementClient.VirtualMachines.
                             CreateOrUpdate(this.ResourceGroupName, this.VMName, selectedVM);
            }

            HashSet <string> scopes = new HashSet <string>();

            int endIndex = 4; //Scope is set to resource group

            if (this.SetAccessToIndividualResources)
            {
                endIndex = 8; //Scope is set to resource
            }

            // Add VM Scope or Resource Group scope
            scopes.Add(String.Join("/", selectedVM.Id.Split('/').SubArray(0, endIndex)));
            //TODO: do we want to support unmanaged disks?
            scopes.Add(String.Join("/", selectedVM.StorageProfile.OsDisk.ManagedDisk.Id.Split('/').SubArray(0, endIndex)));
            foreach (var dataDisk in selectedVM.StorageProfile.DataDisks)
            {
                scopes.Add(String.Join("/", dataDisk.ManagedDisk.Id.Split('/').SubArray(0, endIndex)));
            }
            foreach (var nic in selectedVM.NetworkProfile.NetworkInterfaces)
            {
                scopes.Add(String.Join("/", nic.Id.Split('/').SubArray(0, endIndex)));
            }

            DateTime startTime = DateTime.Now;

            foreach (string scope in scopes)
            {
                /* In some cases, the role assignment cannot be created because the VM identity is not yet available for usage. */
                bool created = false;
                while (!created)
                {
                    string scopedRoleId            = $"{scope}/providers/Microsoft.Authorization/roleDefinitions/{AEMExtensionConstants.NewExtensionRole}";
                    string roleDefinitionId        = $"/subscriptions/{this.DefaultContext.Subscription.Id}/providers/Microsoft.Authorization/roleDefinitions/{AEMExtensionConstants.NewExtensionRole}";
                    var    existingRoleAssignments = AuthClient.RoleAssignments.ListForScope(scope);
                    var    existingRoleAssignment  = existingRoleAssignments.FirstOrDefault(assignmentTest =>
                                                                                            assignmentTest.Properties.PrincipalId.EqualsInsensitively(selectedVM.Identity.PrincipalId) &&
                                                                                            assignmentTest.Properties.RoleDefinitionId.EqualsInsensitively(roleDefinitionId) &&
                                                                                            assignmentTest.Properties.Scope.EqualsInsensitively(scope));

                    if (existingRoleAssignment != null)
                    {
                        this._Helper.WriteVerbose($"Role Assignment for scope {scope} already exists for principal {selectedVM.Identity.PrincipalId}");
                        created = true;
                        break;
                    }


                    RoleAssignmentCreateParameters createParameters = new RoleAssignmentCreateParameters()
                    {
                        Properties = new RoleAssignmentProperties()
                        {
                            RoleDefinitionId = scopedRoleId,
                            //TODO: do we want to support user assigned identity?
                            PrincipalId = selectedVM.Identity.PrincipalId
                        }
                    };
                    try
                    {
                        string testMode       = Environment.GetEnvironmentVariable("AZURE_TEST_MODE");
                        string assignmentName = Guid.NewGuid().ToString();
                        if ("Record".EqualsInsensitively(testMode) || Microsoft.WindowsAzure.Commands.Utilities.Common.TestMockSupport.RunningMocked)
                        {
                            // Make sure to use the same ID during test record and playback
                            assignmentName = AEMHelper.GenerateGuid(scope);
                        }

                        AuthClient.RoleAssignments.Create(scope, assignmentName, createParameters);
                        created = true;
                    }
                    catch (CloudException cex)
                    {
                        if (!("PrincipalNotFound".Equals(cex.Body.Code)))
                        {
                            throw;
                        }

                        this._Helper.WriteVerbose(cex.ToString());
                    }

                    if (!created && (DateTime.Now - startTime).TotalSeconds < MAX_WAIT_TIME_FOR_SP_SECONDS)
                    {
                        this._Helper.WriteVerbose("Virtual Machine System Identity not available yet - waiting 5 seconds");
                        Microsoft.WindowsAzure.Commands.Utilities.Common.TestMockSupport.Delay(5000);
                    }
                    else if (!created)
                    {
                        this._Helper.WriteError($"Waited {MAX_WAIT_TIME_FOR_SP_SECONDS} seconds for VM identity to become available - giving up. Please try again later.");
                        return;
                    }
                }
            }

            var sapmonPublicConfig = new List <KeyValuePair>();

            if (!String.IsNullOrEmpty(this.ProxyURI))
            {
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "proxy", Value = this.ProxyURI
                });
            }
            if (this.DebugExtension.IsPresent)
            {
                sapmonPublicConfig.Add(new KeyValuePair()
                {
                    Key = "debug", Value = "1"
                });
            }

            ExtensionConfig jsonPublicConfig = new ExtensionConfig();

            jsonPublicConfig.Config = sapmonPublicConfig;

            var vmExtensionConfig = new VirtualMachineExtension()
            {
                Publisher = AEMExtensionConstants.AEMExtensionPublisherv2[OSType],
                VirtualMachineExtensionType = AEMExtensionConstants.AEMExtensionTypev2[OSType],
                TypeHandlerVersion          = AEMExtensionConstants.AEMExtensionVersionv2[OSType].ToString(2),
                Location = selectedVM.Location,
                Settings = jsonPublicConfig,
                AutoUpgradeMinorVersion = true,
                ForceUpdateTag          = DateTime.Now.Ticks.ToString()
            };

            if (NoWait.IsPresent)
            {
                var op = this.VirtualMachineExtensionClient.BeginCreateOrUpdateWithHttpMessagesAsync(
                    this.ResourceGroupName, this.VMName, AEMExtensionConstants.AEMExtensionDefaultNamev2[OSType],
                    vmExtensionConfig).GetAwaiter().GetResult();

                var result = ComputeAutoMapperProfile.Mapper.Map <PSAzureOperationResponse>(op);
                WriteObject(result);
            }
            else
            {
                var op = this.VirtualMachineExtensionClient.CreateOrUpdateWithHttpMessagesAsync(
                    this.ResourceGroupName, this.VMName, AEMExtensionConstants.AEMExtensionDefaultNamev2[OSType],
                    vmExtensionConfig).GetAwaiter().GetResult();

                var result = ComputeAutoMapperProfile.Mapper.Map <PSAzureOperationResponse>(op);
                WriteObject(result);
            }
        }