C# - 从 Web 服务映射网络驱动器

发布于 2024-08-04 11:16:21 字数 675 浏览 10 评论 0原文

我们正在开发一个 Web 服务,该服务必须运行与映射网络驱动器交互的第 3 方进程。因此,我们必须通过 Web 服务以编程方式映射该驱动器。

我已经将 WNetAddConnection2 等封装在另一个项目的更好的类中,因此我将代码直接放入。

我们的 Web 服务在 UltiDev Cassini(而不是 IIS)下运行,而 UltiDev Cassini 在系统帐户下运行。我们每次都会收到错误代码:“指定的设备名称无效”。我还尝试在 web.config 文件中模拟其他用户,得到相同的结果。

当我在普通用户帐户下从控制台程序运行代码时,驱动器将很好地映射。

我还尝试从 C# 运行等效的“net use”命令,其结果与 WNetAddConnection 完全相同。

有谁知道为什么 Windows 服务或系统用户无法映射网络驱动器?

有人知道解决方法吗?简单地在系统启动时映射驱动器将是一个解决方案,但系统/模拟用户如何访问它?

UltiDev Cassini 的链接: UltiDev

解决方案: 我设置了 UltiDev Cassini服务以管理员身份登录,一切正常。 ASP .Net 模拟不得按计划运行。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

谈情不如逗狗 2024-08-11 11:16:21

LOCAL_SYSTEM 帐户在网络上提供匿名凭据 。您可以使用 UNC 网络共享来访问此信息,前提是匿名(每个人)都可以访问该共享。

您还可以将 Cassini 安装为 Windows 服务,您可以将其配置为在其下运行不同的用户。

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.

◇流星雨 2024-08-11 11:16:21

如果您使用本地系统帐户,那么我相信它本质上无法访问网络 [foo]。我想说,模仿是你唯一可行的途径。从技术上讲,您可以减少对共享的访问控制,使任何人都可以读取/写入共享,但这带来的问题多于解决方案。

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.

2024-08-11 11:16:21

我们有同样的问题。出现问题的原因是代码运行所用的帐户。您可以像我们一样通过使用以下类来解决这个问题。您必须使用用于访问/复制文件的相同代码来映射驱动器。我们使用的模式是始终首先检查驱动器是否已连接。如果是这样,我们将其断开,然后重新连接。如果没有,我们只需将其连接即可。看来你所描述的问题已经很清楚了。

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;
        }

    }

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;
        }

    }
屌丝范 2024-08-11 11:16:21

您可以使用 UNC 共享而不是映射驱动器进行连接吗?

我仍然会冒充有权访问共享的用户。

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

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

梦言归人 2024-08-11 11:16:21

我以前实际上已经这样做过,但那是很久以前的事了——比如 1997 年,

我从内存中运行带有 Delphi 2 的 Win NT 3.51,但我认为它是这样的:
您使用 Win API:

WNetAddConnection2()

调用信息:http://msdn.microsoft.com/en-us/library/aa385413(VS.85).aspx

您可以从 pInvoke.net 获取 C# 签名: http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html

配置注意事项:
我认为您需要为该服务设置一个域帐户,并使用该帐户的身份而不是本地系统的身份运行该服务。我认为您传递 null 作为用户名和密码。

可能能够在本地系统传递域帐户的用户名和密码时运行该服务——我根本不知道系统帐户是否允许任何网络访问。

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(VS.85).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.

灯角 2024-08-11 11:16:21

要记住的一般概念是“映射驱动器号”是用户概念,而不是系统概念。因此,当 Joe 登录到 Windows 计算机时,映射的驱动器将附加到 Joe 用户帐户。当 Windows 服务运行时,通常它在 LOCAL_SYSTEM“用户帐户”下运行,这意味着 LOCAL_SYSTEM 不知道 Joe 的映射驱动器号。

因此,当尝试从 Windows 服务中访问任何远程资源时,对网络共享的 UNC 访问是可行的方法。请注意,您可以在“Joe”用户帐户的上下文中运行 Windows 服务,或者您可以创建一个名为“MyServiceAccount”之类的虚拟 AD 帐户并将该帐户权限授予 UNC,或者您可以使用模拟并拥有Windows 服务使用带有模拟句柄的 NetLogon() 函数登录到本地工作站,然后从那里访问 UNC。

有很多方法可以做到这一点,但都归结为用户帐户与映射驱动器和 UNC 访问关联。

祝你好运,希望这些信息有帮助!

The general concept to keep in mind is that 'mapped drive letters' are a User concept, not a System concept. So when Joe logs in to the Windows Computer, the mapped drives are attached to the Joe user account. When a Windows Service is running, generally it's running under the LOCAL_SYSTEM 'user account', meaning that LOCAL_SYSTEM does not know about Joe's mapped drive letters.

Therefore, UNC access to network shares are the way to go when trying to access any remote resource from within a Windows Service. Note that you could run the Windows Service under the context of the 'Joe' user account, or you could create a dummy AD account called something like 'MyServiceAccount' and give that account rights to the UNC, or you could use Impersonation and have the Windows Service log in to the local workstation using the NetLogon() function with an impersonation handle and then access the UNC from there.

There are lots of ways to do it, but the all come down to User accounts are associated with Mapped Drives and UNC access.

Good Luck, hope this information helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文