Tuesday, December 22, 2015

Find VM status of all VMs in Azure; Start/Stop VMs in bulk (in ARM)

Get-AzureRmSubscription | Where-Object {$_.SubscriptionId -like "*499"} | Select-AzureRmSubscription

#improvise the script per your need

#select your subscription or iterate through subscriptions if desired

$action="stop"
#$action="start"

$excludeStartVMs = @("winweb1hdicp", "b", "c")
$includeStartVMs = @("MyWindowsVM", "e")

$excludeStopVMs = @("1", "2", "3")
$includeStopVMs = @("4", "5")


function Take-Action($vmname, $action) {
    if ($action -eq "stop") {
        return Generic-Action $vmname $excludeStopVMs, $includeStopVMs
    }
    if ($action -eq "start") {
        return Generic-Action $vmname $excludeStartVMs $includeStartVMs
    }
    return $true;
}

function Generic-Action($vmname, $excludeArray, $includeArray) {
    #iterate through exclusion
    foreach ($exclusionVM in $excludeArray) {
        if ($exclusionVM -eq $vmname) {
            return $false
        }
    }
    #iterate through inclusion
    foreach ($exclusionVM in $includeArray) {
        if ($exclusionVM -eq $vmname) {
            return $true
        }
    }

    #or else...
    return $true;
}

#to handle situation where a vm is in weired situation, you dont want to delete it to troubleshoot, but the operations kills your time
function Include-VM($vmname) {
    foreach ($exclusionVM in ($excludeStartVMs + $excludeStopVMs)) {
        if ($exclusionVM -eq $vmname) {
            return $false
        }       
    }
    return $true
}

#select your subscription or iterate through subscriptions if desired
$sw = [Diagnostics.Stopwatch]::StartNew()
foreach ($rg in Get-AzureRmResourceGroup)
{
    foreach($vm in Get-AzureRmVM -ResourceGroupName $rg.ResourceGroupName){
        Write-Host $rg.ResourceGroupName  $vm.Name
        if (Include-VM $vm.Name) {
            #get status
            $status = ((Get-AzureRmVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name -Status).Statuses).DisplayStatus
            Write-Host $status
           
            if ($action -eq "stop") {
                if ($status -like ("*running*")) {
                    if (Take-Action $vm.Name $action) {
                        Write-Host "Going to stop ..." $rg.ResourceGroupName $vm.Name
                        Stop-AzureRmVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name

                        #doesnt prompt for confirmation...(for non-interactive/batch mode)
                        #Stop-AzureRmVM -ResourceGroupName -Force $rg.ResourceGroupName -Name $vm.Name
                        Write-Host "Stopped:" $rg.ResourceGroupName $vm.Name
                    }
                }
            }#end of stop action
            if ($action -eq "start") {
                if ($status -like ("*Stopped*") -or $status -like ("*deallocated*")) {
                    if (Take-Action $vm.Name $action) {
                        Write-Host "Going to start ..." $rg.ResourceGroupName $vm.Name
                        $confirmStatus=Read-Host 'Are you sure you want to start the VM Yes(1)/No(2) followed by <Enter> [default No(2)]'
                        if ($confirmStatus -eq $null -or $confirmStatus.Length -eq 0) {
                            $confirmStatus="2"
                        }
                        if ($confirmStatus -eq "1") {
                            Start-AzureRmVM -ResourceGroupName $rg.ResourceGroupName -Name $vm.Name
                            Write-Host "Started:" $rg.ResourceGroupName $vm.Name
                        }

                    }
                }
            }#end of start
        } #end of include vm

    }
 }
$sw.Stop()
$sw.Elapsed

Install AD Forest + DC in Azure Only in ARM (aka v2) in 30 min


Context:

Install a cloud only AD Forest + DC. (with HA)



Install:


·        Single VM install (for quick testing): https://github.com/Azure/azure-quickstart-templates/tree/master/active-directory-new-domain worked for me. It saves stuff in a data disk, puts the vm behind an alb, installs the forest via a vm extension, etc..

Note it takes a long time to complete the installation.

The deployment in portal looks like:

 (yes event after the installation is successful, so don’t get alarmed.)



But, when you dig in to the deployment, you will see a busy icon though, currently its “green”…I captured after the install. A busy symbol is what you are looking for….

Verify the installation:

However, after the install the template will show successful:


 

Also, in resources.azure.com, you should see success messages.




 



References:





·         http://blogs.msdn.com/b/rds/archive/2015/07/13/10627643.aspx (though its setting up RDS)



Troubleshooting/tips:

