Microsoft Campus Days 2014 Azure RemoteApp slides available on SlideShare

I recently gave a session at the Microsoft Campus Days 2014 Event in Copenhagen, Denmark about the new Microsoft Azure RemoteApp service. Thank you to everyone that came to the session. The slide are now available on SlideShare:

http://www.slideshare.net/MorganSimonsen/building-azure-remoteapp-microsoft-campus-days-2014

Morgan

Manage Azure Active Directory without an Azure subscription (sort of)

Introduction to Azure Active Directory

Azure Active Directory is Microsoft’s cloud identity platform and the identity provider for all the services in the Microsoft Cloud ecosystem. It is a multi tenant global identity platform, available in all the Azure regions. If you have Office 365, Windows Intune or Microsoft Azure; you also have Azure Active Directory. To call it Azure Active Directory can sometimes be a little misleading because although it is part of the Azure platform, it exists outside the other services we generally associate with Azure, like Infrastructure-as-a-Service or Platform-as-a-Service. Even though Azure Active Directory shares its name with the Windows Server Active Directory Domain Services role we find in Windows Server, Azure AD offers a lot more than its earthbound namesake. Azure AD is not just a directory that stores information about users and groups, and authenticates them, it also has identity lifecycle management, advanced reporting, multi-factor authentication and support for OAuth, OpenID Connect and WS-* protocols. The complete feature set is too long to list here, and outside the scope of this post anyway. Azure AD is backed by a REST API called the Graph API.

Azure AD comes in three flavors; Free, Basic and Premium. The base offering, Free, can be used by anyone for almost anything. You could build your own webapp in AWS and use Azure AD as the identity provider for example. Like I mentioned, if you already have Office 365, you also have Azure AD. The Office 365 portal offers one view into Azure AD via the admin portal (portal.office.com).

image

Another way to interact with Azure AD is via PowerShell. The Azure AD PowerShell module has over 70 cmdlets:

image

As you can see from the list above, it is Azure AD that handles federation and directory integration with your existing on-premises directories, not Office 365.

Management of Azure AD

As we’ve seen there are several views into Azure AD; PowerShell, Office 365 or Windows Intune portals. But to manage the full set of available features in Azure AD we need to use the Azure Management Portal (manage.windowsazure.com).

image

If you have an Azure subscription you either got an Azure AD tenant when you signed up, you created one in the Azure portal afterwards or you associated your existing Azure AD tenant with your Azure subscription. Either way that tenant then becomes visible in the Azure portal like in the screenshot above. From here you can manage all the base functionality of Azure AD like directory integration, domain verification, multi-factor authentication, reporting etc. You can also add users form other Azure AD tenants (provided you have access to the tenant in question) and add Microsoft Accounts (MSA).

Azure AD vs. Azure

There are several ways to get Azure AD without having an Azure subscription. Maybe you signed up for an Office 365 or Windows Intune trial, or something else. However you got an Azure AD tenant you now want to manage it from the Azure portal. But you cannot do that without a subscription. If you try to log on to the Azure Management portal with a Global Administrator from your Azure AD tenant you get an error telling you you do not have any active Azure subscriptions:

image

What you are experiencing here is the dichotomy between Azure and Azure AD. Azure AD is a separate service from Azure with its own roles and permissions. A user account in Azure AD can have one of several roles inside the Azure AD tenant, but no roles in Azure. The roles in Azure AD are:

Organization role Description
User Regular user without any special privileges or permissions. Can read most information in the directory (tenant).
Password Administrator Resets passwords, manages service requests, and monitors service health. Password administrators can reset passwords only for users and other password administrators.
User Administrator Resets passwords, monitors service health, and manages user accounts, user groups, and service requests. Some limitations apply to the permissions of a user management administrator. For example, they cannot delete a global administrator or create other administrators. Also, they cannot reset passwords for billing, global, and service administrators.
Service Administrator Manages service requests and monitors service health.
Billing Administrator Makes purchases, manages subscriptions, manages support tickets, and monitors service health.
Global Administrator Has access to all administrative features. The person who signs up for the Azure AD tenant becomes the first global administrator. Only global administrators can assign other administrator roles. There can be more than one global administrator at your company.

More information about the Azure AD administrative roles is available here. These roles can be granted to either Microsoft Accounts or Azure AD accounts.

