Showing posts with label VMRole. Show all posts
Showing posts with label VMRole. Show all posts

Thursday, July 14, 2011

FirstLogonCommands to configure your images on deployment when user context is required

This is an old trick and I am sure that there are more elegant ways to handle this.  However, I thought I would share how I am using AutoAdminLogon and FirstLogonCommands in my sysprep unattend answer file to do some heavy lifting for me to drive modifying server settings and application install and configuration.

This came about through using an Azure VM role and being forced to complete as much setup as I can without having to get to the console of the VM.  It is amazing how much you can automate when you get creative.

Let me get one thing out of the way:  Can this be used securely?  Sure, why not, with some proper precautions.  First, encrypt your admin user password; second, don’t use the built-in administrator; third, know that no one can get to the console of the machine (totally headless); fourth, disable the admin account and logout as your last step.

All of the settings that I am referring to are in the “Microsoft-Windows-Shell-Setup” section of your unattend.xml answer file.

First – you have to create and provide a password for the local administrator account.  Note, I am naughty by using the built-in local administrator.

<UserAccounts>
  <AdministratorPassword>
    <Value>IdidntEncryptMineButYouShould</Value>
    <PlainText>true</PlainText>
  </AdministratorPassword>
</UserAccounts>

Then I need to enable AutoAdminLogon

<AutoLogon>
  <Password>
    <Value>IdidntEncryptMineButYouShould</Value>
    <PlainText>true</PlainText>
  </Password>
  <Username>Administrator</Username>
  <LogonCount>1</LogonCount>
  <Enabled>true</Enabled>
</AutoLogon>

Then I define all of my tasks that run when the first user with administrator credentials logs on to the machine:

<FirstLogonCommands>
  <SynchronousCommand wcm:action="add">
    <Order>1</Order>
    <CommandLine>C:\MyFolder\vjRedist64\install.exe /q</CommandLine>
    <Description>Install Visual J# Redistribution</Description>
  </SynchronousCommand>
  <SynchronousCommand wcm:action="add">
    <Order>2</Order>
    <CommandLine>%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command start-sleep 120</CommandLine>
    <Description>Wait for j# install</Description>
  </SynchronousCommand>
  <SynchronousCommand wcm:action="add">
    <Order>3</Order>
    <CommandLine>%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command Import-Module ServerManager; Add-WindowsFeature Web-Server; Add-WindowsFeature Web-Asp-Net; Add-WindowsFeature Web-Windows-Auth; Add-WindowsFeature Web-Metabase</CommandLine>
    <Description>Add ASP.Net and IIS6 Metabase compatibility</Description>
  </SynchronousCommand>
  <SynchronousCommand wcm:action="add">
    <Order>4</Order>
    <CommandLine>%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command set-executionpolicy remotesigned -force >> C:\Users\Public\Documents\setExecution.log</CommandLine>
    <Description>Set the ExecutionPolicy to RemoteSigned for the setup script to run</Description>
  </SynchronousCommand>

</FirstLogonCommands>