·         If the deployment fails, delete all its content including the resource group. Because, each deployment doesn’t create a set of unique assets even if the parameters are uniquely named, ALB for instance is not. You can certainly modify the template for your need.

·         Parameter verification: Don’t rely on the template check to validate the uniqueness of your parameter, e.g. “a” in storage account comes back as available….

Thursday, December 17, 2015

Create an Azure File Share and mount drive (and persists) on Windows and Centos

Pre-requisite: Azure Storage Account.
Steps:
1.       Create a file share either in portal.azure.com or through PS (you can’t create AFS in ARM template yet)
PS C:\Users\xyz> $storageContext=New-AzureStorageContext -StorageAccountName saaccount -StorageAccountKey yourkey

PS C:\Users\xyz> $storageContext |  New-AzureStorageShare -Name yourshare
2.       Test that file share exists
a.       Via PS
PS C:\Users\xyz> $storageContext |  Get-AzureStorageShare

b.       Via Azure File Explorer
3.       Mount the share
cmdkey /add:yoursaacount.file.core.windows.net /user:yoursaacount /pass:yoursakey
net use z: \\yoursaacount.file.core.windows.net\yourshare
4.       Test the share in windows
PS C:\Users\xyz> net use
Also, test in the File Explorer
a.       Reboot the machine
b.       Retest for the persistence

cmds on Centos:
mkdir /mnt/yourshare

sudo mount -t cifs //yourstorageaccountname.file.core.windows.net/yourshare /mnt/yourshare -o vers=3.0,user=yourstorageaccountname,password=yoursakey,dir_mode=0777,file_mode=0777

df -h /mnt/yourshare/


cd /mnt/yourshare/

Persist in /etc/fstab

//yourstorageaccountname.file.core.windows.net/yourshare  /mnt/yourshare   cifs  _netdev,username=yourstorageaccountname,password=yoursakey,dir_mode=0755,file_mode=0755,uid=500,gid=500 0 0

Troubleshooting tips:
·         Unable to connect (System error 53):
o   Ensure that outbound 425 port for TCP (for smb) is open
o   Ensure that you launched cmd as an administrator
o   Ensure that cmdkey has persisted
   cmdkey /list
o   Last resort troubleshoot with WireShark like tool
·         Unable to persists (share prompts for password after reboot of the box)

net use y: \\yoursaacount.file.core.windows.net\yourshare /u:yoursaacount yoursakey /P:Yes -- if you have use, then try cmdKey instead.
·         In linux mnt fails
 e.g.
systemd: Mounting /mnt/yourshare...
kernel: Key type dns_resolver registered
kernel: Key type cifs.spnego registered
kernel: Key type cifs.idmap registered
kernel: CIFS VFS: cifs_mount failed w/return code = -112
mount: mount error(112): Host is down


Ensure that the host is able to reach the file server. You might want to add an entry in /etc/hosts.

Wednesday, December 16, 2015

Custom FQDN for Azure WebApps (previously known as WebSites)

Pre-requisite: Create a website with App Service Plan/pricing tier with any but not a Free Tier. Free Tier doesn’t allow custom domains to be mapped. Ensure that the website is accessible (through a webbrowser)
Steps:
1.       Create a cname in your registrar to verify that you own the domain
 To point a custom domain name to your app, Microsoft Azure must verify that you are authorized to do so. First, create a CNAME resource record with your DNS provider that points from either www.yourdomain.com to webappbaredptest.azurewebsites.net, or from awverify.www.yourdomain.com to awverify.<yourwebsite>.azurewebsites.net.
2.       Create a cname form your custom domain to the website
3.       Associate the website FQDN with the custom domain
4.       Access the website via the custom domain name

Troubleshooting tips:
1.       If you try to enter a custom domain before registering the domain (cname) then Azure throws the error
Error: The DNS record for '<yoursubdomain>.<yourdomain>' that points to 'webappbaredptest.azurewebsites.net' could not be located. If you want to configure an A record, you must first create a CNAME record with your DNS provider for 'awverify.myweb.<yourdomain>' that points to 'awverify.webappbaredptest.azurewebsites.net'. First allow the resource record to propagate, and then create the A record.
2.       If you try to enter a custom domain before verifying Azure wont let you enter custom domain
3.       DNS propagation takes sometime. (In reality, in my case took me couple of minutes (~ 1min) to propagate the DNS cname. I configure multiple cname for all kind of use case.)
4.       If you get a message from the website with Error 404 (image below)
Problem:
Solution: Dig/nslookup/ http://digwebinterface.com to ensure that cname has been propagated to the system (might need to flush your ARP records, if you are reusing an existing FQDN)


Tuesday, December 15, 2015

