C# - IIS 上托管的 Web 应用程序仅显示共享打印机队列

C# - Only Shared Printer Queues are visible from web application hosted on IIS

提问人:Legolas21 提问时间:10/26/2023 更新时间:10/27/2023 访问量:51

问:

我在 Windows Server 2016 上运行的 System1 中配置了两台打印机。一种是共享打印机(在打印机属性中启用了打印共享)。另一个不是共享打印机(在打印机属性中禁用了打印共享)。

在 System2 中,我尝试使用以下 C# 代码片段以编程方式列出 System1 上可用的所有打印队列。

PrintServer printServer = new PrintServer(@"\\System1");
PrintQueueCollection printQueues = server.GetPrintQueues();

当我从 System2 中的控制台应用程序运行上述代码时,GetPrintQueues() 方法返回 System1 上存在的两个打印队列(共享和非共享打印机)。但是,当我从 System2 中 IIS 上托管的 ASP.NET Web 应用程序运行相同的代码片段时,GetPrintQueues() 方法仅返回 System1 上存在的共享打印机的打印队列。

我怎样才能确保,即使是在IIS上运行的Web应用程序也能够获取共享和非共享的打印队列?

注意:System1 和 System2 都使用相同的登录管理员用户运行,因此控制台应用程序使用此用户帐户运行。但是,IIS 应用程序使用 IIS 用户运行。这可能是上述问题的原因吗?如果是这样,如何以简洁的方式解决问题?

C# asp.net IIS 打印 PrintQueue

评论

0赞 Lex Li 10/26/2023
是的。用户帐户(和会话)的差异很大,这解释了您观察到的内容。从 halfblood.pro/ 中可以学到更多......
0赞 Legolas21 10/26/2023
谢谢。有哪些选项可以否定/绕过这种行为并解决问题?
0赞 Lex Li 10/26/2023
不。您没有 .NET BCL 中的选项,因为像这样的类不是为 ASP.NET learn.microsoft.com/en-us/dotnet/api/ 而设计的......PrintServer

答:

1赞 Jalpa Panchal 10/26/2023 #1

当您运行控制台应用程序时,它会在您的管理员用户帐户下执行,因此它有权访问 System1 上的所有打印队列。但是,当您运行 ASP.NET Web 应用程序时,它将在 IIS 中应用程序池的标识下执行,该应用程序池没有足够的权限。

您可以按照以下步骤将 IIS 应用程序池设置为使用自定义帐户,该帐户是管理员用户:

  1. 打开 IIS 管理器,展开服务器节点,单击“应用程序池”
  2. 找到 Web 应用程序使用的应用程序池,选择“高级设置”。
  3. 在“进程模型”部分下的“标识”属性中,选择“自定义帐户”,然后单击“设置”。
  4. 输入具有足够权限访问 System1 上所有打印队列的帐户的用户名和密码。
  5. 单击“确定”保存更改并重新启动应用程序池以使更改生效。

更新:

通过编码,可以在 asp.net Web 应用中使用模拟:

using System.Security.Principal;
using System.Runtime.InteropServices;

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
    int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

...

SafeTokenHandle safeTokenHandle;
bool returnValue = LogonUser("username", "domain", "password",
    2, 0, out safeTokenHandle); 

if (returnValue)
{
    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
    {
        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
        {
            PrintServer printServer = new PrintServer(@"\\System1");
            PrintQueueCollection printQueues = printServer.GetPrintQueues();
        }
    }
}

在用户名密码中,使用管理员用户凭据。

评论

0赞 Legolas21 10/27/2023
这就像一个魅力。谢谢!同时,探索从代码中实现类似效果的可能性也很好。
1赞 Jalpa Panchal 10/27/2023
@Legolas21请查看更新后的答案
0赞 Legolas21 10/27/2023
再次感谢。模拟是一个很好的代码解决方案,但不幸的是,由于代码/配置中需要用户凭据,因此似乎存在安全性受损的缺点。如果能够使用登录的AD用户会话并达到类似的效果就好了。需要看到这种可能性。
1赞 Jalpa Panchal 10/27/2023
@Legolas21,可以使用 IIS Windows 身份验证,在 web.config 文件中将模拟标识设置为 true,并在代码中使用 WindowsIdentity.GetCurrent() 获取当前用户的标识,并将其传递给构造函数PrintServer
0赞 Legolas21 11/9/2023
谢谢你的建议。将探索这种可能性。就目前而言,IIS配置似乎可以胜任这项工作。再次感谢。