Upload files to Azure Web App via FTP

Upload files to Azure Web App via FTP

Recently, I was spending some time on Stack overflow and found an interesting Question on our today’s headline topic. The Question is based on Official Azure Documentation on Uploading files to Azure Web App via FTP.

Issue:

The person who asked the question was getting below error whenever the sample script provided in the article tries to upload file from first sub-folder of the source location but works fine for the files present root folder.

Exception calling "UploadFile" with "2" argument(s):
The remote server returned an error: (550) File unavailable (e.g., file not found, no access)

On the first look at the issue, i thought it would because of some reason(some other process might be using the file) the file from sub-folder isn’t available for upload. But when i did some research on this error, i understand that it could be some issue with the script itself as so many people who are using the same are reporting the same issue and then I decided to dig through it and come up with a solution.

When I tried to the script on myself, i was able to reproduce the exact same error which was reported on Stack overflow. If we are able to reproduce any issue, there is a better chance that we can do a better fix to it.

After doing some debugging on the script with one of the sample azure web app created for this demo, i figured it out that when we create a web app in azure the root folder(ftp) for the application would be like below

ftp://XXXXXX.ftp.azurewebsites.windows.net/site/wwwroot/

So when the script tried to upload files from root directory of source location, it went smooth and successful as ┬áit just need to upload files to wwwroot folder on FTP which is existing. But when trying to upload any file from sub-directory, it will look for a folder under wwwroot with the same name as sub-folder at source location before uploading file to FTP location and hence failing to find sub-folder and throwing the error “file not found“.

Fix:

In the original script, it was retrieving all the files from Source directory recursively by checking a condition that it is not a directory which means it will result in only actual files.

$files = Get-ChildItem -Path $appdirectory -Recurse | Where-Object{!($_.PSIsContainer)}

foreach ($file in $files)
{
$relativepath = (Resolve-Path -Path $file.FullName -Relative).Replace(".\", "").Replace('\', '/')

$uri = New-Object System.Uri("$url/$relativepath")

"Uploading to " + $uri.AbsoluteUri $webclient.UploadFile($uri, $file.FullName) 
}

In my fix, i removed the condition to check for directory while retrieving the files and added condition inside loop to check if it is a Directory then creating that directory in FTP location using a new FTP Request as shown below:

$files = Get-ChildItem -Path $appdirectory -Recurse #Removed IsContainer condition
foreach ($file in $files)
{
    $relativepath = (Resolve-Path -Path $file.FullName -Relative).Replace(".\", "").Replace('\', '/')  
    $uri = New-Object System.Uri("$url/$relativepath")

    if($file.PSIsContainer)
    {
        $uri.AbsolutePath + "is Directory"
        $ftprequest = [System.Net.FtpWebRequest]::Create($uri);
        $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
        $ftprequest.UseBinary = $true

        $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)

        $response = $ftprequest.GetResponse();
        $response.StatusDescription
        continue
    }

    "Uploading to " + $uri.AbsoluteUri + " from "+ $file.FullName

    $webclient.UploadFile($uri, $file.FullName)
} 

with this, as we are creating a directory at FTP location before uploading file from sub-directory, we will not hit the mentioned exception and all the files from source location would be uploaded successfully.

Here is whole script for your reference.

$appdirectory="<Replace with your app directory>"
$webappname="mywebapp$(Get-Random)"
$location="West Europe"

# Create a resource group.
New-AzureRmResourceGroup -Name myResourceGroup -Location $location

# Create an App Service plan in `Free` tier.
New-AzureRmAppServicePlan -Name $webappname -Location $location `
-ResourceGroupName myResourceGroup -Tier Free

# Create a web app.
New-AzureRmWebApp -Name $webappname -Location $location -AppServicePlan $webappname `
-ResourceGroupName myResourceGroup

# Get publishing profile for the web app
$xml = (Get-AzureRmWebAppPublishingProfile -Name $webappname `
-ResourceGroupName myResourceGroup `
-OutputFile null)

# Not in Original Script
$xml = $xml

# Extract connection information from publishing profile
$username = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userName").value
$password = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@userPWD").value
$url = $xml.SelectNodes("//publishProfile[@publishMethod=`"FTP`"]/@publishUrl").value

# Upload files recursively 
Set-Location $appdirectory
$webclient = New-Object -TypeName System.Net.WebClient
$webclient.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$files = Get-ChildItem -Path $appdirectory -Recurse #Removed IsContainer condition
foreach ($file in $files)
{
    $relativepath = (Resolve-Path -Path $file.FullName -Relative).Replace(".\", "").Replace('\', '/')  
    $uri = New-Object System.Uri("$url/$relativepath")

    if($file.PSIsContainer)
    {
        $uri.AbsolutePath + "is Directory"
        $ftprequest = [System.Net.FtpWebRequest]::Create($uri);
        $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
        $ftprequest.UseBinary = $true

        $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)

        $response = $ftprequest.GetResponse();
        $response.StatusDescription
        continue
    }

    "Uploading to " + $uri.AbsoluteUri + " from "+ $file.FullName

    $webclient.UploadFile($uri, $file.FullName)
} 
$webclient.Dispose()

Hope it resolved your issue.

Happy Coding!!!

<p>I am a Consultant at Microsoft currently living in Hyderabad, India. My interests range from blogging to technology especially into /Web. I am also interested in movies and photography.</p>

Leave a Reply

1 thought on “Upload files to Azure Web App via FTP”

Skip to toolbar