As mentioned Azure has its own permissions and roles. The only two roles at present is the Service Administrator and one or more Co-Administrators. The users assigned these roles can be either Microsoft Accounts or Azure AD accounts. The Azure Preview portal (portal.azure.com) has support for Role Based Access Control (RBAC) which gives more granular control of resources. The users assigned roles in RBAC are also either Microsoft Accounts or Azure AD accounts.

So now we know that you can have two sets of permissions and roles; one for Azure AD and one for Azure. We have also established that to fully manage your Azure AD tenant you need access to the Azure Management Portal, but for that you also need an Azure subscription. You could create a an Azure trial subscription with your Azure AD Global Administrator account, but that might be more than you bargained for and requires registering a credit card and managing that subscription. Or you could add the Azure AD Global Administrator to an existing Azure subscription you have, but that will require you to use an MSA to do the linking and the account must be added as a co-admin, thus granting full access to your entire Azure subscription. This is not a good security practice. You could also manage Azure AD directly with PowerShell, but this would not give you full access to all features.

The optimal solution to this would be to let Azure AD Global Administrators log on to the Azure Management portal without a subscription to manage just Azure AD, or to have a separate portal for just Azure AD, but that is not possible. There is however an option that comes pretty close.

Azure AD only Azure subscriptions

With a special Azure offer code we can sign up for a subscription that does not require a credit card, is not a trial subscription, and that only gives access to Azure AD. Here’s how to do that:

  1. Make sure you use a clean browser or browser tab where you are not already signed in to any Microsoft services, either Azure AD based or MSA based.
  2. Use the following URL:
    https://account.windowsazure.com/signup?offer=MS-AZR-0110P
  3. Select Sign in with your organizational account and sign in with the Global Administrator account of your Azure AD tenant.
  4. Complete the Azure sign up form, note that the only thing you need to do is verify your mobile phone number.
    image
  5. Hit Sign up and you will be forwarded to the Azure Account portal while your subscription is set up.
    image
  6. Hit Portal to be forwarded to the management portal:
    image

You now have access to manage the full feature set of Azure AD in the management portal without having to sign up for a trial or pay as you go subscription. This subscription has the following characteristics:

  • It is a regular Azure subscription
  • It has a subscription ID that can be managed and associated with EA
  • It will not expire or incur charges
  • It can only manage Azure AD services
  • You can assign licenses for Azure AD Basic or Free since these are purchased over licensing agreements as opposed to Azure consumption
  • You cannot create any other Azure resources except those related to Azure AD; these are Directory, ACS and MFA
  • You can add other co-admins and change the service admin from the account portal
  • The account that signed up for this subscription is also the account admin and has access to the account portal

Further steps

Now that you have access to the full management experience through the Azure portal you can add other Azure AD tenants that you want to manage. The only way to accomplish this is to use a Microsoft Account (MSA). The MSA directory (formerly Live ID) is the only directory from which everyone can read user objects, both other MSAs and Azure AD users. This makes it possible to “bridge” two Azure AD tenants and make one MSA, or Azure AD account, a Global Administrator of both tenants. You still need to create a the special type of Azure subscription described in this post though. Here are the overall steps:

  1. Create an Azure AD only subscription for the first Azure AD tenant following the steps in the previous section.
  2. Select or create a suitable Microsoft Account
  3. Make the MSA a co-admin in your Azure subscription
  4. Make the MSA a Global Admin in your Azure AD tenant
  5. Make the MSA a Global Admin of the other Azure AD tenant you want to manage in your Azure subscription. This can be done either by creating another Azure AD only subscription or in the full Azure portal if the Azure AD tenant in question is associated with an existing subscription. Ask an admin for help if needed.
  6. You now have one MSA that is both a Global Admin in your Azure AD only Azure subscription, a co-admin on your Azure AD only subscription and a Global Admin in another Azure AD tenant you want to add and manage from your Azure AD only subscription.
  7. Log in to the Azure AD portal with the MSA
  8. Both directories should now be visible
  9. Since the MSA can read from both Azure AD tenants you can now add Azure AD accounts from one to the other.
  10. Create a user in the second Azure AD tenant that is sourced from the first Azure AD tenant by selecting New User and then User in another Windows Azure AD directory.
  11. Make the new user a Global Administrator of the directory.
  12. If you wish you can now remove the MSA from both directories and the Azure subscription and only use Azure AD accounts.

