The end of BizTalk Server is fast approaching, signaling a significant shift in the Microsoft integration landscape. With this transition, the era of on-premises integration is drawing to a close, prompting many organizations to migrate their integration workloads to Azure.
One key challenge in this process is: “How can I read and write from an on-premises file share using Logic Apps?” Thankfully, this functionality has been available for some time with Azure Logic Apps Standard, as documented here.
In this blog post, I’ll walk you through a complete example of how to set this up using Bicep. Along the way, I’ll also cover some lesser-known, “undocumented” features that I uncovered during my exploration to make this solution work.
The basics: networking
To access file shares within your company’s network boundaries, establishing connectivity between Azure and your on-premises network is essential. Azure provides several options for this, with VPN and ExpressRoute being the most common solutions. Typically, this setup is handled by your organization’s network or security team, so I won’t go into the specifics.
As developers, the key point to understand is that your Logic App must reside within a VNet and an associated subnet to facilitate this connection. For the purposes of this blog post, I’ll assume that your network team has already provided the necessary information to configure this.
Keep in mind that the specifics of your network setup can vary significantly based on your organization’s requirements and constraints, which is beyond the scope of this post.

Creating the Logic App
Now, let’s dive into creating our Logic App using Bicep. This section focuses specifically on the settings required to access on-premises file shares. Note that the examples provided are simplified and tailored to this scenario. You can adapt these snippets to fit your setup. Yes, I’m aware that the properties and appSettings are not exhaustive here. 😉
resource la_standard 'Microsoft.Web/sites@2023-12-01' = {
name: 'la-fileshare'
location: 'westeurope'
kind: 'functionapp,workflowapp'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'<myidentity>': {}
}
}
properties: {
enabled: true
serverFarmId: '<myasp>'
reserved: false
isXenon: false
hyperV: false
siteConfig: {
numberOfWorkers: 1
acrUseManagedIdentityCreds: false
alwaysOn: false
http20Enabled: false
functionAppScaleLimit: 0
minimumElasticInstanceCount: 1
appSettings: [
{
name: 'APP_KIND'
value: 'workflowApp'
}
{
name: 'AzureFunctionsJobHost__extensionBundle__id'
value: 'Microsoft.Azure.Functions.ExtensionBundle.Workflows'
}
{
name: 'AzureFunctionsJobHost__extensionBundle__version'
value: '[1.*, 2.0.0)'
}
{
name: 'AzureWebJobsStorage'
value: '<mystorageaccount>'
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
{
name: 'AzureFunctionsWebHost__hostid'
value: replace(guid('la-fileshare'), '-', '')
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'mystorageaccount'
}
{
name: 'WEBSITE_NODE_DEFAULT_VERSION'
value: '~18'
}
{
name: 'WEBSITE_DNS_SERVER'
value: 'primarydns'
}
{
name: 'WEBSITE_DNS_ALT_SERVER'
value: 'secondarydns'
}
{
name: 'WEBSITE_CONTENTOVERVNET'
value: '1'
}
{
name: 'WEBSITE_CONTENTSHARE'
value: 'la-fileshare'
}
{
name: '<Share>_password'
value: '@Microsoft.KeyVault(VaultName=<mykeyvault>;SecretName=<mysecret>)'
}
{
name: '<Share>_mountPath'
value: 'C:\\mounts\\<Share>'
}
]
azureStorageAccounts: {
<Share>: {
type: 'FileShare'
accountName: '<DOMAIN\\user>'
endpoint: '<FQDN or IP address of the Machine>'
shareName: '<MyShare>'
accessKey: '@AppSettingRef(<Share>_password)'
mountPath: '\\mounts\\<Share>'
protocol: 'Smb'
}
}
}
virtualNetworkSubnetId: '<myvnet>'
keyVaultReferenceIdentity: '<myidentity>'
}
}
Key App Settings
Below are the critical app settings required for this setup:
- WEBSITE_CONTENTOVERVNET: Ensures that all traffic flows through the configured VNet.
- WEBSITE_DNS_SERVER & WEBSITE_DNS_ALT_SERVER: If using an FQDN for your file share, these settings allow DNS resolution to the correct on-premises address.
- <Share>_password: This can either be plain text or a secure reference to an Azure Key Vault secret. The latter is highly recommended for security. Ensure the naming aligns with the azureStorageAccounts section (e.g., FinanceShare_password).
- <Share>_mountPath: Defines the local path inside the Logic App where the file share is mounted.
Configuring File Shares
azureStorageAccounts: {
<Share>: {
type: 'FileShare'
accountName: '<DOMAIN\\user>'
endpoint: '<FQDN or IP address of the Machine>'
shareName: '<MyShare>'
accessKey: '@AppSettingRef(<Share>_password)'
mountPath: '\\mounts\\<Share>'
protocol: 'Smb'
}
}
To map the Logic App to the file share(s), use the azureStorageAccounts property within the siteConfig. Here’s what you need to know:
- <Share>: Choose a meaningful name for your share (e.g., FinanceShare instead of fileshare1).
- type: Set this to FileShare (you can safely ignore any Bicep validation warnings).
- accountName: Provide the domain user required to access the file share.
endpoint: Specify the FQDN or IP address of the file share, such as myfileshare.mydomain.net (exclude \\ or any file paths).
- shareName: Enter the name of the specific share under the server, like FinanceDocs (avoid slashes or paths).
- accessKey: Provide the domain user password as either plain text or a reference to appSettings.
- mountPath: Map the local folder path in the Logic App. Using the same value as <Share> is recommended for readability.
- protocol: Always set this to Smb.
Deployment Insights
Bicep validation may throw warnings about certain properties, especially for azureStorageAccounts. You can safely ignore these. After deploying, the Logic App should create a local folder, e.g., C:\mounts\, which directly maps to the specified on-premises file share.
Debugging
Debugging issues with this setup can be quite challenging due to its design. The process lacks an intuitive interface, making it harder to identify and resolve problems effectively. While you can test and troubleshoot through the Kudu console, the error messages you encounter are often vague or unclear.
One major limitation is the absence of a proper UI for managing connections, running basic tests, or diagnosing issues such as authentication, authorization, or network errors. This makes troubleshooting more cumbersome than it should be.
If you encounter any issues, I strongly recommend referring to the Microsoft documentation linked earlier in this post. It provides valuable guidance and tips for validating connections and addressing common problems.
Pro Tip:
Be extremely cautious when dealing with the mapped folder (C:\mounts\<Share>). This folder is directly linked to your file share. Deleting it doesn’t just remove the mapping—it will erase the entire file share on the server side. Unfortunately, I learned this the hard way, so take my advice and tread carefully!
Triggers
The File System connector gives you two triggers to choose from:

