You have created Azure File Share within Azure Storage account. This File Share is having different folders and files in it. Now if you require to download these files on some server then the PowerShell script provided will be handy. You can argue that Azure File sync can be used for this. Why to use PowerShell script?

There is catch/limitation of File Sync – Any file created directly in the Azure file share by using the Azure portal or SMB are not immediately detected and replicated like changes to the server endpoint. Such changes it syncs once a day

So for immediate syncing of such files this PowerShell script can be scheduled to run in Windows task scheduler to download them.

This script assumes that the Azure Storage access key is saved in Key Vault and Service principal is used to get the access to Storage account as well as the Key vault. You need to have the below information handy before running the script

>> Vault Name – where the Azure Storage access key is stored under secrets.

>> Service Principal Client_ID & Client_secretCheck this link to create Service principal and to get this info.

>> Secret Name – Name of Secret created in Key Vault where Azure Storage access key is saved.

>> Local Path – This is the local path on the server where the downloaded folders and files would be saved.

>> Azure File Share Name – name of the File share created in Azure storage account.

 

This PowerShell script does following

>> Gets the access token to access Key Vault resource.

>> Gets the Azure Storage Account Secret from Key Vault.

>> Downloads all the folders and files from Azure File Share. Every time all files and folders will be downloaded. There is no way to detect the changes to File Share.

 

Script can be copied from here

Param ([string] $vaultName , [string] $clientId, [string] $clientSecret, [string] $secretName, [string] $localPath, [string] $storageAccountName, [string] $fileShareName)

function GetAuthUrl
(
  [string]$vaultName
)
{
  $response = try { Invoke-RestMethod -Method GET -Uri "https://$vaultName.vault.azure.net/secrets" -Headers @{} } catch { $_.Exception.Response }
  $authHeader = $response.Headers['www-authenticate']
  $endpoint = [regex]::match($authHeader, 'authorization="(.*?)"').Groups[1].Value
 
  return $endpoint
}



function GetAccessToken
(
  [string]$vaultName,
  [string]$Client_Id,
  [string]$Client_Secret
)
{
  $oauth2 = GetAuthUrl -vaultName $vaultName
  
  $body = 'grant_type=client_credentials'
  $body += '&client_id=' + $Client_Id
  $body += '&client_secret=' + [Uri]::EscapeDataString($Client_Secret)
  $body += '&resource=' + [Uri]::EscapeDataString("https://vault.azure.net")

  $response = Invoke-RestMethod -Method POST -Uri "$oauth2/oauth2/token" -Headers @{} -Body $body

  return $response.access_token
}

function GetSecret
(
  [string]$access_Token,
  [string]$vaultName,
  [string]$secretName
)
{

  $header = @{ 'Authorization' = "Bearer $access_Token" }
  
  $queryUrl = "https://$vaultName.vault.azure.net/secrets/$secretName" + '?api-version=2016-10-01'
  
  $response = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $header

  return $response.value
}

function GetAzureFiles ([string] $fileShareName , [object] $storageContext, [string] $downloadFolder, [string] $path)
{
    
	$content = get-azurestoragefile -sharename $fileSharename -Context $storagecontext -path $path | Get-AzureStorageFile
   
    foreach($file in $content) 
    {
        
		$Parentfolder = $file.uri.segments[($file.uri.segments.count - 2)] -replace '/', '\'
		
        if (!(test-path $downloadFolder)) 
        {
		    mkdir $downloadFolder
		}
		$p = $file.uri.LocalPath -replace "$($file.share.name)/", ''
        
		if (Get-AzureStorageFile -ShareName $file.share.name -path $p -Context $storageContext) 
        {
           
			if ($file.properties -is [Microsoft.WindowsAzure.Storage.File.FileDirectoryProperties]  ) 
            {
				$d = [Microsoft.WindowsAzure.Storage.File.CloudFileDirectory]::new($file.uri.AbsoluteUri) 
                
				
                $path = $d.Uri.LocalPath -replace "/$fileSharename/", ""
                
				$dest = $path -replace '/', '\'
                
                $de = $file.uri.segments[($file.uri.segments.count - 1)] -replace '/', '\'
                
				Write-Output "$($file.name) is a directory --getting all the files in $downloadfolder\$de"
				
                if (!("$downloadfolder\$de")) 
                {
					mkdir "$downloadfolder\$de"
                
				}
				
                GetAzureFiles -filesharename $fileShareName -storageContext $storageContext -downloadFolder "$downloadfolder\$de" -path $path
			}
            elseif ($file -is [Microsoft.WindowsAzure.Storage.File.CloudFile]) 
            {
				
                Write-Output "Downloading the file --- $($file.name)"
				
                $destination = $($file.name)
				$dest = "$downloadFolder\$destination"  
                $de = $downloadFolder 
                
			    if (!(test-path $de)) 
                {
					mkdir $de
				}
				Get-AzureStorageFileContent -ShareName $file.share.name -Path $p -Destination $dest -Force -Context $storageContext
                   
                
			}
			else 
            {
				Write-Output "File is already downloaded --- $dest"
			}
			
		}
		
	}
	
}


$access_Token = GetAccessToken $vaultName $clientId $clientSecret  

$secretvalue = GetSecret $access_Token $vaultName $secretName 

$storageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $secretvalue

getAzureFiles -filesharename $fileShareName -storageContext $storageContext -downloadfolder $localPath -path '/'

 

What does each function do

>>GetAccessToken – It takes vaultName, service principal client Id and Client secret as input to get access token from Azure for Key vault resource. Make sure the service principal is having access to key vault and storage account.

>>GetSecret – Once access token is received, it is used in this function to get access to secrets stored in Key vault. Secret value is returned by this function.

>>GetAzureFiles – this function downloads the folders and files available in File Share.

 

Schedule the PowerShell script in Windows Task Scheduler

You can create a task job in task scheduler to run this script at specific interval to download the files/folders from File share. Save the above script in a file and name it something like download_filesfolders.ps1

>>Open task scheduler and create a task

>> click on Triggers tab and provide details

>> Click on Actions tab and add the script and parameters as required by the script in proper order-

-file C:\script\downlaod_fielsfolders.ps1  "vaultName" "aae-fdsfdse-fdsfdg-a5e0c22f-70f8150c9fd2" "xdsgfdstr442354trhsa43egfdaXf/kl" "secretName" "C:\temp\temp" "storageAccount Name" "Filesharename"

 

>>Save the job and now it will execute every 1 minute.

 

If required you can add below statement to remove files from the File share after the download-

Remove-AzureStorageFile -ShareName $file.share.name -Path $p -Context $storageContext

If you are using powershell Azure Az module then you have to make changes to this script.

>> Enable-AzureRmAlias for backward compatibility

>> change this [Microsoft.WindowsAzure.Storage.File.FileDirectoryProperties] to [Microsoft.Azure.Storage.File.FileDirectoryProperties]

>> change this [Microsoft.WindowsAzure.Storage.File.CloudFileDirectory] to [Microsoft.Azure.Storage.File.CloudFileDirectory]

>> change this [Microsoft.WindowsAzure.Storage.File.CloudFile] to [Microsoft.Azure.Storage.File.CloudFile]