PowerShellAzureFunctions.psm1

. $PSScriptRoot\SiteNameArgumentCompleter.ps1

$httpTrigger = @{
    config = @{
        "bindings" = @(
            @{
                "name"      = "req"
                "type"      = "httpTrigger"
                "direction" = "in"
                "authLevel" = "function"
            }
            @{
                "name"      = "res"
                "type"      = "http"
                "direction" = "out"
            }
        )
    }
}

$timerTrigger = @{
    config = @{
        "bindings" = @(
            @{
                "name"      = "myTimer"
                "type"      = "timerTrigger"
                "direction" = "in"                     
                "schedule"  = "0 */5 * * * *"
            }
        )
    }
}

function Invoke-AzureLogin {
    try {
        $ctx = Get-AzureRmContext
        if (!$ctx.Subscription) {
            $null = Login-AzureRmAccount
        }
    }
    catch {
        $null = Login-AzureRmAccount
    }
}

function Get-FunctionApp {
    param($SiteName)

    Invoke-AzureLogin

    if ($SiteName) {
        Get-AzureRmResource | 
            Where-Object {
            $_.Name -eq $SiteName 
        } | ForEach-Object ResourceId   
    }
    else {
        Get-AzureRmResource | 
            Where-Object {
            $_.kind -eq 'functionapp' -and $_.ResourceType -eq 'Microsoft.Web/sites'
        } | ForEach-Object ResourceId
    }
}

function Get-Sitename {
    foreach ($name in Get-FunctionApp) {
 
        $null, $null, $subscriptionId, $null, $ResourceGroupName, $null, $null, $null, $SiteName = $name.split('/')
        [PSCustomObject][Ordered]@{
            SubscriptionId    = $subscriptionId
            ResourceGroupName = $ResourceGroupName
            SiteName          = $SiteName 
        }
    }
}

function Publish-AzureFunction {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        $SiteName,
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Alias('PSPath')]
        $SourceFile,
        [ValidateSet('HttpTrigger', 'TimerTrigger')]
        $TriggerType = "HttpTrigger" 
    )

    Begin {
        
        Invoke-AzureLogin

        Function GetResourceTypeAndName($SiteName, $Slot) {
            $ResourceType = "Microsoft.Web/sites"
            $ResourceName = $SiteName
            if ($Slot) {
                $ResourceType = "$($ResourceType)/slots"
                $ResourceName = "$($ResourceName)/$($Slot)"
            }

            $ResourceType, $ResourceName
        }

        Function GetFunctionInvokeUrl($ResourceGroupName, $SiteName, $FunctionName, $Slot) {
            $ResourceType, $ResourceName = GetResourceTypeAndName $SiteName $Slot

            Invoke-AzureRmResourceAction -ResourceGroupName $ResourceGroupName -ResourceType $ResourceType/Functions -ResourceName $SiteName/$FunctionName -Action listsecrets -ApiVersion "2015-08-01" -Force
        }
    }

    Process {
        
        $fileName = (Split-Path -Leaf $SourceFile)
        $extensionName = $fileName.Split('.')[-1]
        $FunctionName = $fileName.Split('.')[0]

        $SourceFileContent = Get-Content -Raw $SourceFile

        $map = @{
            "ps1" = "run.ps1"  
            "js"  = "index.js" 
            "cs"  = "run.csx"  
            "fs"  = "run.fsx"     
        }

        $functionFileName = $map.($extensionName)

        switch ($TriggerType) {
            "HttpTrigger" {$props = $httpTrigger}
            "TimerTrigger" {$props = $timerTrigger}
        }
        
        $props.files = @{$functionFileName = "$SourceFileContent"}        

        foreach ($targetSite in $SiteName) {
            $baseResourceID = Get-FunctionApp $targetSite
            $newResourceId = "{0}/functions/{1}" -f $baseResourceID, $FunctionName

            $ResourceGroupName = ($baseResourceID -split '/')[4]            
            Write-Verbose "Deploying $($fileName) to $($targetSite) in resource group $($ResourceGroupName)"            

            $null = New-AzureRmResource -ResourceId $newResourceId -ApiVersion 2015-08-01 -Properties $props -Force    

            if ($TriggerType -eq "HttpTrigger") {
                GetFunctionInvokeUrl $ResourceGroupName $targetSite $FunctionName |
                    ForEach-Object trigger_url
            }
            Write-Verbose "Function deployed"
        }
    }
}

Set-Alias Invoke-DeployAzureFunction Publish-AzureFunction