Reset admin VM password on Azure (create a user when you are locked out of the vm) on ARM aka V2.

Pre-requisite: Ensure that the VM is running.
Reset password: You need to create a different user with the same privilege as the original admin user. After you login to the box, change the original admin’s password.

Important points:
1.       Powershell doesn’t work
a.       Approach 1:
 #select vm
$centosvm =
    (Get-AzureRmVM |
     Out-GridView `
        -Title "Select an Azure VM ..." `
        -PassThru)


PS C:\Users\XXX> $centosvm | Set-AzureRmVMOperatingSystem -Credential $cred -Linux -ComputerName $centosvm.Name| Update-AzureRmVM
Update-AzureRmVM : PropertyChangeNotAllowed: Changing property 'osProfile' is not allowed.
OperationID : '4df65df4-eda1-4b2c-88ba-2195fe4fa32d'
At line:1 char:97
+ ... redential $cred -Linux -ComputerName $centosvm.Name| Update-AzureRmVM
+                                                          ~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Update-AzureRmVM], ComputeCloudException
    + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Common.ComputeCloudException,Microsoft.Azure.Commands.Compute.UpdateAzureVMCommand
b.       Approach 2:
PS C:\Users\xxxx> $centosvm = Get-AzureRmVM | Where-Object {$_.name -eq "$vmname"}


PS C:\Users\xxxx> Set-AzureRmVMOperatingSystem -ComputerName centosweb1hdicp -Credential $vmAdminCreds -Linux -VM $centosvm
PS C:\Users\xxxx> $vmconfig = Set-AzureRmVMOperatingSystem -ComputerName centosweb1hdicp -Credential $vmAdminCreds -Linux -VM $centosvm

PS C:\Users\xxxx> Update-AzureRmVM -ResourceGroupName HDInsightHBTC -VM $vmconfig
Update-AzureRmVM : PropertyChangeNotAllowed: Changing property 'osProfile' is not allowed.
OperationID : 'dd785f5b-0bbc-4b0a-bf75-0bf722d4b476'
At line:1 char:1
+ Update-AzureRmVM -ResourceGroupName HDInsightHBTC -VM $vmconfig
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Update-AzureRmVM], ComputeCloudException
    + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Common.ComputeCloudException,Microsoft.Azure.Commands.Compute.UpdateAzureVMCommand

2.       ARM json snippet doesn’t work
        "osProfile": {
                "computerName":"centosweb1hdicp",
          "adminUsername": "MppUsWest2admin",
          "adminPassword": "Xxxx1@3$"
        },         
3.       Cli reset works
azure vm reset-access -n "vmname" -g "RGName"  -u "new user id" -p "new password"
info:    Executing command vm reset-access
info:    Looking up the VM "vmname"
info:    Installing extension "VMAccessForLinux", VM: "vmname"

info:    vm reset-access command OK 

Monday, December 14, 2015

Update Azure VM Size in PowerShell for ARM aka V2

#login to Rm Account
Login-AzureRmAccount

#alternative
#$vmname = "centosweb1hdicp"

#select the subscription id
$subscriptionId =
    (Get-AzureRmSubscription |
     Out-GridView `
        -Title "Select an Azure Subscription ..." `
        -PassThru).SubscriptionId

Select-AzureRmSubscription `
    -SubscriptionId $subscriptionId

#select vm
$centosvm =
    (Get-AzureRmVM |
     Out-GridView `
        -Title "Select an Azure Resource Group ..." `
        -PassThru)

#select the resource group
$rgName = $centosvm.ResourceGroupName
#select the resource group/alternative
#$rgName =
#    (Get-AzureRmResourceGroup |
#     Out-GridView `
#        -Title "Select an Azure Resource Group ..." `
#        -PassThru).ResourceGroupName


#collect VM / alternative
#$centosvm = Get-AzureRmVM | Where-Object {$_.Name -eq "$vmname"}

# current size
$currVMSize=$centosvm.HardwareProfile.VirtualMachineSize
Write-Host "Current Size of the VM: $currVMSize" -BackgroundColor Red -ForegroundColor Cyan

#collect location
$location=(Get-AzureRmResourceGroup -Name $rgName).Location

#collect new size
$newVMSize =
    (Get-AzureRmVMSize -Location $location |
     Out-GridView `
        -Title "Select a VM Size ..." `
        -PassThru).Name

# Stop VM
$centosvm | Stop-AzureRmVm -Force

# Resize VM
$centosvm.HardwareProfile.VirtualMachineSize = $newVMSize
$centosvm | Update-AzureRmVM

# Start VM
$centosvm | Start-AzureRmVm