Creating a local drive mapped with an Azure File Share for your files in the cloud
File Management in the cloud is always an hot topic when using SaaS services like Dynamics 365 Business Central.
A common request that I always see popping up on forums or from partners and customers is if it’s possible to automatically save a file on a local drive from Dynamics 365 Business Central (or more in general, from SaaS applications). As you can imagine, from a SaaS tenant you don’t have access to the local file system (so you cannot directly save a file into your C: drive or on your local network share folder). I’ve talked in the past about this topic (our Mastering Dynamics 365 Business Central book provides a full solution for this task) and I’ve also shared with you a solution on this blog that permits you to save a file from Dynamics 365 Business Central to a cloud storage (like Azure Blob Storage) and then also to an SFTP server.
I know that many of you are using the solution provided in our book, but a question that sometimes I receive is: can I map this cloud storage to a local drive, so that my users can manage files transparently by working exactly as they are used to do with the files on their local machine?
As standard, you cannot map an Azure Blob Storage container as a local drive. For this scope, you can use Azure Files that has support for mapping drives to both local and azure hosted systems. Usage is exactly the same as I’ve described in my book or in my blog post linked above.
Azure Files and Azure Blob storage both offer ways to store large amounts of data in the cloud, but they are useful for slightly different purposes.
Azure Blob storage is useful for massive-scale, cloud-native applications that need to store unstructured data. To maximize performance and scale, Azure Blob storage is a simpler storage abstraction than a true file system. You can access Azure Blob storage only through REST-based client libraries (or directly through the REST-based protocol).
Azure Files is specifically a file system in the cloud. Azure Files has all the file abstracts that you know and love from years of working with on-premises operating systems. Like Azure Blob storage, Azure Files offers a REST interface and REST-based client libraries. Unlike Azure Blob storage, Azure Files offers SMB access to Azure file shares. By using SMB, you can mount an Azure file share directly on Windows, Linux, or macOS, either on-premises or in cloud VMs, without writing any code or attaching any special drivers to the file system. You also can cache Azure file shares on on-premises file servers by using Azure File Sync for quick access, close to where the data is used.
So, what’s the full solution that normally I use to satisfy this requirement? To upload a file to an Azure File Share, simply modify the UploadFile Azure Function from the previous post in order to call a new UploadBlobAsyncToFileShare function instead of the previous UploadBlobAsync. The new UploadBlobAsyncToFileShare function is defined as follow (it works with a CloudFileShare object instead of a CloudBlobContainer object, please not that to reduce the code lines here I’ve not handled logging and exceptions):
public static async Task<Uri> UploadBlobAsyncToFileShare(string base64String, string fileName, string fileType, string fileExtension, string folderName)
{
string fileShareConnectionString = "CONNECTION_STRING";
string shareName = "share_name_lowercase";
string contentType = fileType;
byte[] fileBytes = Convert.FromBase64String(base64String);
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(fileShareConnectionString);
CloudFileClient client = storageAccount.CreateCloudFileClient();
CloudFileShare share = client.GetShareReference(shareName);
//Create the share if it doesn not exists
await share.CreateIfNotExistsAsync();
//Reference to the root directory
CloudFileDirectory rootDirectory = share.GetRootDirectoryReference();
CloudFileDirectory fileDirectory = null;
if (string.IsNullOrWhiteSpace(folderName))
{
// There is no folder specified, so return a reference to the root directory.
fileDirectory = rootDirectory;
}
else
{
// There was a folder specified, so return a reference to that folder.
fileDirectory = rootDirectory.GetDirectoryReference(folderName);
await fileDirectory.CreateIfNotExistsAsync();
}
// Set a reference to the file.
CloudFile file = fileDirectory.GetFileReference(fileName);
using (Stream stream = new MemoryStream(fileBytes, 0, fileBytes.Length))
{
await file.UploadFromStreamAsync(stream).ConfigureAwait(false);
}
return file.Uri;
}
Then, you need to map the file share as a local drive. You can do this task directly from the Azure Portal or you can use Azure Powershell for that. I normally prefer the Powershell way, and the script that creates the Azure File Share and them map it as a network drive is explained here.
Creating the Azure File Share instance is obviously a one-time operation. First you need to create a storage account, then you can create a file share instance on that storage account and then you can map those instance to a local drive. The Powershell script that performs all this for you is as follows:

When the file share is created, you have an endpoint like the following:

You can map this endpoint to a local drive letter by using the New-PSDrive cmdlet:

The New-PSDrive
cmdlet creates temporary and persistent drives that are mapped to or associated with a location in a data store. Here I’m using the -Persist option in order o create a persistent drive. A persistent drive will remain active also when you close the Powershell session (otherwise temporary drives exist only in the current PowerShell session and in sessions that you create in the current session and you can’t access them by using File Explorer).
When mounted, you can see a new local disk (here mapped to the X: letter) and now you can use it as a normal drive:

Your users can now work with files in your SaaS tenant exactly like in a local drive.
The complete Powershell script that I’m using is available here.
This was originally posted here.
*This post is locked for comments