views:

2858

answers:

5

We are working on a web service that has to run a 3rd party process that interacts with a mapped network drive. So we have to map this drive programmatically from the web service.

I have already wrapped up WNetAddConnection2, etc. in a nicer class for another project, so I threw the code right in.

Our web service is running under UltiDev Cassini (instead of IIS) which runs under the System account. We get the error code for: "the specified device name is invalid" every time. I also tried impersonating other users in the web.config file, with the same results.

The drive will map just fine when I run my code from a console program under a normal user account.

I have also tried running the equivalent "net use" command from C# with the exact same results as WNetAddConnection.

Does anyone know why a windows service or System user wouldn't be able to map network drives?

Does anyone know a workaround? Simply mapping the drive on system startup would be a solution, but how could the system/impersonated user access it?

Link for UltiDev Cassini: UltiDev

SOLUTION: I set the UltiDev Cassini service to logon under Administrator and everything is working. The ASP .Net impersonation must not work as planned.

+2  A: 

If you're using the Local System account, then I believe it's inherently incapable of accessing network [foo]. I'd say impersonation is your only viable path. Technically you could reduce access controls on the share to the point that anyone could read/write to the share, but that brings more problems than solutions.

OldTroll
Then why does the web.config impersonation not work? I printed Environment.Username in our log, and it prints Administrator, but if I look at the UltiDev process--it is still under Local System. Could UltiDev be doing something strange?
Jonathan.Peppers
The Local System account does have network access, but it presents anonymous credentials to network resources.
bryanbcook
A: 

We had the same issue. The problem happens because of the account the code is running under. You can get around this as we did by using the following class. You have to map the drive in the same code you're using to access/copy files. The pattern we use is to always check t see if the drive is connected first. if so, we disconnect it, and then reconnect it. if not, we just connect it. It seems to clear up the issue you're describing.

public static class NetworkDrives
    {
     public static bool  MapDrive(string DriveLetter, string Path, string Username, string Password)
     {

      bool ReturnValue = false;

      if(System.IO.Directory.Exists(DriveLetter + ":\\"))
      {
       DisconnectDrive(DriveLetter);
      }
      System.Diagnostics.Process p = new System.Diagnostics.Process();
      p.StartInfo.UseShellExecute = false;
      p.StartInfo.CreateNoWindow = true;
      p.StartInfo.RedirectStandardError = true;
      p.StartInfo.RedirectStandardOutput = true;

      p.StartInfo.FileName = "net.exe";
      p.StartInfo.Arguments = " use " + DriveLetter + ": " + Path + " " + Password + " /user:" + Username;
      p.Start();
      p.WaitForExit();

      string ErrorMessage = p.StandardError.ReadToEnd();
      string OuputMessage = p.StandardOutput.ReadToEnd();
      if (ErrorMessage.Length > 0)
      {
       throw new Exception("Error:" + ErrorMessage);
      }
      else
      {
       ReturnValue = true;
      }
      return ReturnValue;
     }
     public static bool DisconnectDrive(string DriveLetter)
     {
      bool ReturnValue = false;
      System.Diagnostics.Process p = new System.Diagnostics.Process();
      p.StartInfo.UseShellExecute = false;
      p.StartInfo.CreateNoWindow = true;
      p.StartInfo.RedirectStandardError = true;
      p.StartInfo.RedirectStandardOutput = true;

      p.StartInfo.FileName = "net.exe";
      p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
      p.Start();
      p.WaitForExit();

      string ErrorMessage = p.StandardError.ReadToEnd();
      string OuputMessage = p.StandardOutput.ReadToEnd();
      if (ErrorMessage.Length > 0)
      {
       throw new Exception("Error:" + ErrorMessage);
      }
      else
      {
       ReturnValue = true;
      }
      return ReturnValue;
     }

    }
David Stratton
I cannot disconnect and reconnect because it will not connect in the first place.
Jonathan.Peppers
A: 

Instead of a mapped drive, could you connect using the UNC share?

I'd still impersonate a user that has access to the share.

Aaron Daniels
Our 3rd party process that we interact with has to work with a plain drive letter such as f:\
Jonathan.Peppers
+1  A: 

The LOCAL_SYSTEM account presents Anonymous credentials on the network. You could use a UNC network share to access this information, provided that anonymous (Everyone) has access to the share.

You can also install Cassini as a windows service which you could configure to run under a different user.

bryanbcook
A: 

I have actually done this before, but it was a VERY long time ago -- like 1997, and Win NT 3.51 with Delphi 2

I'm running from memory, but I think it goes something like this: You use the Win API:

WNetAddConnection2()

Info on the call: http://msdn.microsoft.com/en-us/library/aa385413%28VS.85%29.aspx

You can get the c# signature from pInvoke.net: http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html

Note on configuration: I think that you will need to set up a domain account for the service, and run the service with the identity of that account instead of local system. I think that you pass null as the user name and password.

You might be able to run the service as local system pass the username and password of a domain account -- I don't know whether the system account is allowed any network access at all.

JMarsch
I have already implemented WNetAddConnection2.
Jonathan.Peppers
@Jonathan: Have you applied the configuration notes in my post? It probably will not work with a service that is running as local system -- you will need to set up a domain account that has network access and the appropriate permissions to access the share that you are connecting. The service will have to run as that account, and not as local system.
JMarsch