Automate Shutting Down Azure VMs

As I am developing, I create and use quite a few Microsoft Azure services and virtual machines. If I forget to shut down the services at the end of the day, it will quickly burn through my MSDN Azure credits leaving me dead in the water until the end of the month.

This happened to me last month and I vowed never again, so I dove into Azure Automation Accounts to automatically shut down services at the end of the day. The setup wasn’t intuitive, but it can be really useful for cleaning up, or any scheduled maintainance of your account. Just make sure you don’t end up taking down production services by mistake!

Create an Azure Active Directory Account

If like me you use multi-factor authentication for your Azure account, you cannot use your account to run automation scripts. Instead, you will need to create an Azure Active Directory account to run the automation scripts. If you are not using multi-factor authentication, you should consider switching, but if not, you can skip this and use your own account when setting up the credentials in the automation account below.

You need to log into the Azure Portal using the account of the Service Administrator to add new users. If this is your MSDN Subscription, you are likely the Service Administrator, but if it is a company account, you can find the Service Administrator by logging in with your account, then going to Subscriptions. Click on the subscription you want to administer, then All Settings | Properties.

Subscription Admin

The bottom text box in the Properties blade is the Service Admin, log in with that account and click on Active Directory. This currently launches you into the classic portal.

On the left, click on the Directory for the subscription, then on the USERS tab. If you do not see the directory listed, you are not the admin for the directory. Now click on Add User at the bottom.

Azure Active Directory

Select “New user in your organization” and enter a username for your automation user.

New AD User

Click next and fill in the user information. The role should be User and don’t enable multi-factor authentication.

New AD User Step 2

Click next, then Create to create the user and generate a temporary password for the user. Write down the username and the temporary password.

Since this is a temporary password, you must change it. Do this by logging out of Azure and logging back in with the newly created automation account. It will prompt you to change the password, do so, then log out and back in with your account.

Allow the Automation User to Manage your Subscription

Log back into the Classic Azure Portal with your user, click Settings at the bottom left, then Administrators.

Subscription Admins

Enter the email for the user you just created and select the subscription they will manage.

CoAdministrator

Create an Automation Account

Back in the Azure Portal using your MSDN Subscription account, click on Automation Accounts. On the Automation Accounts blade, click on Add.

Create Automation Account

Give the new account a recognizable name. You will probably want to assign it to the same resource group as the services you are managing and select the same region. The default account options creates a tutorial runbook, leave it on, the code is useful to crib off of. When you are ready, click Create. After it is deployed, you will have a new automation account. Drill into it.

Automation Account

Add Credentials to the Account

Automation scripts need credentials to run under, so the first step is to add them. Click on the Assets tile, then the Credentials tile then Add a Credential.

New Automation Credentials

If you name the credentials DefaultAzureCredential then you you do not need to change the example automation scripts. If you prefer to use another name, you will need to change it in the automation scripts. For the username and password, use the automation user you created at the start of this post. If you skipped that and don’t use multi-factor authentication I believe you can use your MSDN account.

Testing Your Setup

Close back out to the blade for your automation account and click on Runbooks. You should have a single Get-AzureVMTutorial runbook that was created when you created the account. We’ll use this to test that you have the credentials setup correctly. Click on the runbook to open its blade. If you used DefaultAzureCredential for the credentials name, you can just press Start. If you used a different name, edit the script and change the authentication account where specified.

A job blade will open and the job will cycle through Queued, Starting, Running and if all goes well Completed. If it fails for some reason, then the an exception will be shown at the bottom of the blade and the job will become Suspended. If it does this, stop it. If it succeeded, click the output tile to see the list of classic VMs that it found in your subscription.

Test Run

Time to write some code

If you peeked at the tutorial runbook code, you will see that it is just a PowerShell script. Time to create our own. I like to test what I am writing in the PowerShell ISE on my machine, but I will leave the setup of that to another blog post. For now, let’s create a simple runbook to shutdown virtual machines.

Back on the blade for your automation account, click Runbooks and Add a runbook.

Add Runbook - Microsoft Azure

Create a new runbook called Stop-AzureVirtualMachines of type PowerShell Workflow and give it a meaningful description and click Create.

Runbook - Microsoft Azure

A new Workflow Runbook will open in the editor, copy the following code in;

<#
  .DESCRIPTION
    Stops all Azure Virtual Machines in an account. To stop classic VMs, change Get-AzureRmVM and Stop-AzureRmVM to
    Get-AzureVM and Stop-AzureVM

  .NOTES
    AUTHOR: Rob Prouse
    LASTEDIT: Feb 08, 2016
