Skip to content

Windows Azure PowerShell Developer Guide

ogail edited this page Mar 27, 2013 · 33 revisions

##Get it! A normal git geek can clone the repo.

Configuring Visual Studio

Development Environment

  • You need to have this environment variable setup EnableNuGetPackageRestore=true
  • Below is the Visual Studio configuration

Prerequisites

Running unit tests

  • Open VS 2012 in administrator mode and run all tests except those under Management.ScenarioTest

Running scenario tests

  • In a Windows Azure storage, create a new container called testcredentials-production
  • upload these three files there:
    • default.publishsettings: that's publish settings file used in the tests
    • environment.yml: these are environment variables you want to inject (check yml file format)
    • variables.yml: these are PowerShell variables you want to inject
  • On your machine set these environment variables:
    • AZURE_TEST_ENVIRONMENT=production
    • AZURE_STORAGE_ACCOUNT=<storage account name>
    • AZURE_STORAGE_ACCESS_KEY=<storage account key>
  • Run scenario tests by executing this cmd: msbuild build.proj /t:Scenariotest

Enable running Windows PowerShell when debugging

  • Choose any project and set it as startup project.
  • Open this project properties.
  • Go to Debug tab.
  • Under Start Action pick Start external program and type Windows PowerShell directory (i.e. C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe)
  • Make sure to open VS cmdline and run this command from the project root directory: msbuild build.proj /t:BuildDebug

Importing modules automatically when start debugging

  • Assuming the Debug page is opened, go to Start Options
  • In Command line arguments type this command
-NoExit -Command "Import-Module <Modules to import>"
  • For example this command loads module manifest:
-NoExit -Command "Import-Module .\Azure.psd1"

It's recommended to enable verbose as it's enabled by default when using Windows Azure PowerShell shortcut

-NoExit -Command "$VerbosePreference="Continue";Import-Module .\Azure.psd1"

Walkthrough: Developing a new cmdlet LOTR style

The story

Based on the Lord of the Rings novel, Sauron the creator of rings of power decided to move to the cloud. So he asked one of his slaves to add these cmdletts to Windows Azure PowerShell:

Get-AzureRingOfPower

Add-AzureRingOfPower

Remove-AzureRingOfPower

The REST backbone (ServiceManagement.csproj)

This project holds main parts of doing REST calls with Windows Azure.

Add Operation Contracts (Contract)

  • Under Contract folder in ServiceManagement.csproj add new file called RingsOfPower.cs
  • In this file define and implement the REST APIs Sauron asked for.

Add Data Contract (ResourceModel)

  • Under ResourceModel folder create new file called RingsOfPower.cs
  • Add all data contracts (actual classes) that the service will return.

Windows Azure PowerShell cmdlets backbone (Management.csproj)

Common pieces of code to deal with PowerShell, it contains all base cmdlets that Sauron slave need to extend to add their own cmdlets.

Extending CmdletBase.cs

  • If you have any cmdlet that will not do REST work then most probably it should extend CmdletBase

Extending CloudBaseCmdlet.cs

  • This is the base cmdlet for all cloud based cmdlets. Mainly you'll extend it with type of your channel.

Rings of Power Project (Management.RingsOfPower.csproj)

The rings of power management project which will contain the actual cmdlets that users are going to use.

Microsoft.WindowsAzure.Management.RingsOfPower.dll-Help.xml It's essential to have XML help file, check Microsoft.WindowsAzure.Management.CloudService.dll-Help.xml

MSSharedLibKey.snk Adding this public key to your project is essential for the signing process on the CI server. The key is found here

AssemblyInfo.cs Align this file with an existing [AssemblyInfo.cs](https://github.com/WindowsAzure/azure-sdk-tools/blob/master/WindowsAzurePowershell/src/Management.CloudService/Properties/AssemblyInfo.cs)

Project Cofiguration Make sure to add ReleaseSigned configuration to your project and make it the default configuration. Check sample of ReleaseSigned configuration here

Microsoft.WindowsAzure.Management.RingsOfPower.format.ps1xml (Optional) The format file is optionally added when the cmdlet output will be customized. Check this sample for more info.

Implementing RingOfPowerCmdletBase (Optional) If there are any common code, authentication process, etc.. all that should be in this base class.

Cmdlet development guidelines Any cmdlet added should make sure from the following guidelines:

  • The cmdlet verb portion in the name uses Approved Verbs for Windows PowerShell Commands
  • The cmdlet name starts with Azure as prefix.
  • The cmdlet specifies an OutputType property.
  • One object is emitted to the output pipeline.
  • Any information message should be written to verbose stream.
  • The debug stream should at least have REST call (request/response) information.
  • Any warnings should be written to the warning stream.
  • If the cmdlet will emit an enumerable collection make sure to use WriteObject with true for enumerable parameter.
  • If the cmdlet does any operation that will result is a loss of data and non-recoverable then this operation should be surrounded with ShouldProcess method and the cmdlet class should have the attribute SupportsShouldProcess
  • Any cmdlet that uses ShouldProcess should provide Force parameter to enable automation.
  • Most of Remove/Set/Start/Stop/... cmdlets does not return any value and throwing an error indicates failure. If that's the case add PassThru parameter which forces the cmdlet to return something if passed.

Rings of Power Test Project (Management.RingsOfPower.Test.csproj)

The test project for the new added cmdlets

MSSharedLibKey.snk Adding this is will eliminate a warning in the build process.

Project Cofiguration Make sure to have ReleaseSigned config, check this sample

Implementing SimpleRingsOfPowerManagement.cs (Mock Channel) This mock channel will act as replacement for the real channel used in the cmdlets. Check SimpleServiceManagement as an example.

Inject the cmdlets into Windows Azure PowerShell installation

Adding to Windows Azure PowerShell Azure.psd1

  • Update FormatsToProcess entry to add format file.
  • Update NestedModules to include cmdlets DLL.
  • Updaye FileList to include the help xml file.

Adding to MSI setup project

  • Using build.proj in the project root folder, execute a target called BuildRelease
  • Make sure to have wix tools in the PATH env variable and then execute getenrate.exe. This will add the all the output of new project into the MSI installation process.

Misc

Understanding piping

In Powershell cmdlets pipe objects between one another. Cmdlets should not return text, they should return objects.

For example, if you use our Azure cmdlets, you can do the following

Get-AzureWebsite | Remove-AzureWebsite

Get-AzureWebsite will return a set of Website objects and then invoke Remove-AzureWebsite passing each object one by one.

Piping in

As long as the property names of the objects getting returned from Get-AzureWebsite match those of Remove-AzureWebsite, and Remove-AzureWebsite's properties are properly annotated with [Parameter(ValueFromPipeline)], then piping between them works.

In this case, the RemoveAzureWebsite and GetAzureWebsite classes both inherit from WebsitesBaseCmdlet. This base class includes a "Name" parameter which is properly annotated as is shown below:

[Parameter(Position = 0, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The web site name.")]
[ValidateNotNullOrEmpty]
public string Name
{
   get;
   set;
}

ValueFromPipelineByPropertyName=true instructs Powershell to try to match any objects coming in from the pipeline by the property name and type. If it finds a match then the value will be plugged in. Multiple properties can be annotated in this way.

Piping out

To pipe out, you use the cmdlet's WriteObject method. This will then write the objects out to the pipeline. Below is an example of how this is done in the GetAzureWebsite class.

protected virtual void WriteWebsites(IEnumerable<Site> websites)
{
    WriteObject(websites, true);
}

For more information on piping, see the following links:

We'd also recommend looking at our existing cmdlets such as the ones mentioned above.