Creating Multiple Azure Virtual Machines – Part пять

In the last session Creating Multiple Azure Virtual Machines – Part Vier we setup the file access rights, made sure that our Windows Communication Foundation (WCF) features were installed, setup or HTTP binding, and created and FTP server. It’s been a while since my last post so if you are unclear on what we did or just need a refresher, then please go back and re-read this post.

In this installment, we are going to install and configure the web site for our web application. The first thing we will need to do is make sure the web server is installed on the target system. Our web server of choice will of course be Internet Information Server (IIS).

Yes technically you could install Apache’ on your server as well, but since I haven’t done that; it’s what you get.

Ensure Web Server Installed

In order to ensure that the web server is installed on the target system we are going to take advantage of the Server Manager Cmdlets found on Windows 8.1, Windows PowerShell 4.0, Windows Server 2012, and Windows Server 2012 R2. We can use them to give us information about the remote server as well as what roles and/or services have been installed on the system. The first thing we will do is ensure that the web server is installed and if it is not, install it with all the correct features.

function EnsureWebServerInstalled {
    Param([Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession] $remoteSession)

    ValidateRemoteSession $remoteSession

    Write-Host "Checking for the existance of IIS Web Server"

    $webServerResults = Invoke-Command -Session $remoteSession -ScriptBlock { Get-WindowsFeature web-server }
    if ($webServerResults.Installed -eq $false) {
        Write-Host "The IIS Web Server Feature was not found on the machine, installing..."
        Invoke-Command -Session $remoteSession -ScriptBlock { Install-WindowsFeature Web-Server -IncludeAllSubFeature -IncludeManagementTools }
        Write-Host "Removing the WebDAV feature..."
        Invoke-Command -Session $remoteSession -ScriptBlock { Uninstall-WindowsFeature Web-DAV-Publishing }

    $webServerVersion = Invoke-Command -Session $remoteSession -ScriptBlock { Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp }
    if ($webServerVersion -ne $null) {
        Write-Host ($webServerVersion.IISProgramGroup + ' (' + $webServerVersion.SetupString + ') ')
        Write-Host ($webServerVersion.VersionString + ' (' + $webServerVersion.MajorVersion + '.' + $webServerVersion.MinorVersion + ')')
        Write-Host ('Install Location: ' + $webServerVersion.InstallPath)

Now you will see that, on line 13, I am removing the Web Distributed Authoring and Versioning (WebDAV) component. It is one of the components that was causing problems with our application and, since I’m not doing any editing of the documents on the web server, I don’t need this feature.

Install Web Application

Now we are going to install the web application. The first thing we are going to do is create an application pool to host our web application. Notice that I can create the application pool as either classic or integrated pipeline. You will need to select the correct one needed to run your application. Next, the command is executed to create the web site itself specifying the newly created application pool

$createApplicationPool = {
        Param([string] $applicationPoolName)

        Import-Module 'WebAdministration'

        Write-Host ('Creating Application Pool "' + $applicationPoolName + '"...')

        New-Item ('IIS:\AppPools\' + $applicationPoolName) -Force

        Write-Host 'Application Pool Created.'

$createWebApplication = {
    Param([string] $siteName, [string] $applicationPoolName, [string] $physicalPath)

    Write-Host ('Creating website "' + $siteName + '"...')
    New-WebApplication -Name $siteName -PhysicalPath $physicalPath -ApplicationPool $applicationPoolName -Site 'Default Web Site' | Write-Host
    Write-Host 'Website created.'

$setHttpBindingForSite = {
    Param([string] $siteName, [int] $portNumber)

    Write-Host ('Updating the HTTP binding for the "' + $siteName + '" site')

    [string] $protocolName = 'http'
    $existingBinding = (Get-WebBinding | Where-Object { $_.protocol -eq $protocolName })
    if ($existingBinding -ne $null) {
        Write-Host ' -> Removing the existing binding'
        Remove-WebBinding -Name $siteName -Protocol $protocolName

    New-WebBinding -Name $siteName -Protocol $protocolName -Port $portNumber -Force

    Write-Host 'Binding Updated.'

function CreateWebsites {
    Param([ValidateSet('Classic', 'Integrated')] [string] $pipeline='Integrated', [Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession] $remoteSession)
    ValidateRemoteSession $remoteSession
    $applicationPoolName = ('XYZ_Widgits v4.x ' + $pipeline)
    Invoke-Command -Session $remoteSession -ScriptBlock $createApplicationPool -ArgumentList $applicationPoolName
    Invoke-Command -Session $remoteSession -ScriptBlock $createWebApplication -ArgumentList 'ApplicationName', $applicationPoolName, 'C:\XYZ_Widgits\ApplicationName'    

function SetHttpBinding {
    Param([Parameter(Mandatory = $true)] 
          [System.Management.Automation.Runspaces.PSSession] $remoteSession,
          [Parameter(Mandatory = $true, HelpMessage="(Required) The http port that you want to assign to the site.`n")] 
          [int] $httpPort,
          [Parameter(Mandatory = $false)]
          [string] $siteName = 'Default Web Site')

    ValidateRemoteSession $remoteSession

    Invoke-Command -Session $remoteSession -ScriptBlock $setHttpBindingForSite -ArgumentList $siteName, $httpPort

After you install the web server, you are going to need to make sure that you setup the binding properly. This involves changing the binding that the web server will normally sit on, port 80. The function on line 52 will allow you to modify the default binding. This must be configured for an alternate port because you are accessing a single Azure Cloud Service. In order to get routed to the appropriate virtual machine, you will need to have the web server bound the the correct port on the virtual machine so that the End Points we configured when we created the virtual machine will function properly.

If you’ve forgotten how we did this when we created the virtual machines, please refresh your memory by re-reading my first post Creating Multiple Azure Virtual Machines.

Firewall Ports

Finally, we need to create ports in the Windows firewall that will allow the application and other things that you might need access to, to be exposed through the firewall.

function CreateFirewallPorts {
    Param([System.Management.Automation.Runspaces.PSSession] $remoteSession, [int] $httpPort = 80)

    ValidateRemoteSession -remoteSession $remoteSession

    Write-Host 'Creating Firewall Ports...'

    Invoke-Command -Session $remoteSession -ScriptBlock {
            Param([int] $port)

            Write-Host (' -> Creating Port for Http Binding TCP Port ' + $port)
            New-NetFirewallRule -DisplayName ('Basic HTTP Binding TCP Port ' + $port) -Direction Inbound -Protocol TCP -LocalPort $port
            Write-Host ' -> Creating Port for SQL Server'
            New-NetFirewallRule -DisplayName 'SQL Server TCP Port 1433' -Direction Inbound -Protocol TCP -LocalPort 1433
        } -ArgumentList $httpPort

    Write-Host 'done'


Now we have installed the web application on the remote server and opened up the firewall ports to match the binding that we created when we created the virtual machine. If your application does not require anything else, then you are done and ready to go! Mine did, however, so in my next installment I’m going to show you how to work with a database server on the remote machine. Since most applications store their data in a database of some sort, I’m sure I’ll see you there.

пока мы не встретимся снова (Until we meet again)


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s