#>
workflow Stop-AzureVirtualMachines
{
  #The name of the Automation Credential Asset this runbook will use to authenticate to Azure.
  $CredentialAssetName = 'DefaultAzureCredential'

  #Get the credential with the above name from the Automation Asset store
  $Cred = Get-AutomationPSCredential -Name $CredentialAssetName
  if(!$Cred) {
    Throw "Could not find an Automation Credential Asset named '${CredentialAssetName}'. Make sure you have created one in this Automation Account."
  }

  #Connect to your Azure Account
  $Account = Add-AzureRmAccount -Credential $Cred
  if(!$Account) {
    Throw "Could not authenticate to Azure using the credential asset '${CredentialAssetName}'. Make sure the user name and password are correct."
  }

  #TODO (optional): pick the right subscription to use. Without this line, the default subscription for your Azure Account will be used.
  #Select-AzureRmSubscription -SubscriptionName "TODO: your Azure subscription name here"
  
  #Get all the VMs you have in your Azure subscription
  $VMs = Get-AzureRmVM

  # Stop each of the started VMs
  foreach ($VM in $VMs)
  {      
      Write-Output ("Stoping " + $VM.Name)
      Stop-AzureRmVM -Name $VM.Name -Id $VM.Id -Force -ErrorAction Continue
  }
}

If you didn’t use DefaultAzureCredential when you created the credentials, make sure you change it in the script. Also, if you have more than one subscription, uncomment the Select-AzureRmSubscription line. Notice that this script shuts down the new Azure Virtual Machines using the PowerShell commands with Rm in them like Get-AzureRmVM. If you want to shut down classic VMs or other services, modify accordingly.

You can now test your script by clicking the Test pane button and starting your script. If you see any errors, make the necessary edits to get it running in your account. Once it is running, exit the test blade and click Publish.

After you publish the script, the edit blade should close. Back in the runbook blade, double check that the status is Published.

2016-02-08 15_37_25-Stop-AzureVirtualMachines - Microsoft Azure

Scheduling the Job

Last step, promise. In the blade for the runbook you just created, click the Schedules tile, Add a schedule, Schedule and Create a new schedule. Give it a name like Every Evening at 6pm, a description, a start date and time in the future and a daily recurrence. You can now exit out of the blades, you are done.

New Schedule

Monitoring your Jobs

Optionally, you may want to monitor the status of your jobs to make sure they don’t start failing. Do do this, go to the blade for your automation account. There is a Job Statistics tile on that blade. Right click on it and pin it to your dashboard for easy viewing…

Job Statistics

Read More

Using Ninject for Prism for Xamarin.Forms

I started a Xamarin.Forms mobile project recently and decided to use the Prism for Xamarin.Forms framework. I followed the directions for getting started with Prism for Xamarin.Forms and was up and running in no time.

My only issue was that the only IoC container that was supported was Unity. I won’t debate the merits of various IoC containers, but I prefer Ninject, so I submitted a large pull request adding Ninject support to Prism for Xamarin.Forms which is now available on NuGet as Ninject for Prism.

Brian Lagunas’s getting started with Prism for Xamarin.Forms and Prism for Xamarin.Forms 6.2.0 Preview is fairly complete, so I will only outline getting up and running using Ninject instead of Unity.

Getting Started

First, download and install the Prism Template Pack extension for Visual Studio. It contains a project template for a Xamarin.Forms Prism Unity App which is a good start.

In Visual Studio, add a new Prism Unity App (Forms) project. There isn’t currently a Ninject template, so we will modify the Unity version.

New Prism Project

This is a multi-project template that will create a shared library and three platform specific projects for Android, iOS and Windows Phone 8.0.

Prism Ninject Demo Solution

Now we will switch out Unity for Ninject. Right-click on the solution and Manage NuGet Packages for Solution… and uninstall the Prism.Unity, Unity and CommonServiceLocator NuGet packages from all projects in that order.

Next, search for and install the Prism.Ninject NuGet package to all solutions. As of today, the package is prerelease, so make sure you select the Include prereleases checkbox and install at least version 6.2.0-pre2.

The code in the portable project needs to be switched from using Unity to Ninject. Open App.xaml and switch the two instances of Prism.Unity to Prism.Ninject.

<?xml version="1.0" encoding="utf-8" ?>
<prism:PrismApplication xmlns="http://xamarin.com/schemas/2014/forms"
                        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                        xmlns:prism="clr-namespace:Prism.Ninject;assembly=Prism.Ninject.Forms"
                        x:Class="PrismNinjectDemo.App">

</prism:PrismApplication>