Azure and RFC3927 IP Addresses

RFC3927’s title is Dynamic Configuration of IPv4 Link-Local Addresses, and it describes how a host can automatically configure itself with an IPv4 address to communicate with other hosts on the same local link, when no statically configured IP address or DHCP server is available. The IPv4 address space set aside for this is 169.254.0.0/16. Just as RFC1918 defines addresses that can be used for private, routed networks, the addresses in RFC3927 are also private, but even more restricted than those in RFC1918. The addresses from RFC1918 (10/8, 172.16/12 and 192.168/16) will be dropped by any Internet-connected router. The only way to get traffic from a host with an RFC1918 address out on the Internet is through the use of Network Address Translation. On your own network, however, RFC1918 addresses work just as public addresses and can be routed etc. But addresses from RFC3927 will not be routed anywhere, they are what is know as link-local addresses and only facilitate communications on the same link. No router will forward RFC3927 addresses. You can test this yourself by leaving your computer set to receive a dynamic IP from a DHCP server, and then making sure that no DHCP server is available, but that your still have a network link. If your computer is RFC3927 compliant it will configure itself with an address in the 169.254.0.0/16 range. RFC3927 defines rules for how to choose an address and make sure your host can keep it once other hosts connect to the same link as you, but it is beyond this post to recite the RFC. Now let’s look at how RFC3927 pertains to Microsoft Azure.

In fact, it is very straight forward. RFC3927s 169.254.0.0/16 addresses are blocked from use in Azure on:

  • Azure Virtual Networks
    Only RFC1918 IPv4 addresses are valid on Azure vNets
  • Local network sites
    Both RFC1918 IPv4 addresses and any public IPv4 addresses you may own, unless they are in conflict with already configured network resources in Azure, can be used.
  • Gateway subnets
    Technically a part of an Azure address space so the same rules apply as for vNets.
  • P2S subnets
    Only RFC1918 IPv4 addresses allowed

The only place in Azure that the RFC3927 addresses are in use is inside S2S VPN tunnels. When you download S2S configuration scripts from the Azure portal you will find references to 169.254.0.0/16. As in this example for the Cisco ISR template:

int tunnel 1
ip address 169.254.0.1 255.255.255.0
  ip tcp adjust-mss 1350
tunnel source <NameOfYourOutsideInterface>
tunnel mode ipsec ipv4
tunnel destination 137.135.242.240
tunnel protection ipsec profile vti

And here on a Windows Server 2012 R2 RRAS server you can see it in the IP properties of the PPP Link adapter:

PPP adapter 23.101.xx.yy:

   Connection-specific DNS Suffix  . :