These triggers work by polling the folder you specify, so it’s important to set a frequency that makes sense for your workflow. For example: if files are being added all the time, you’ll probably want to check more often. But if changes happen less frequently, you can space it out to keep things efficient.
When setting up a trigger, you’ll need to add the Folder Path—this tells Logic Apps where to look. Let’s say your files are stored at \\companyfileshare.domain.net\FinanceFileShare\Reporting\EndOfMonth. In this case, you’d just enter Reporting\EndOfMonth as the folder path.
Don’t forget to set how often you want the trigger to check for changes. You can also customize things like the time zone and start time to fit your needs.

Actions
After you’ve got the trigger sorted, it’s time to decide what happens next. The File System connector has a bunch of actions you can use, including:

With all these options, you can build workflows that do pretty much anything you need—moving files, processing them, archiving, and more. Once you’ve got the connection set up, the rest is just a matter of putting the pieces together.
CI/CD
When deploying your workflows as part of your CI/CD pipelines, it’s essential to ensure that your Logic Apps have the proper connections configured. A key part of this is the connections.json file, which defines how your app interacts with external resources like a file system share.
Below is an example of how you can configure this file to set up a connection to a file system:
{
"managedApiConnections": {},
"serviceProviderConnections": {
"<Share>": {
"displayName": "<Share>",
"parameterValues": {
"mountPath": "@appsetting('<Share>_mountPath')"
},
"serviceProvider": {
"id": "/serviceProviders/FileSystem"
}
}
}
}
By configuring the connections.json file in this way, your workflow will know which local folder to use, allowing seamless interaction with the file system during the execution of your Logic App as part of the CI/CD process.
If you are looking for more information on how you can include standard logic apps in your CI/CD, please refer to this page as a starting point https://learn.microsoft.com/en-us/azure/logic-apps/set-up-devops-deployment-single-tenant-azure-logic-apps?tabs=azure-devops
Wrapping Up
Legacy systems often depend on file-based integration, making on-premises file share connectivity a crucial aspect of migrating to Azure. While setting up this connection can be one of the more challenging steps, it’s a vital foundation for replicating and modernizing workflows during a BizTalk migration. Once the connection is in place, Azure Logic Apps empowers you to maintain and even enhance these file-based processes. With the File System connector, you can build a reliable and scalable platform for your integration workloads in the cloud.
Share this post:

Tim D’haeyer
Azure ConsultantIntroducing Tim, our seasoned Azure Consultant at Zure! With an impressive 15-year journey in Microsoft technologies, Tim has honed his skills as both a developer and a team lead across a multitude of projects. His enthusiasm for problem-solving is not just a job requirement; it's a genuine passion that drives excellence in every task. Join us in experiencing the blend of expertise and passion Tim brings to our team, making him an invaluable asset in navigating the complex world of Azure solutions.
tim.dhaeyer@zure.com