Add-AzureWebSite.ps1

function Add-AzureWebSite
{
    <#
    .Synopsis
        Adds an Azure web site to a service definition.
    .Description
        Adds an Azure web site to a service definition.
         
        The site can bind to multiple host
         
        Creates a web role if one does not exist.
    .Example
        New-AzureServiceDefinition -ServiceName "AService" |
            Add-AzureWebSite -SiteName "ASite" -PhysicalDirectory "C:\inetpub\wwwroot\asite" -HostHeader a.subdomain.com, nakeddomain.com, www.fulldomain.com -asString
    .Link
        New-AzureServiceDefinition
    #>

    [OutputType([xml],[string])]
    param(    
    # The ServiceDefinition XML. This should be created with New-AzureServiceDefinition or retreived with Import-AzureServiceDefinition
    [Parameter(Mandatory=$true,
        ValueFromPipeline=$true,
        ValueFromPipelineByPropertyName=$true)]
    [ValidateScript({
        $isServiceDefinition = $_.NameTable.Get("http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition")
        if (-not $IsServiceDefinition) {
            throw "Input must be a ServiceDefinition XML"
        }
        return $true
    })]    
    [Xml]
    $ServiceDefinition,

    # If set, the local resource will only apply to the role named ToRole. If ToRole is not found, or doesn't
    # exist, the last role will be used.
    [Parameter(ValueFromPipelineByPropertyName=$true)]        
    [string]
    $ToRole,
    
    # The name of the site to create. If Sitename is not set, sites will be named Web1, Web2, Web3, etc
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]
    $SiteName,
    
    # The physical directory of the website. This is where the web site files are located.
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string]
    $PhysicalDirectory,            
    
    # One or more host headers to use for the site
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [string[]]
    $HostHeader,
    
    # Additional bindings. Each hashtable can contain an EndpointName, Name, and HostHeader
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Hashtable[]]
    [ValidateScript({
        Test-SafeDictionary -Dictionary $_ -ThrowOnUnsafe
    })]
    $Binding,
    
    # Additional virtual directories.
    # The keys will be the name of the virtual directories, and the values will be the physical directory on
    # the local machine.
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Hashtable]
    [ValidateScript({
        Test-SafeDictionary -Dictionary $_ -ThrowOnUnsafe
    })]
    $VirtualDirectory,
    
    # Additional virtual applications.
    # The keys will be the name of the virtual applications, and the values will be the physical directory on
    # the local machine.
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Hashtable]
    [ValidateScript({
        Test-SafeDictionary -Dictionary $_ -ThrowOnUnsafe
    })]    
    $VirtualApplication,   
    
    # The VMSize
    [ValidateSet('ExtraSmall','Small','Medium', 'Large', 'Extra-Large', 'XS', 'XL', 'S', 'M', 'L')]
    $VMSize,
    
    # If set, will return values as a string
    [switch]
    $AsString
    )
    
    begin {
        $xmlNamespace = @{'ServiceDefinition'='http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition'}                
        if (-not $script:siteCount) {$script:SiteCount  = 0}
    }
    
    process {        
     
        $script:siteCount++
        # Resolve the role if it set, create the role if it doesn't exist, and track it if they assume the last item.
        $roles = @($ServiceDefinition.ServiceDefinition.WebRole), @($ServiceDefinition.ServiceDefinition.WorkerRole) +  @($ServiceDefinition.ServiceDefinition.VirtualMachineRole)
        
        $selectXmlParams = @{
            XPath = '//ServiceDefinition:WebRole'
            Namespace = $xmlNamespace
        }        
        $roles = @(Select-Xml -Xml $ServiceDefinition @selectXmlParams | 
            Select-Object -ExpandProperty Node)
        if (-not $roles) {
            $params = @{}
            if ($vmSize) { $params['vmSize']= $vmSize}
            $ServiceDefinition = $ServiceDefinition | 
                Add-AzureRole -RoleName "WebRole1" @params
                
            $roles = @(Select-Xml -Xml $ServiceDefinition @selectXmlParams | 
                Select-Object -ExpandProperty Node)
        }
        
        if ($roles.Count -gt 1) {
            if ($ToRole) {
            } else {
                $role = $roles[-1]                
            }
        } else {
            if ($ToRole) {
                if ($roles[0].Name -eq $ToRole) {
                    $role = $roles[0]
                } else { 
                    $role = $null 
                }
            } else {            
                $role = $roles[0]
            }           
        }
        
        if (-not $role) { return }
        
        $realSize = [Math]::Ceiling($size / 1mb)
        
        if (-not $role.Sites) {
            $role.InnerXml += "<Sites/>"
        }
        
        $sitesNode = Select-Xml -Xml $role -Namespace $xmlNamespace -XPath '//ServiceDefinition:Sites' |
            Select-Object -ExpandProperty Node
        if (-not $siteName) { 
            if ($physicalPath) {
                $SiteName = "WebSite${siteCount}"
            } else {
                $SiteName = "Web${siteCount}"
            }
            
        }
        
        if ($PhysicalDirectory) {   
            $translatedPhysicalPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($PhysicalDirectory)
            $sitesNode.InnerXml += "<Site name='$SiteName' physicalDirectory='$translatedPhysicalPath' />"
        } else {
            $sitesNode.InnerXml += "<Site name='$SiteName' />"
        }
        
        $siteNode = Select-Xml -Xml $sitesNode -Namespace $xmlNamespace -XPath "//ServiceDefinition:Site"|
            Where-Object { $_.Node.Name -eq $siteName } | 
            Select-Object -ExpandProperty Node -Last 1
                
        
        if ($psBoundParameters.VirtualDirectory)
        {
            foreach ($kv in $psBoundParameters.VirtualDirectory.GetEnumerator()) {
                $siteNode.InnerXml += " <VirtualDirectory name='$($kv.Key)' physicalDirectory='$($kv.Value)' />"
                $role.Sites.InnerXml  = $sitesNode.InnerXml.Replace('xmlns=""', '')
            }
        }
        
        if ($psBoundParameters.VirtualApplication) {
            foreach ($kv in $psBoundParameters.VirtualApplication.GetEnumerator()) {
                $siteNode.InnerXml += " <VirtualApplication name='$($kv.Key)' physicalDirectory='$($kv.Value)' />"
                $role.Sites.InnerXml  = $sitesNode.InnerXml.Replace('xmlns=""', '')
            }
        }
        
        $usedDefaultEndPoint = $false
        if (-not $role.Endpoints) {
            $usedDefaultEndPoint = $true
            $role.InnerXml += "<Endpoints><InputEndpoint name='DefaultWebSiteEndPoint' protocol='http' port='80' />
            </Endpoints>"

        }
        
        $specifiesBindingEndPoint = $false
        
        if ((-not $psBoundParameters.Binding) -and (-not $psBoundParameters.HostHeader)) {
            $endpointsNode = Select-Xml -Xml $role -Namespace $xmlNamespace -XPath "//ServiceDefinition:Endpoints"|
                Select-Object -ExpandProperty Node
        
            $endPointName = @($endPointsNode.InputEndPoint)[-1].Name
            
            $siteNode.InnerXml += "<Bindings><Binding endpointName='$endPointName' name='Binding1' /></Bindings>"            
            $role.Sites.InnerXml  = $sitesNode.InnerXml.Replace('xmlns=""', '')
        }
        
        if ($psBoundParameters.Binding) {
            $bindings = foreach ($ht in $psBoundParameters.Binding) {
                $bindingXmlText = "<Binding"
                foreach ($kv in $ht.GetEnumerator()) {
                    if ($kv.Key -eq 'EndpointName') {
                        $attributeName = 'endpointName'
                        $specifiesBindingEndPoint = $true                        
                    } elseif ($kv.Key -eq 'Name') {
                        $attributeName = 'name'
                    } elseif ($key.Key -eq 'HostHeader') {
                        $attributeName = 'hostHeader'
                    }
                    if ($attributeName){
                        $bindingXmlText+= " $attributeName='$($kv.Value)'"
                    }
                }
                "$bindingXmlText />"      
            }
            
            $ofs = [Environment]::NewLine
            $siteNode.InnerXml += "<Bindings>$bindings</Bindings>"    
            $role.Sites.InnerXml  = $sitesNode.InnerXml.Replace('xmlns=""', '')
         
        }
        
        if ($psBoundParameters.HostHeader) {
            $endpointsNode = Select-Xml -Xml $role -Namespace $xmlNamespace -XPath "//ServiceDefinition:Endpoints"|
                Select-Object -ExpandProperty Node

            $endPointName = @($endPointsNode.InputEndPoint)[-1].Name
            
            $bindingCount = 1
            $bindings = foreach ($header in $psBoundParameters.HostHeader) {
                "<Binding endpointName='$endPointName' name='Binding${BindingCount}' hostHeader='$header'/>"
            }
            $ofs = [Environment]::NewLine
            if ($siteNode.InnerXml)  {
                 $siteNode.InnerXml += "<Bindings>$bindings</Bindings>" 
            } else {
                 $siteNode.InnerXml = "<Bindings>$bindings</Bindings>" 
            }
            $role.Sites.InnerXml  = $sitesNode.InnerXml.Replace('xmlns=""', '')         
            
        }                                               
    }
    
    end {
        $webRole= Select-Xml -Xml $role -Namespace $xmlNamespace -XPath '//ServiceDefinition:WebRole' |
            Select-Object -ExpandProperty Node
            

        if ($AsString) {
            $strWrite = New-Object IO.StringWriter
            $serviceDefinition.Save($strWrite)
            return "$strWrite"
        } else {
            $serviceDefinition
        }   
    
    }
}