Note that there is a sequence number, this way you can simulate a workflow by having having your tasks or scripts execute in a synchronous order.  You just have to watch out for those tasks that run off on their own threads and don’t execute within the context of the command windows where the script executes (that Visual J# installer is a perfect example).  You can manage these spawned processes with PowerShell, but not with a batch command.

Wednesday, April 13, 2011

PowerShell to add SSL binding to Default Web Site

Azure can be a bit perplexing at times – especially for those of us that are not developers.

This is where we all look at the VM Role as a way to get services running in Azure that have really complex set-ups.

At the same time, we can use Azure features to do part of the work for us.

Let me take the following scenario:  You have an application, this application requires specific IIS Role features, then some long application install, and last of all it has an involved set-up.  The scripting is all worked out, but it takes a really long time and there are a couple settings that have to be manually applied.

Your goal; automate as much as absolutely possible.

In Azure, you can add an SSL certificate to your Service – the Azure Service Certificate.

You can then configure Azure to automatically inject this certificate (public + private key) into your VM after it completes mini-setup in the Azure cloud.

Great!  I can use a certificate in my VM Role and the private key is not broken by the fact that I had to generalize the image with sysprep.  Now what?  I need to actually use this certificate.

I have two methods that I have worked out to add this certificate to the IIS default web site.

First of all – I created a self-signed certificate but I named it using my Azure Service DNS.  So the URL for my site is HTTP://MyService.CloudApp.Net 

BlankedCertificate

(Don’t get all funny, you cannot purchase a cloudapp.net SSL certificate as this is Microsoft’s domain – you have to get your own domain, get your certificate and forward the DNS to your Azure Service URL).

Both of these methods I run within a PowerShell script – the different is how I achieve the results.

The common part before either method runs:

I had told Azure to put my certificate in the Local Machine\Personal store in the definition file:

BlankedCertificateStoreLocation

After the VM exits mini-setup and my script runs I need to go find my certificate:

# Get all of the installed Local Computer certificates that can be used
# With Azure this is a Service Certificate that is defined in the configuration for this Role.

$allCerts = Get-ChildItem cert:\localmachine\my

# Find the Certificate that is defined for the domain name
foreach ($cert in $allCerts) {
    if ($cert.SubjectName.Name -match "CloudApp.Net") {
        $cloudCert = $cert
    }
}

Now, I have the certificate, let’s create the binding in IIS

Method 1 – the netsh way using apphost (Server 2008):

## Older Method to achieve the same thing.
$certThumb = $cloudCert.Thumbprint
## Generate a GUID for the SSL binding
$sslGuid = "{" + ([System.Guid]::NewGuid().toString()) + "}"
## Import the SSL certificate
netsh http add sslcert ipport=0.0.0.0:443 certhash=$certThumb appid=$sslGuid
## Create the SSL binding on port 443 for the Default Web Site
& "$env:windir\system32\inetsrv\appcmd.exe" set config -section:system.applicationHost/sites /+"[name='Default Web Site'].bindings.[protocol='https',bindingInformation='*:443:']" /commit:apphost

Method 2 – the PowerShell IIS module way (Server 2008 R2):

Import-Module WebAdministration

New-WebBinding -Name "Default Web Site" -IP "*" -Port 443 -Protocol https

$certObj = Get-Item $cloudCert.PSPath
New-Item IIS:SslBindings\0.0.0.0!443 -value $certObj

# Remove the HTTP binding
Remove-WebBinding -Name “Default Web Site” -BindingInformation *:80:

The new PowerShell 2.0 WebAdministration module way is much easier to deal with – but, it is PowerShell v2 – that is Server 2008 R2 and newer only.

Monday, April 4, 2011

Sneaking around the lack of name resolution in Azure

This is one of those things that you will most likely run into if you try to run a traditional enterprise application in Azure – there is no name resolution.

Over many years enterprise applications have gone through the evolution of moving from IP addresses to relying on WINS to now DNS.  This move to using machine names provides great flexibility to server administrators to replace boxes at will, simply by editing a DNS entry or renaming the new server to the old server.  No need to update the configuration of the application.

Well, now we have Azure.  And although it is not Infrastructure as a Service, if you use a VM Role for some component of a historic enterprise application you do expect familiar features.

One way to handle this is to use Azure Connect.  Connect provides name resolution for the machine that participate in the virtual network.  However you only get IPv6 endpoint addresses back.  And this is useful for machine to machine communication but not for much else.

Another hitch is that in Azure machine names change.  Since all of the images are prepared with sysprep they come out of sysprep with new machine names (each provisioned instance needs to be unique, right?).  All that I know is that my worker tier machine will get new names if something happens and an instance gets replaced.  Or is someone stops my service and then starts it again, or reimages one of my instances.  With this going on, name resolution actually doesn’t help me much.

Well, I had a situation where I absolutely needed name resolution.  And that is one piece of information that I cannot query through the Azure Service Runtime.  So I have a homegrown solution – I edit the HOSTS file on each server.

In my example I only need to know the machine name of all of the instances of a particular role – so I query that to get the IP addresses.  I then turn around and use WinRM to query those instances and get the DNSHostName back from them.

I am using WinRM and not WMI because it is a single, incoming, well known port.  So I only have to define one endpoint at the Role level.  Through a bit of searching I discovered that WMI is not so fixed and I didn’t want to make it so.

Here is how it goes.  Warning:  I am not securing any of this.  I use HTTP for WinRM, and I reduce the PowerShell script execution security.  If you need to be secure and tight, then you need to tighten that up.

In my sysprep unattend.xml I first change the PowerShell execution policy.  I then run a script to set the WinRM service and client.  I then have a wait to give each instance a change to set the WinRM settings.  Then I query the Azure Service Runtime for the role instances and their IP addresses, then through WinRM I touch each server and get its DNSHostName.  Last, I append the local HOSTS file adding this information.  This executes on each server – they are all clones of each other after all.

Don’t forget to add the Internal Endpoint of 5985 to the Role definition in your service.  If you don’t, none of this matters.  If you secure this, use the endpoint of 5986.

Setting WinRM on each client (unsecurely, be aware of that):

<#
.SYNOPSIS
    A script to set the WinRM firewall rules and to configure the service and the
    client.  This enables unsecured communication.
.DESCRIPTION
    This script is designed to simply set up WinRM for remote unsecured communication.
    QuickConfig opens the firewall, the service settings allow remote connections,
    the client setting enables unsecured calling from the client to the remote service.
.LEGAL
    SCRIPT PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF ANY KIND, INCLUDING BUT NOT LIMITED TO
    MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.  ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF THE AUTHOR,
    SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH DAMAGE.  IF YOUR STATE DOES NOT PERMIT THE COMPLETE
    LIMITATION OF LIABILITY, THEN DELETE THIS FILE SINCE YOU ARE NOW PROHIBITED TO HAVE IT.  TEST ON NON-PRODUCTION SERVERS.
.AUTHOR
    Brian Ehlert, Citrix Labs, Redmond, WA, USA
.REFERENCES
    Thank you TechNet. For examples. And a random forum post for the single quote fix.
#>

winrm quickconfig -quiet
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/client '@{AllowUnencrypted="true"}'
winrm set winrm/config/client
'@{TrustedHosts="*"}'

Now, to enumerate the information from the service runtime and append the HOSTS file:

<#
.SYNOPSIS
    A script to set the HOSTS file for Azure VMs to allow proper name resolution.
.DESCRIPTION
    In an Azure environment name resolution might not be available or might resolve IPv6 addresses.
    The Azure RuntimeService is queried to discover the IP addresses of other role members.  And then
    WinRM is used to query the DNSHostName of the other servers.
    The results are then appended to the HOSTS file.
.LEGAL
    SCRIPT PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF ANY KIND, INCLUDING BUT NOT LIMITED TO
    MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.  ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF THE AUTHOR,
    SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH DAMAGE.  IF YOUR STATE DOES NOT PERMIT THE COMPLETE
    LIMITATION OF LIABILITY, THEN DELETE THIS FILE SINCE YOU ARE NOW PROHIBITED TO HAVE IT.  TEST ON NON-PRODUCTION SERVERS.
.AUTHOR
    Brian Ehlert, Citrix Labs, Redmond, WA, USA
.REFERENCES
    Thank you to Jason Fossen (
http://blogs.sans.org/windows-security/). And to TechNet. For examples.
#>

# this is a local administrator and user name that is established in the VM
# Azure RDP access will automatically create / inject a user account that is defined
# Otherwise you need to establish a user account using your unattend.xml
$userName = "administrator"
$password = "Citrix`$2"
# Note:  I am using a plain text password.

# Add the Service Runtime snap-in to the standard Windows PowerShell command shell.
add-pssnapin microsoft.windowsazure.serviceruntime

# Take the VM Instance offline with Azure
Set-RoleInstanceStatus -Busy

$HostsFilePath = "$env:systemroot\system32\drivers\etc\hosts"

# Test the Hosts file by adding LocalHost entries
"127.0.0.1 localhost"  | add-content $HostsFilePath -force
"::1 localhost"  | add-content $HostsFilePath -force
if (-not $?) { "Error writing to hosts file!" ; return }

# Discover the other members of the Role
# It is not possible to have a server discover the Role that it is; as is the question "what am I" - it must be hardcoded.
# Enumerate all of the instances of the role named MyRole
$roleMem = Get-RoleInstance -Role MyRole

# Discover the endpoint IP the service is not necessary as it is the same for all
foreach ($roleIn in $roleMem) {

    # Find the WinRM port number
    foreach ($roleInEnd in $roleIn.InstanceEndpoints.Values){
        if ($roleInEnd.IPEndpoint.Port.Equals(5985)){
            #Get the IP of the endpoint
            $endIp = $roleInEnd.IPEndpoint.Address.ToString()
        }
        else{}
    }
   
    # winrm get wmi/root/cimv2/Win32_ComputerSystem (I simply find is easier to treat this as XML)
    $remoteServer = [xml](winrm enum wmi/root/cimv2/Win32_ComputerSystem -r:$endIp -encoding:utf-8 -a:basic -u:$userName -p:$password -format:pretty)
   
    # Add the entry to the HOSTS file
    $endIp + "`t" + $remoteServer.Results.Win32_ComputerSystem.DNSHostName
    $endIp + "`t " + $remoteServer.Results.Win32_ComputerSystem.DNSHostName |  add-content $HostsFilePath -force
   
}

That is it.  I use two scripts with a wait sequence in between (I use my random sleep script a couple articles back) since each machine is independent and must be able to call out to the others – the timing for WinRM happening early is important.

Friday, April 1, 2011

Getting Role Instance endpoint information from within an Azure VM

In a previous post I discussed the concepts of VM to VM communication in Azure.  The basics of how it works and where the knobs are to enable it.

Here is a little different focus.  It is the scenario that the endpoints have been defined, but your setup script that is installing or configuring your application needs to discover other roles and information about them because it needs to talk to them.

This is IPv4 traffic.  Most any application should know how to use this. 

I mentioned previously that name resolution is not available.  The other caveat is that I am not using Azure Connect (the Azure Virtual Network feature).  Connect gives name resolution, but it only gives me the IPv6 endpoint of the Connect VPN tunnel it does not give me the IP actual network IP addresses that my application wants.

So, PowerShell to the rescue.  To get you started I have this little PowerShell script that walks through my service, all Roles, and documents the endpoints that are enabled.

I run this on Instance A and I know where the open ports are configured on instance B.  I also use this to document my environment from within my environment by directing the output to a text file.

By the way, this is made possible by the Azure Service Runtime.  This is installed in VM Role VMs when the Windows Azure Integration Components are installed.  The hitch is that the VM must be in Azure for it to work, and you must be executing as Administrator.

<#
.SYNOPSIS
    A script to query the Azure Service Runtime and dump the endpoint configuration
    of all roles to a TXT file.
.DESCRIPTION
    This script is designed as a very simple troubleshooting tool for your VMs in Azure.
    It performs the very simple task of working through all Roles and Instances and
    writing the EndPoint configurations to a TXT file.
    This way when you are troubleshooting issues you have a quick document in the VM
    that you can reference to see what Internal EndPoints have been opened to
    facilitate VM to VM communication.
.LEGAL
    SCRIPT PROVIDED "AS IS" WITH NO WARRANTIES OR GUARANTEES OF ANY KIND, INCLUDING BUT NOT LIMITED TO
    MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.  ALL RISKS OF DAMAGE REMAINS WITH THE USER, EVEN IF THE AUTHOR,
    SUPPLIER OR DISTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF ANY SUCH DAMAGE.  IF YOUR STATE DOES NOT PERMIT THE COMPLETE
    LIMITATION OF LIABILITY, THEN DELETE THIS FILE SINCE YOU ARE NOW PROHIBITED TO HAVE IT.  TEST ON NON-PRODUCTION SERVERS.
.AUTHOR
    Brian Ehlert, Citrix Labs, Redmond, WA, USA
.REFERENCES
    Thank you TechNet. For examples.
#>

# declare the DumpInstance Function
function DumpInstance {
    param ($roleMem)
   
    foreach ($roleIn in $roleMem) {
    $i = ($roleIn.InstanceEndpoints.Count -  1)
    $roleIn.Role.Name + ", " + $roleIn.Id

    do {
    $keyName = $roleIn.InstanceEndpoints.Keys[$i]
    $endProtocol = $roleIn.InstanceEndpoints.Values[$i].Protocol
    $endPort = $roleIn.InstanceEndpoints.Values[$i].IPEndPoint.Port
    $endIp = $roleIn.InstanceEndpoints.Values[$i].IPEndPoint.Address.ToString()
    $endFamily = $roleIn.InstanceEndpoints.Values[$i].IPEndPoint.AddressFamily
   
    $endIp + ", " + $endPort + ", " + $keyName + ", " + $endProtocol + ", " + $endFamily
    --$i
    }
    until ($i -lt 0)
    ""
    }
}

# Add the Service Runtime snap-in to the standard Windows PowerShell command shell.
add-pssnapin microsoft.windowsazure.serviceruntime

# Get all Roles
$allRoles = Get-RoleInstance

foreach ($roleMem in $allRoles) {
    DumpInstance $roleMem
}

Tuesday, March 22, 2011

Azure VM Role and Application Setup

I have never considered myself an unattended setup type of person.  Mainly because for most applications the process has always been too painful or the potential for danger is too high.

Needless to say, I have been spending a great deal of time with Windows Azure and the VM Role and a few applications.

What have I learned from this?

  • Not all command line utilities can be invoked properly using ‘&’ or ‘cmd /c’ from PowerShell.
    • I have a couple applications that just don’t execute into a command windows from powershell.  I have worked around this by determining my variables and then writing a .CMD file using Out-File.
    • I can then use ‘&’ to run the .CMD file and it works perfect.
  • Not all unattended installers work as documented.
    • ‘nuf said
  • FirstLogonCommands in the unattend.xml file is highly useful.
    • You can execute PowerShell, you can execute individual commands, you can install server roles and features, lots of stuff.
  • Software in Azure doesn’t always debug the same as on Hyper-V
    • At the very least network communication is different.
    • The Azure VM runtime container is different and is managed differently, to say the least.

I will be posting some PowerShell snippets that I have found useful and we will undo an Unattend.xml file as well.

All in due time.

Thursday, December 16, 2010

Pale Blue Cloud that is Azure part 1 VMRole

Lately I have had my head in the Microsoft Cloud – Azure to be specific.

It is pale blue and pretty.  It scales, it is definitely intended for developers.

I know there has been lots of speculation about Azure and the VM Role and the ability of Infrastructure as a Service.  I can tell you that the VM Role is not intended for a person to run their entire datacenter in the Azure Public Cloud. 

On the other side, once you work things out – the VM Role is actually pretty cool but not always necessary.  In fact, unless you have a total lack of creativity you really don’t need the VM Role for doing much.  The Web Role and the Worker Roles have a great deal of flexibility. 

Now, this sounds like marketing speak as it comes across as sounding really easy – it isn’t – but I will tell you that if you can write code and understand installation and deployment that you can do most of what you might want to with Worker and Web roles.  There are lots of options available – and they are very traditional deployment options – but you have to structure them in code; so you must really understand your application and your application dependencies.

This is really where the VM Role comes into play.  It is designed for the scenario where you have a legacy application that you want to get into the cloud but it is too costly or not feasible to re-write it specifically for Azure.  Now, that being said – Azure has some really cool features that developers can use to make really big and really resilient and really grand applications.  But the reality is that software actually lives for a long time.  And not everyone upgrades to the latest and greatest version.  And, it takes time to re-write an application – it can take over a year for an enterprise application to go through a revision – let alone a major re-write for a new platform.

I plan on going into some of the features of Azure that will be of interest to ITPros – as most likely at some point in the future you will come into contact with an Azure application – Azure is not the exclusive playground of developers, they might think it is, but it really isn’t.

I hope that at some time in the future I can share the interesting things that I am playing with.

In the mean time – if you want an easy Getting Started with the VM Role guide – here is it:

http://msdn.microsoft.com/en-us/WAZPlatformTrainingCourse_VMRoleLab

There is no reason for me to write information a second time that already exists (and is pretty decent).