Export/Public/New-LoadBalancer.ps1

function New-LoadBalancer {
    [CmdletBinding()]
    <#
    .SYNOPSIS
        ...
    .DESCRIPTION
        ...
    #>

    param(        
        [Parameter(Mandatory = $true)]
        [string]
        $ResourceGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $ResourceLocation,        
        [Parameter(Mandatory = $true)]
        [string]
        $LoadBalancerName,
        [Parameter(Mandatory = $true)]
        [string]
        $VMScaleSetName,
        [Parameter(Mandatory = $false)]
        [string]
        $FrontEndIpConfigName = "$($VMScaleSetName)FrontEnd",
        [Parameter(Mandatory = $false)]
        [string]
        $BackendPoolName = "$($VMScaleSetName)BackEnd",
        [Parameter(Mandatory = $true)]
        [string]
        $VirtualNetworkName,
        [Parameter(Mandatory = $false)]
        [string]
        $VirtualNetworkResourceGroupName = $ResourceGroupName,        
        [Parameter(Mandatory = $true)]
        [string]
        $SubnetName,
        [Parameter(Mandatory = $false)]
        [string]
        $PrivateIpAddress,
        [Parameter(Mandatory = $false)]
        [ValidateSet('IPv4', 'IPv6')]
        [string]
        $PrivateIpAddressVersion = 'IPv4',
        [Parameter(Mandatory = $false)]
        [string]
        $PublicIpAddressName,
        [Parameter(Mandatory = $false)]
        [string]
        $DomainNameLabel,
        [Parameter(Mandatory = $false)]
        [ValidateSet('Standard', 'Basic')]
        [string]
        $LoadBalancerSku = "Standard",
        [Parameter(Mandatory = $false)]
        [bool]
        $UpdateScaleSet = $true,
        [HashTable]
        $Tags
    )
    process {
        $loadBalancer = Get-AzLoadBalancer -ResourceGroupName $ResourceGroupName -Name $LoadBalancerName -ErrorAction SilentlyContinue
        if ($loadBalancer) {
            Write-Verbose "Load Balancer $LoadBalancerName already exists."
            return
        }
        $VMScaleSet = Get-AzVmss -ResourceGroupName $ResourceGroupName -VMScaleSetName $VMScaleSetName

        Write-Verbose "Setting up LoadBalancer-configuration for $LoadBalancerName..."

        Write-Verbose "Getting VirtualNetwork $VirtualNetworkName..."
        $vnet = Get-AzVirtualNetwork -Name $VirtualNetworkName -ResourceGroupName $VirtualNetworkResourceGroupName
        Write-Verbose "Getting SubnetConfiguration $SubnetName..."
        $subnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $vnet -Name $SubnetName
        if ($PublicIpAddressName) {
            Write-Verbose "Using PublicIP..."
            # Get or create PublicIP
            $publicIP = Get-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Name $PublicIpAddressName -ErrorAction SilentlyContinue
            if (-not($publicIP)) {
                Write-Verbose "Creating PublicIP..."
                $publicIP = New-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Name $PublicIpAddressName -Location $ResourceLocation -DomainNameLabel $DomainNameLabel -AllocationMethod "Static" -Sku Standard
            }     
            $frontEndArgs = @{
                Name            = "$FrontEndIpConfigName-public"
                PublicIpAddress = $publicIP
            }            
        }
        else {
            Write-Verbose "Using PrivateIP..."
            $frontEndArgs = @{
                Name                    = "$FrontEndIpConfigName-private"
                Subnet                  = $subnet
                PrivateIpAddressVersion = $PrivateIpAddressVersion
            }        
            if (-not([string]::IsNullOrEmpty($PrivateIpAddress))) {
                $frontEndArgs.Add("PrivateIpAddress", $PrivateIpAddress)
            }
        }
        $backendpool = New-AzLoadBalancerBackendAddressPoolConfig -Name $BackendPoolName

        Write-Verbose "Creating FrontEndConfiguration..."
        $frontendConfig = New-AzLoadBalancerFrontendIPConfig @frontEndArgs
        if ($PublicIpAddressName) {
            # This is the necessary configuration, so that the Scale set will be able to create outbound connections
            $probeName = "HttpProbe"
            $inboundRuleName = "InboundRule"
            $outboundRuleName = "OutboundRuleInternet"
            Write-Verbose "Creating Probe for PublicIP-access..."
            $probe = New-AzLoadBalancerProbeConfig -Name $probeName -Protocol "http" -Port 80 -IntervalInSeconds 15 -ProbeCount 2 -RequestPath /
            Write-Verbose "Creating InboundRule for PublicIP-access..."
            $inboundRule = New-AzLoadBalancerRuleConfig -Name $inboundRuleName -FrontendIPConfiguration $frontendConfig -BackendAddressPool $backendpool -Probe $probe -Protocol "Tcp" -FrontendPort 80 -BackendPort 80 -IdleTimeoutInMinutes 15 -EnableFloatingIP -LoadDistribution SourceIP -DisableOutboundSNAT
            Write-Verbose "Creating OutboundRule for PublicIP-access..."
            $outboundRule = New-AzLoadBalancerOutBoundRuleConfig -Name $outboundRuleName -FrontendIPConfiguration $frontendConfig -BackendAddressPool $backendpool -Protocol All -IdleTimeoutInMinutes 15 -AllocatedOutboundPort 10000
        }        

        Write-Verbose "Creating Load Balancer $LoadBalancerName..."
        $params = @{
            Name                    = $LoadBalancerName 
            Sku                     = $LoadBalancerSku
            ResourceGroupName       = $ResourceGroupName 
            Location                = $resourceLocation 
            FrontendIpConfiguration = $frontendConfig 
            BackendAddressPool      = $backendpool
        }
        if ($PublicIpAddressName) {
            $params.Add("Probe", $probe)
            $params.Add("LoadBalancingRule", $inboundrule)
            $params.Add("OutboundRule", $outboundrule)            
        }        
        $loadBalancer = New-AzLoadBalancer @params

        Write-Verbose "Adding Tags to Resource..."
        $Resource = Get-AzResource -ResourceGroupName $ResourceGroupName -Name $LoadBalancerName
        $Resource.Tags = $Tags
        $Resource | Set-AzResource -Force
        Write-Verbose "Done."

        # Add Scale Set to Backend
        $params = @{
            ResourceGroupName = $ResourceGroupName
            LoadBalancerName  = $LoadBalancerName
            BackendPoolName   = $BackendPoolName
            ScaleSetName      = $VMScaleSetName
        }
        Set-LoadBalancerAssociationForScaleSet @params

        return
        # Update instances
        Write-Verbose "Updating Scale Set $($VMScaleSet.Name)..."
        foreach ($instance in Get-AzVmssVM -ResourceGroupName $resourceGroupName -VMScaleSetName $VMScaleSet.Name -ErrorAction SilentlyContinue) {    
            Update-AzVmssInstance -ResourceGroupName $resourceGroupName -VMScaleSetName $VMScaleSet.Name -InstanceId $instance.InstanceID | Out-Null
        }

        <#
        ################################# TEST #################################
        $LBPrefix = "AppScaleSetLB-Public"
        #$inboundPublicIPName = "$LBPrefix-InboundPIP"
        $outboundPublicIPName = "$LBPrefix-OutboundPIP"
        #$frontEndInboundName = "$LBPrefix-FrontEndInbound"
        $frontEndOutboundName = "$LBPrefix-FrontEndOutbound"
        #$backEndInboundName = "$LBPrefix-BackEndInbound"
        $backEndOutboundName = "$LBPrefix-BackEndOutbound"
        $probeName = "HttpProbe"
        $inboundRuleName = "InboundRule"
        $outboundRuleName = "OutboundRuleInternet"
        #$pubIPin = New-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Name $inboundPublicIPName -AllocationMethod Static -Sku Standard -Location $resourceLocation
        $pubIPout = New-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Name $outboundPublicIPName -AllocationMethod Static -Sku Standard -Location $resourceLocation
        #$frontendIPin = New-AzLoadBalancerFrontendIPConfig -Name $frontEndInboundName -PublicIpAddress $pubIPin
        $frontendIPout = New-AzLoadBalancerFrontendIPConfig -Name $frontEndOutboundName -PublicIpAddress $pubIPout
        #$bepoolin = New-AzLoadBalancerBackendAddressPoolConfig -Name $backEndInboundName
        $bepoolout = New-AzLoadBalancerBackendAddressPoolConfig -Name $backEndOutboundName
        $probe = New-AzLoadBalancerProbeConfig -Name $probeName -Protocol "http" -Port 80 -IntervalInSeconds 15 -ProbeCount 2 -RequestPath /
        $inboundRule = New-AzLoadBalancerRuleConfig -Name $inboundRuleName -FrontendIPConfiguration $frontendIPout -BackendAddressPool $bepoolout -Probe $probe -Protocol "Tcp" -FrontendPort 80 -BackendPort 80 -IdleTimeoutInMinutes 15 -EnableFloatingIP -LoadDistribution SourceIP -DisableOutboundSNAT
        $outboundRule = New-AzLoadBalancerOutBoundRuleConfig -Name $outboundRuleName -FrontendIPConfiguration $frontendIPout -BackendAddressPool $bepoolout -Protocol All -IdleTimeoutInMinutes 15 -AllocatedOutboundPort 10000
        New-AzLoadBalancer -Name $LBPrefix -Sku Standard -ResourceGroupName $ResourceGroupName -Location $resourceLocation -FrontendIpConfiguration $frontendIPout -BackendAddressPool $bepoolout -Probe $probe -LoadBalancingRule $inboundrule -OutboundRule $outboundrule
        #>

        <#
        # Only update Scale Set, if it's for the Private-IP-Configuration, this saves around 5 minutes
        #if ($UpdateScaleSet) {
        Write-Verbose "Scale Set needs to be stopped to be able to update the IP Configuration."
        Write-Verbose "Stopping Scale Set..."
        Stop-AzVmss -ResourceGroupName $ResourceGroupName -VMScaleSetName $VMScaleSet.Name -Force | Out-Null
        #}
         
        Write-Verbose "Creating IPConfiguration..."
        $ipconfigName = "LBIPConfig"
        if ($PublicIpAddressName) {
            $ipconfigName = "LBIPConfig-public"
        }
 
        # IPConfig for Scale Set
        $ipConfig = New-AzVmssIpConfig `
            -Name $ipconfigName `
            -LoadBalancerBackendAddressPoolsId $loadBalancer.BackendAddressPools[0].Id `
            -SubnetId $vnet.Subnets[0].Id
 
        Write-Verbose "Adding IPConfiguration to Scale Set $($VMScaleSet.Name)..."
        if ($PublicIpAddressName) {
            $VMScaleSet = Add-AzVmssNetworkInterfaceConfiguration -VirtualMachineScaleSet $VMScaleSet -IpConfiguration $ipConfig -Name "LBIPConfigNic-public"
        }
        else {
            $VMScaleSet = Add-AzVmssNetworkInterfaceConfiguration -VirtualMachineScaleSet $VMScaleSet -IpConfiguration $ipConfig -Name "LBIPConfigNic-private"
        }
 
        Write-Verbose "Updating Scale Set $($VMScaleSet.Name)..."
        Update-AzVmss -ResourceGroupName $ResourceGroupName -VirtualMachineScaleSet $VMScaleSet -VMScaleSetName $VMScaleSet.Name | Out-Null
 
        Write-Verbose "Starting Scale Set $($VMScaleSet.Name)..."
        Start-AzVmss -ResourceGroupName $ResourceGroupName -VMScaleSetName $VMScaleSet.Name | Out-Null
         
        # We need to stop the Scale Set again, because the new Network-settings for the Load Balancer can not be applied before
        Write-Verbose "Scale Set needs to be stopped and started again so that all Instances can be updated and get the new IP Configuration."
        Write-Verbose "Stopping Scale Set..."
        Stop-AzVmss -ResourceGroupName $ResourceGroupName -VMScaleSetName $VMScaleSet.Name -Force | Out-Null
              
        foreach ($instance in Get-AzVmssVM -ResourceGroupName $resourceGroupName -VMScaleSetName $VMScaleSet.Name -ErrorAction SilentlyContinue) {
            Update-AzVmssInstance -ResourceGroupName $resourceGroupName -VMScaleSetName $VMScaleSet.Name -InstanceId $instance.InstanceID | Out-Null
        }
        Write-Verbose "Starting Scale Set $($VMScaleSet.Name)..."
        Start-AzVmss -ResourceGroupName $ResourceGroupName -VMScaleSetName $VMScaleSet.Name | Out-Null
        #>

    }    
}