Description . . . . . . . . . . . : 23.101.xx.yy
Physical Address. . . . . . . . . :
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Yes
Autoconfiguration IPv4 Address. . : 169.254.0.35(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
Default Gateway . . . . . . . . . :
DHCPv6 IAID . . . . . . . . . . . : 587208029

So in summary, the only place you will find these addresses in Azure are inside your S2S VPN tunnels. Now you know what those strange addresses are doing there…

Quick and dirty DirSync install automation

Here are the steps required to do an automated vanilla install of the latest DirSync tool:

Download the DirSync bits using BITS (the URL always points to the latest version):
Start-BitsTransfer -Source http://go.microsoft.com/fwlink/?LinkID=278924 -Destination c:Tempdirsync.exe

Install the required .NET 3.5 bits:
Add-WindowsFeature -Name NET-Framework-Core

Install DirSync unattended:
.DirSync.exe /quiet

UPDATE: Regarding AADSync

Unfortunately this does not seem to work with the AADSync download.

Azure Files and IaaS Domain Controllers

Probably on of the very first VMs you deploy in your Microsoft Azure IaaS deployment are Windows Server Active Directory Domain Controllers. The Active Directory Domain Service is the foundation for pretty much every Windows server application out there, from Exchange to System Center. Running DCs in Azure IaaS works great, just remember that bit about tuning off the host caching on the disk where your DIT is.

At TechED NA 2014 Microsoft announced a new feature called Azure Files, which is currently in preview. In summary it is access to Azure storage over the SMB 2.1 protocol. Until Azure Files, if you wanted to talk to the blog, table or queue storage endpoints in Azure you had to do it via the REST API. Fine for developers, but not easliy accessible for others. What Azure Files does is introduce another endpoint for Azure storage, an endpoint that speaks the SMB protocol. So now if we want to talk to Azure Storage we can access it from any compute instance over SMB and UNC paths. So raw storage over SMB, without the need for a file server VM in between. Think of it as Fileserver-as-a-Service. Read the full announcement from the Azure Storage Group here. I wanted to use Azure Files to store a bunch of data in my lab environment in Azure, but I ran into a problem…

You access Azure Files over a UNC path where the servername is the name of the Azure Files endpoint in your storage account, the username is the name of the storage account, and the password is the access key for the same storage account. Like this:

net use \mystorageaccount.file.core.windows.netshare /u:mystorageaccount <storage account access key>

When I tried to do this on a workgroup VM in Azure it worked great, same with member servers in my lab domain, but on Domain Controllers in the domain I got this error:

System error 53 has occurred.

The network path was not found.

All VMs I have tested are in the same region and affinity group as the storage account, which is also in the same affinity group. I have also tested with a storage account outside an affinity group, but in the same region; same result.

My preliminary conclusion is that “something” in how DCs handle the browsing for the network path is different from member servers or stand alone VMs. I have no root cause yet, I just thought I should write this up so that anyone else experienceing the same would have some information. Sound of in the comments if you have experienced the same or have a solution.

Issue with using Windows Server 2012 RRAS as a local VPN device with Microsoft Azure when WAN interface has DHCP assigned IP address

In my personal lab I use a Windows Server 2012 R2 VM running on a local Hyper-V server as my VPN device to connect to a Microsoft Azure Virtual Network gateway. This setup has been working fine for quite some time, and is indeed a supported configuration. Recently though I could not make it connect. Come hear the story…

My ISP (Telenor) here in Norway is gracious enough to provide me with 2 dynamically assigned official IPv4 addresses. I use one for my home network and the other for the Azure gateway. I hadn’t used the lab for some time so the S2S VPN had been down. When I tried to reconnect it wouldn’t work.I knew Microsoft had made some changes recently, these were announced during Build 2014, so I figured I would reset the RRAS configuration and run the VPN setup from scratch. So I disabled the RRAS service and downloaded a fresh VpnDeviceScript.cfg file from the portal an redid everything. This didn’t take more than a couple of minutes, but still I could not connect. I noticed that when the RRAS service started I lost all connectivity on my WAN (Internet) interface. I could ping an address on the Interne, but the ping immediately stopped when RRAS started. I fired up Wireshark and did a trace of the WAN interface during RRAS startup and discovered that when the service starts several DHCP Discover messages were sent out on the WAN interface:

image

Since my ISP only allows 2 IPs this made the original address I had received on the WAN interface invalid. But why did it happen?

Also during RRAS startup I got this warning in the System log:

image

When RRAS is running as a remote access service, which it does when providing Site-2-Site VPN tunneling, it also supports incoming VPN requests from clients. These clients need an IP address to be able to communicate on the local network. They get this address either from the RRAS server itself and a static IP pool, or from a DHCP server on the local network where the RRAS reserves IP addresses in blocks of 10. In my case I had DHCP selected and thus no static IP pool configured. If the RRAS server is multi-homed, which it usually is, you can select which interface RRAS looks for a local DHCP server on.This settings is configured through the RRAS server properties:

image

The default setting is Allow RAS to select adapter. This was the cause of my problem. The RRAS service selected my WAN interface and send out a bunch of DHCP Discover messages to allocated IP addresses for incoming clients. This invalidated my existing DHCP lease and stopped all communication on the Internet. Once I selected the internal (LAN) Interface I could connect fine.

I guess this problem can occur in any S2S or RAS scenario where the WAN IP address is dynamically assigned.

Get-ADUser quirkiness

So I was trying to find all the users in an Active Directory domain that had a manager. Naturally I turned to PowerShell and the Get-ADUser cmdlet.

First I tried this:

Get-ADUser -Properties Manager -Filter { manager -like “*” }

That threw this error:

Get-ADUser : Operator(s): The following: ”Eq’, ‘Ne” are the only operator(s) supported for searching on extended
attribute: ‘Manager’.

OK, so we can only use the operators eq (equals) and ne (not equals) when working with what the Active Directory PowerShell module defines as extended properties. But these only work if you are interested in specific values. I wanted to find any user that had a manager defined, regardless of who it was. So I could not use eq or ne.

So then I did this:

Get-ADUser -Properties Manager -Filter * | where { $_.manager -ne $null }

Which works, but returns every user from Active Directory and then PowerShell does the filtering. Not optimal code. I could have left if there, but you know…

This is what I ended up with:

Get-ADUser -Properties Manager -LDAPFilter “(manager=*)”

This uses the power of filtering within the directory service.

Debugging unattended domain join on Windows Azure VMs

Introduction

One great thing about Windows Azure PowerShell is the ability to join a VM to an Active Directory domain during provisioning, this ability is not available in the portal. Joining a domain during Windows setup is nothing new, and it is accomplished by using the normal Windows unattended setup mechanism; namely unattend.xml. In unattend.xml you can specify the following information about the domain you want to join and the account that has permissions to perform the join operation in the directory (excerpt has been edited for readability):

<component name=”Microsoft-Windows-UnattendedJoin” processorArchitecture=”amd64″>
<Identification>
<Credentials>
<Domain><NetBIOS domain name></Domain>
<Username><NT type (samaccountname) username></Username>
<Password><password in encrypted form></Password>
</Credentials>
<JoinDomain><FQDN of domain to join></JoinDomain>
<MachineObjectOU><DN of OU to place machine account in></MachineObjectOU>
</Identification>
</component>

You usually don’t create the unattend.xml file manually, but rather use a tool like Windows System Image Manager from the Windows Assessment and Deployment Kit (ADK).

I recently had an issue where none of my new VMs would join the domain during provisioning, leaving them all in a workgroup. That led me to compile the following during my debugging.

Add-WindowsProvisioningConfig

The cmdlet that enabled a Windows Azure VM to join a domain is called Add-WindowsProvisioningConfig. If used with the –WindowsDomain parameter it lets you specify these additional parameters:

Parameter Info
JoinDomain FQDN of domain to join
Domain NetBIOS name of account with permission to join computers to domain specified in the JoinDomain parameter. This is usually always the NetBIOS name of the domain from JoinDomin, but could be from another domain in the forest or a trusted domain.
DomainUserName NT-style username (samaccountname) of account with permissions to join the domain specified in JoinDomain
DomainPassword Password of the account with permissions to join the domain specified in JoinDomain
MachineObjectOU DN of OU where the computer account of the VM should be placed

This info is loaded into the unattend.xml file used to setup the new VM. After that the unattended setup process continues  as with any regular Windows install.

Logs

If domain join does not work there are several logs that should be examined.

Operation logs in the portal

Under Management Services in the Windows Azure portal you find the Operation Logs.

image

The provisioning of a new VM is an AddRole operation, first one with Status Started and then another one with Status Succeeded. By examining the details of these you can see what is passed to the back end. This is particularly useful if you are using scripts which pass variables to the domain join parameters. Here you see exactly what is passed. Note that the password is omitted from the logs, that is not an error.

Windows Setup logs

After the portal has done its job the rest of the provisioning is left to the normal Windows unattended setup process and is handled entirely within the VM. That means that any normal troubleshooting techniques for unattended Windows setup applies. The working folder of Windows Setup is C:WindowsPanther. Here you will find the unattend.xml file used during setup (if is has not been deleted by setup itself, Azure does not do this), and the logs for the entire setup process:

File Info
unattend.xml The answer file for unattended Windows setup
setuperr.log Any major errors encountered during setup
setupact.log All setup activity

The first thing you should do is check unattend.xml and verify that it contains the correct info.

Domain join during unattended setup is done with the djoin.exe executable, so to debug domin join we need to search for that in setupact.log. Also searching for the words Warning or Error could reveal useful information. This is an excerpt from the setupact.log with the error I encountered:

2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Begin
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Loading input parameters…
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: AccountData = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: UnsecureJoin = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: MachinePassword = [secret not logged]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: JoinDomain = [corp.mydomain.com]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: JoinWorkgroup = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Domain = [corp]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Username = [Administrator]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Password = [secret not logged]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: MachineObjectOU = [CN=Computers,DC=corp,DC=mydomain,DC=com]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: DebugJoin = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: DebugJoinOnlyOnThisError = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: TimeoutPeriodInMinutes = [NULL]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Checking that auto start services have started.
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Calling DsGetDcName for corp.mydomain.com…
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: DsGetDcName returned [dc2.corp.mydomain.com]
2014-03-11 14:09:45, Info     [DJOIN.EXE] Unattended Join: Constructed domain parameter [corp.mydomain.comDC2.corp.mydomain.com]
2014-03-11 14:09:45, Warning     [DJOIN.EXE] Unattended Join: NetJoinDomain attempt failed: 0x2, will retry in 10 seconds…
2014-03-11 22:09:56, Warning     [DJOIN.EXE] Unattended Join: NetJoinDomain attempt failed: 0x2, will retry in 10 seconds…

As you can see from this case, the NetJoinDomain function fails and is eventually abandoned. You can also find these errors in the System log:

ID: 4097
Source: NetJoin
Info: The machine SERVER1 attempted to join the domain corp.mydomain.comDC2.corp.mydomain.com but failed. The error code was 2.

To find out more about this we need to look at another log; C:WindowsdebugNetSetup.log. This file contains information for alle domain join operations performed on a machine, not just the ones during setup. Here is a section from mine:

03/11/2014 22:24:44:407 NetpDoDomainJoin
03/11/2014 22:24:44:407 NetpMachineValidToJoin: ‘SERVER1’
03/11/2014 22:24:44:407     OS Version: 6.2
03/11/2014 22:24:44:407     Build number: 9200 (9200.win8_gdr.130531-1504)
03/11/2014 22:24:44:407     SKU: Windows Server 2012 Datacenter
03/11/2014 22:24:44:407     Architecture: 64-bit (AMD64)
03/11/2014 22:24:44:407 NetpDomainJoinLicensingCheck: ulLicenseValue=1, Status: 0x0
03/11/2014 22:24:44:407 NetpGetLsaPrimaryDomain: status: 0x0
03/11/2014 22:24:44:407 NetpMachineValidToJoin: status: 0x0
03/11/2014 22:24:44:407 NetpJoinDomain
03/11/2014 22:24:44:407     Machine: SERVER1
03/11/2014 22:24:44:407     Domain: corp.mydomain.comDC2.corp.mydomain.com
03/11/2014 22:24:44:407     MachineAccountOU: CN=Computers,DC=corp,DC=mydomain,DC=com
03/11/2014 22:24:44:407     Account: corpAdministrator
03/11/2014 22:24:44:407     Options: 0x23
03/11/2014 22:24:44:407 NetpLoadParameters: loading registry parameters…
03/11/2014 22:24:44:407 NetpLoadParameters: DNSNameResolutionRequired not found, defaulting to ‘1’ 0x2
03/11/2014 22:24:44:407 NetpLoadParameters: DomainCompatibilityMode not found, defaulting to ‘0’ 0x2
03/11/2014 22:24:44:407 NetpLoadParameters: status: 0x2
03/11/2014 22:24:44:407 NetpDisableIDNEncoding: no domain dns available – IDN encoding will NOT be disabled
03/11/2014 22:24:44:407 NetpJoinDomainOnDs: NetpDisableIDNEncoding returned: 0x0
03/11/2014 22:24:44:407 NetpJoinDomainOnDs: status of connecting to dc ‘\DC2.corp.mydomain.com’: 0x0
03/11/2014 22:24:44:407 NetpJoinDomainOnDs: Passed DC ‘DC2.corp.mydomain.com’ verified as DNS name ‘\DC2.corp.mydomain.com’
03/11/2014 22:24:44:407 NetpLoadParameters: loading registry parameters…
03/11/2014 22:24:44:407 NetpLoadParameters: DNSNameResolutionRequired not found, defaulting to ‘1’ 0x2
03/11/2014 22:24:44:407 NetpLoadParameters: DomainCompatibilityMode not found, defaulting to ‘0’ 0x2
03/11/2014 22:24:44:407 NetpLoadParameters: status: 0x2
03/11/2014 22:24:44:407 NetpDsGetDcName: status of verifying DNS A record name resolution for ‘DC2.corp.mydomain.com’: 0x0
03/11/2014 22:24:44:407 NetpProvisionComputerAccount:
03/11/2014 22:24:44:407     lpDomain: corp.mydomain.com
03/11/2014 22:24:44:407     lpMachineName: SERVER1
03/11/2014 22:24:44:407     lpMachineAccountOU: CN=Computers,DC=corp,DC=mydomain,DC=com
03/11/2014 22:24:44:407     lpDcName: DC2.corp.mydomain.com
03/11/2014 22:24:44:407     lpDnsHostName: (NULL)
03/11/2014 22:24:44:407     lpMachinePassword: (null)
03/11/2014 22:24:44:407     lpAccount: corpAdministrator
03/11/2014 22:24:44:407     lpPassword: (non-null)
03/11/2014 22:24:44:407     dwJoinOptions: 0x23
03/11/2014 22:24:44:407     dwOptions: 0x40000003
03/11/2014 22:24:44:407 NetpLdapBind: Verified minimum encryption strength on DC2.corp.mydomain.com: 0x0
03/11/2014 22:24:44:407 NetpLdapGetLsaPrimaryDomain: reading domain data
03/11/2014 22:24:44:407 NetpGetNCData: Reading NC data
03/11/2014 22:24:44:407 NetpGetDomainData: Lookup domain data for: DC=corp,DC=mydomain,DC=com
03/11/2014 22:24:44:407 NetpGetDomainData: Lookup crossref data for: CN=Partitions,CN=Configuration,DC=corp,DC=mydomain,DC=com
03/11/2014 22:24:44:423 NetpLdapGetLsaPrimaryDomain: result of retrieving domain data: 0x0
03/11/2014 22:24:44:423 NetpCheckForDomainSIDCollision: returning 0x0(0).
03/11/2014 22:24:44:423 NetpGetDnsHostName: PrimaryDnsSuffix defaulted to DNS domain name: corp.mydomain.com
03/11/2014 22:24:44:423 NetpGetComputerObjectDn: Cracking DNS domain name corp.mydomain.com/ into Netbios on \DC2.corp.mydomain.com
03/11/2014 22:24:44:423 NetpGetComputerObjectDn: Crack results:     name = corp
03/11/2014 22:24:44:423 NetpGetComputerObjectDn: Cracking account name corpSERVER1$ on \DC2.corp.mydomain.com
03/11/2014 22:24:44:423 NetpGetComputerObjectDn: Crack results:     Account does not exist
03/11/2014 22:24:44:423 NetpGetComputerObjectDn: Specified path ‘CN=Computers,DC=corp,DC=mydomain,DC=com’ is not an OU
03/11/2014 22:24:44:423 NetpCreateComputerObjectInDs: NetpGetComputerObjectDn failed: 0x2
03/11/2014 22:24:44:423 NetpProvisionComputerAccount: LDAP creation failed: 0x2
03/11/2014 22:24:44:423 NetpProvisionComputerAccount: Cannot retry downlevel, specifying OU is not supported
03/11/2014 22:24:44:423 ldap_unbind status: 0x0
03/11/2014 22:24:44:423 NetpJoinCreatePackagePart: status:0x2.
03/11/2014 22:24:44:423 NetpAddProvisioningPackagePart: status:0x2.
03/11/2014 22:24:44:423 NetpJoinDomainOnDs: Function exits with status of: 0x2
03/11/2014 22:24:44:423 NetpJoinDomainOnDs: status of disconnecting from ‘\DC2.corp.mydomain.com’: 0x0
03/11/2014 22:24:44:423 NetpJoinDomainOnDs: NetpResetIDNEncoding on ‘(null)’: 0x0
03/11/2014 22:24:44:423 NetpDoDomainJoin: status: 0x2

I have highlighted my particular error. As you can see I specified the DN of the computers container as the location of the new computer object. Since Computers is in fact a container and not an OU, the NetpCreateComputerObjectInDs function fails. After I specified a bona fide OU in my Add-WindowsAzureProvisioningConfig cmdlet the VM was successfully joined to my domain. If you actually want the computer object to be placed in the Computers container just omit the MachineObjectOU parameter from Add-WindowsAzureProvisioningConfig. Since the Computers container is the default location for new computer objects, unless redirected by the admin or overridden, your VMs account will end up there.

Will it run? How to run your favorite legacy OS in a Windows Azure VM

Introduction

Old OSs are very popular, at least judging by the number of, for want of a better word, “legacy” servers I find in customer data centers. The old workhorses Windows Server 2003/2003 R2, Windows 2000 and even good old Windows NT pop up in disturbing numbers. With them, the question “Will Windows X, run in a Windows Azure VM?” often follows. To be able to answer that question we first need to talk about “run” vs. “supported”. A lot of OSs can be made to run in a Windows Azure VM, but that does not mean that Microsoft will support that OS. Unfortunately a lot of people are only interested in the “run” part of the equation, ignoring any problems of supportability down the road. Support is very straight forward; the oldest supported Windows OS running in a Windows Azure VM is Windows Server 2008 R2 x64, as stated in KB2721672: Microsoft server software support for Windows Azure Virtual Machines. So if you want support the buck stops there. But what can we make to run if we throw supportability to the wind…

It’s still Hyper-V

All the physical servers in a Windows Azure data center run a modified version of Windows Server with the Hyper-V role installed. So basically all the capabilities of Hyper-V should be available in Windows Azure, unless they have been specifically blocked. The About Virtual Machines and Guest Operating Systems page lists all the guest operating systems that are supported on Hyper-V, so lets assume that we can run all of those. I’m not going to test all the OSs on that list, but rather focus on some specific golden oldies (all 32-bit editions):

  • Windows 2000
  • Windows XP
  • Windows Server 2003

There is also a lot of rumor on the Internet concerning support for 32-bit (x86) VMs in Windows Azure. Although all the images in the gallery and the fact that the earliest supported server OS (Windows Server 2008 R2) is only available in 64-bit (x64), this is never actually stated anywhere officially. (At least not that I have found.)

Another area where there is a lot of talk is concerning client operating systems in Windows Azure VMs. In this case Microsoft is very clear; client OSs are not supported and it is a violation of the license to install and run one in a Windows Azure VM. For the sake of scientific discovery I will ignore that issue for this post.

So lets see what’s what…

Basic requirements

I’m going to work from these premises during my testing:

  • The legacy OS needs to be on the supported list for Hyper-V
  • Hyper-V Integration Components need to be available
    Either on the vmguest.iso image, already in the OS or available for download.
  • Remote Desktop for Windows VMs and SSH for Linux VMs must be available
  • Only VHD images are supported in Windows Azure, not VHDX
  • None of the selected legacy OSs will support being generalized in a way that Windows Azure can use, so we can only upload OS disks, not images. (Windows Azure uses the setup technology introduced in Windows Vista, codenamed Panther, which legacy OSs don’t.)

Basic steps

Here is what we need to do (at least):

  1. Use a Hyper-V host running Windows Server 2012 R2
    This probably not a requirement, but the latest and greatest is always nice.
  2. Install a VM with the legacy OS, must select Generation 1 and the VHD disk format.
  3. Once OS install completes, install the Hyper-V integration components
  4. Update the OS through e.g. Microsoft Update
    Having the latest updates will maximize the chance of success
  5. If you want remote PowerShell or WinRM make sure to install those optional updates.
  6. Enable Remote Desktop and make sure the Remote Desktop exception is enabled in the Windows Firewall if it is enabled.
  7. If you are using WinRM technology configure that, preferably with HTTPS instead of HTTP, and enable the appropriate firewall exceptions.
  8. If you are actually trying to run a production server with a legacy OS in Windows Azure (something you should not do), remove any special drivers or low level software that might break the VM. You can always install this alter.
  9. Shut down the VM on your Hyper-V Server
  10. Upload the VHD to a Windows Azure storage account (Add-AzureVHD)
  11. Register the new blob as an OS image (Add-AzureDisk)
  12. Start the VM in Azure and log on (hopefully).

The results

Using the above method I was able to obtain these results:

OS Runs Notes
Windows 2000 Yes
  • Professional, Server and Advanced Server all share the same code base and all work
  • Windows Server 2012 removed Windows 2000 support from the Integration components so you have to use integrations components from Windows Server 2008 R2.
  • Performance was not great on my VM…
Windows XP x86 Yes
Windows Server 2003 x86 Yes Windows Server 2003 R2 is pretty much the same code base so it should run fine too. And in fact it does.

I assume that Windows Server 2003/2003R2 and XP x64 will also work.

Feel free to try some golden oldies yourself and use the comments for your results. Good luck.