Skip to main content

Upload files to Azure Blob maintaining the Folder Structure and Content Type

· 3 min read
Naw Awn

There was a time when you needed to use the PowerShell script to upload your files and folders to the Azure blob storage container and you needed to maintain the folder structure. However, a few times you tried failed to achieve the result you needed.

So I ended up going through Microsoft Docs and saw this section on the Quickstarts. When you look at the Blob attribute value, it is using the forward slash instead of backslash which you would normally use on your Windows standard file system. This was the piece of the puzzle I was missing.

# upload a file to a folder to the Archive access tier
$Blob3HT = @{
File = 'D:\Images\FolderName\Image003.jpg'
Container = $ContainerName
Blob = 'FolderName/Image003.jpg'
Context = $Context
StandardBlobTier = 'Archive'
}
Set-AzStorageBlobContent @Blob3HT

This is now putting into the script to solve the problem at hand. The script will accept the root folder path of the content you want to upload. It will then work out from that path how the structure should be on the blob container.

Let's say your root path for the content was "C:\temp\mywebsite\build". The script takes out the root path and gets the remaining path to the files. While figuring out the new path structure for the blob store, it also replaces the backslash "\" with forward slash "/" along the way.

  • $FilePath = $File.FullName.SubString($Root.length + 1)
  • $BlobPath = $FilePath.Replace("\","/")
Function Upload-BlobData{
[CmdletBinding()]
Param(
[String]$Root,
[String]$ResourceGroupName,
[String]$StorageAccountName
)
Begin{
If (-Not([System.IO.Path]::IsPathRooted($Root))){
$Root = Resolve-Path -Path $Root
}
$Files = Get-ChildItem $Root -Recurse -File
$StorageAccount = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName
$Context = $StorageAccount.Context
}
Process{
Foreach($File in $Files){
$FilePath = $File.FullName.SubString($Root.length + 1)
$BlobPath = $FilePath.Replace("\","/")
$ContentType = Get-ContentType -FilePath $File.FullName
If ([String]::IsNullOrEmpty($ContentType)){
$ContentType = "application/octet-stream"
}

Write-Verbose "Upload $FilePath to $BlobPath"
Set-AzStorageblobcontent -File $File.FullName -Blob $BlobPath -Container `$web -Context $Context -Properties @{ContentType = "$ContentType; charset=utf-8";} -Force
}
}
}

The next thing when you upload the files to Azure blob container is that it doesn't know the file content type (S/MIME type). If you are uploading the files for static website, then this needs to be addressed on your script. Below is the script to work out the content type of the file being uploaded.

#Load S/MIME type only one time to boost the performance
#Reload the script, if you update mime.json content
$Script:MimeType = Get-Content "$PSScriptRoot\mime.json" | ConvertFrom-Json

Function Get-ContentType{
[CmdletBinding()]
Param(
[String]$FilePath
)
Process{
$FileType = ((Get-Item -Path $FilePath).extension).Trim(".")
return $Script:MimeType.$FileType
}
}

You will need to have a Json file which contains the definition of those content type like below.

mime.json
{
"css": "text/css",
"csv": "text/csv",
"htm": "text/html",
"html": "text/html",
"ico": "image/x-icon",
"jpeg": "image/jpeg",
"js": "application/javascript",
"png": "image/png",
"svg": "image/svg+xml",
"txt": "text/plain",
"xml": "text/xml"
}

At this point the first script Upload-BlobData can use the Get-ContentType to determine the content type and assign the right content type to the properties when the files are uploaded.

tip

Use Resolve-Path to transform the Relative Path to Absolute Path. Otherwise, the SubString() could work out the wrong index to create the path for blob container.