Then open App.xaml.cs, switch using Prism.Unity; to using Prism.Ninject; and change all instances of Container to Kernel. You can use the Kernel property on the App class as you would in any application using Ninject. Add your bindings in the RegisterTypes method and as an added bonus, the Ninject Kernel will resolve interfaces registered with the Xamarin DependencyService so you can use existing Xamarin plugins and resolve them in a consistent way.

using Prism.Ninject;
using PrismNinjectDemo.Views;

namespace PrismNinjectDemo
{
    public partial class App : PrismApplication
    {
        public App()
        {
            InitializeComponent();
        }

        protected override void OnInitialized()
        {
            NavigationService.Navigate("MainNavigationPage/ViewA?message=Hello%20From%20Xamarin.Forms");
        }

        protected override void RegisterTypes()
        {
            Kernel.RegisterTypeForNavigation<MainNavigationPage>();
            Kernel.RegisterTypeForNavigation<ViewA>();
            Kernel.RegisterTypeForNavigation<ViewB>();
        }
    }
}

From here, follow the instructions in Getting started with Prism for Xamarin.Forms and Prism for Xamarin.Forms 6.2.0 Preview to learn more about using Prism with Xamarin.Forms.

A demo project using Prism for Ninject for Xamarin.Forms is available on GitHub.

Read More

CoderCamp Hamilton

The new CoderCamp Hamilton website went live tonight hopefully signaling a new phase for a great tech get-together in Hamilton.

CoderCamp is a local, monthly mini-conference where local software developers get together to share their experiences with new tools, technologies and techniques. It is a chance to get together with like minded people in a casual setting and talk about our tech passions. It is also a chance to meet other like-minded people in Hamilton and help build a strong tech community.

We meet every month and try to have several presentations lined up, but we are always looking for new people to share their passions with the group. If you would like to give a short, informal presentation to the group, please contact the organizers at codercamphamilton@gmail.com.

Read More

Testing Xamarin Projects using NUnit 3

NUnit Tests on AndroidWhen testing Xamarin using NUnit 3, you have two choices.

  1. A Portable Library that you reference from the test runner for each platform, or
  2. A Shared Project with your tests referenced from the platform specific test runners.

I prefer the Shared Project approach because it also allows you to run your tests from within Visual Studio by also creating a .NET 4.5.x test project. As of NUnit 3.0.1, you cannot run tests that use the portable version of the NUnit Framework from the console or within Visual Studio, so the .NET 4.5.x test project gets around that limitation.

This approach assumes that you are using and testing a portable Xamarin project. If not and you are using a shared project, everything will be the same except you will not be able to test in Visual Studio using a .NET 4.5.x test project because you cannot reference the platform specific assemblies.

To get started, you should install the NUnit Templates extension for Visual Studio. It will add project templates for the various Xamarin platforms.

The first step is adding a Shared Project to your solution that will contain your tests. Next, add a NUnit 3 Unit Test Project from under the Visual C# | Test node. This project will be .NET 4.5.x based and allow you to run tests from within Visual Studio or on the console. Add your shared project to this project as a shared reference. Depending on what you are testing, you will likely have to add references to the NuGet packages for Xamarin and any plugins you are using.

As you are testing with the .NET 4.5 project, you will eventually try to test things that requires Xamarin or one of the plugins to be initialized on the platform which won’t work under .NET 4.5. This is where you will start needing platform specific test runners.

To add the platform specific test projects, Add | New Project.. and add a NUnit 3 Test Project (Android) from under the Visual C# | Cross-Platform | Test node. Repeat for the platforms that you support.

2015-12-20 15_05_02-Add New Project

Test Projects

You will need to add references to your shared test project, your portable project that you want to test and if you have platform specific code you want to test, your platform specific projects. You may be using a newer version of Xamarin.Forms and/or require additional NuGet packages, so Manage NuGet Packages for Solution and install/upgrade packages for your test projects as appropriate.

With the platform specific runners, you can add needed platform initialization code to the runners just like any other Xamarin.Forms app. You can also include platform specific tests either by adding them to the runners themselves, or by using the various defines for conditional compilation like __MOBILE__ or __ANDROID__.

#if __MOBILE__
    // This test causes the view to be bound to the viewmodel which doesn't work on the
    // desktop because Xamarin.Forms.Init() must be called
    [Test(TestOf = typeof(IssueViewModel))]
    async public Task ListAttachmentsCommandNavigatesToAttachments()
    {
        await ViewModel.OnAppearing();
        Assert.That(ViewModel.ListAttachments != null);
        await ViewModel.ListAttachmentsFunc();
        var navigation = Navigation as MockNavigation;
        Assert.That(navigation.PushAsyncHappend);
    }
#endif

Read More