Saving Uploads to a Network Share (UNC Path) in Classic ASP

The local folder works and the share does not. The path is fine — the identity is the problem.

Why the obvious version fails

Saving to a UNC path looks like it should be a one-line change:

mvcfile.MoveTo "\\\\fileserver\\uploads\\" & storedName

And it fails with Permission denied on a server where saving to a local folder works fine. The path is correct. The problem is who is asking.

By default an IIS application pool runs as ApplicationPoolIdentity — a virtual local account. Locally that account is a real security principal. Over the network it is nobody: it presents itself as the computer account (DOMAIN\WEBSERVER$), and unless the file server has been told about that specific machine, the answer is no.

Quick way to tell this apart from an ordinary permissions problem: if a local folder works and the UNC path does not, it is almost never the share ACL — it is the identity crossing a machine boundary.

Four ways to fix it

1. Grant the computer account (simplest on a domain)

Give DOMAIN\WEBSERVER$ Change on the share and Modify on the NTFS folder. No password to store or rotate, because there isn't one — the machine account authenticates itself.

Best when: web server and file server are both domain-joined and you control the file server.

2. Run the pool as a domain service account

Set the application pool identity to a dedicated domain account and grant that account access to the share. In IIS Manager: Application Pools → Advanced Settings → Identity → Custom account.

Best when: several servers need the same access, or you want the permission to follow the application rather than the hardware. A group Managed Service Account (gMSA) is the modern version of this — same benefit, no password to manage.

Give the account access to that one share and nothing else. A pool identity with broad domain rights turns any upload vulnerability into a domain-wide problem.

3. Impersonate for the write only

Keep the pool identity minimal and borrow credentials for the moment you need them. Classic ASP has no built-in impersonation API, so this means either configuring anonymous authentication to use a specific account, or mapping the share under that identity. It is the fiddliest option and the one most likely to surprise whoever maintains the site next.

4. Do not write across the network at all

Write to a local folder, and let something else move the files — a scheduled robocopy, DFS replication, a service watching the folder. The upload path stays fast and simple, and a file-server outage no longer takes your upload form down with it.

Best when: uploads must not fail because of network conditions, which is most of the time.

Writing to the share once access works

<%
Dim fso, dest, storedName

Set fso = Server.CreateObject("Scripting.FileSystemObject")
dest    = "\\\\fileserver\\uploads\\"

If Not fso.FolderExists(dest) Then
    Response.Write "The upload share is not reachable."
    Response.End
End If

For i = 0 To UBound(list)
    Set mvcfile = uploader.GetUploadedFile(list(i))
    storedName  = list(i) & SafeExtension(mvcfile.FileName)
    mvcfile.MoveTo dest & storedName
Next
%>

Note the FolderExists check. A network path can be unavailable in ways a local path never is, and "the share was down" is a much better error message than a raw VBScript failure.

Use the UNC path directly rather than a mapped drive letter. Drive mappings belong to an interactive logon session; a service running under a pool identity generally has none, so Z:\ will not exist even though the same share works by UNC.

Keep the temp folder local

Let files stream to a local temporary folder and only move the finished file across the network. Streaming chunks over SMB is slow and multiplies the number of things that can fail mid-upload. This is the default behaviour — just do not point the temp folder at the share.

Serving files back from a share

Do not point a virtual directory at the share and link to it. Read the file server-side and stream it, so authorisation is checked and no URL maps to the share:

<%
Dim stm, q
q = Chr(34)

If Session("UserID") = "" Then Response.Status = "403 Forbidden" : Response.End

Set stm = Server.CreateObject("ADODB.Stream")
stm.Type = 1
stm.Open
stm.LoadFromFile "\\\\fileserver\\uploads\\" & storedName

Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Disposition", "attachment; filename=" & q & displayName & q
Response.AddHeader "X-Content-Type-Options", "nosniff"
Response.BinaryWrite stm.Read
stm.Close
%>

Checklist

  1. Identify the pool identity, and remember it becomes the computer account over the network.
  2. Grant rights on both the share and the NTFS folder — the effective permission is the more restrictive of the two.
  3. Use UNC paths, never mapped drive letters.
  4. Keep the temp folder local; move only finished files.
  5. Check the share is reachable before writing, and fail with a readable message.
  6. Serve files through a script rather than exposing the share as a virtual directory.
  7. Scope the account's rights to that one share.

Frequently asked questions

Why does Permission denied happen only for the UNC path?

Because ApplicationPoolIdentity is a local virtual account. Over the network it presents the computer account, which the file server has probably never been granted anything.

Can I use a mapped drive letter instead?

No, not reliably. Drive mappings belong to an interactive session and will not exist for the pool identity.

Should uploads be written straight to the file server?

Usually not. Write locally and replicate, so a network hiccup does not fail the upload.

Skip the plumbing

ASP Uploader does everything on this page out of the box: multi-file selection, a real progress bar, client and server validation, incremental large-file handling, and no COM component to register. Drop the folder on your server and add one include line.

Download the free trial Try the live demo Pricing