我正在制作一个 ASP.NET (C#) 应用程序,它基本上是一个网关,用于为日常管理任务运行 Powershell 脚本。其中一些脚本使用 ActiveDirectory RSAT 模块,我发现其中一些 cmdlet 在通过网关调用时将无法正确运行,并且跟踪似乎暗示与域控制器的连接成功,但随后被关闭由直流电。
下面的代码是一个 ASP.NET Web 表单,它有一个文本输入来指定用户名。基本上,它执行以下操作:
- 假设 web 用户的身份(确认被 powershell 继承)
- 在该运行空间中创建一个 powershell 运行空间和一个管道
- 调用 Get-ADUser cmdlet 并将用户名作为 Identity 参数传递
通过将用户名读入表单上的输出元素来确认成功。
protected void LookupButton_Click( object sender, EventArgs e ) { WindowsImpersonationContext impersonationContext = ((WindowsIdentity)User.Identity).Impersonate(); Runspace runspace; Pipeline pipe; try { runspace = new_runspace(); runspace.Open(); pipe = runspace.CreatePipeline(); Command cmd = new Command("Get-ADUser"); cmd.Parameters.Add(new CommandParameter("Identity", text_username.Text)); pipe.Commands.Add(cmd); PSObject ps_out = pipe.Invoke().First(); output.Text = ps_out.Properties["Name"].Value.ToString(); } catch( Exception ex ) { error.Text = ex.ToString(); } finally { impersonationContext.Undo(); } } private Runspace new_runspace( ) { InitialSessionState init_state = InitialSessionState.CreateDefault(); init_state.ThreadOptions = PSThreadOptions.UseCurrentThread; init_state.ImportPSModule(new[] { "ActiveDirectory" }); return RunspaceFactory.CreateRunspace(init_state); }
有趣的部分是在 catch 块中暴露的错误消息中的具体措辞(强调我的):
System.Management.Automation.CmdletInvocationException:无法联系服务器。这可能是因为此服务器不存在、当前已关闭或没有运行 Active Directory Web 服务。---> Microsoft.ActiveDirectory.Management.ADServerDownException:无法联系服务器。这可能是因为此服务器不存在、当前已关闭或没有运行 Active Directory Web 服务。---> System.ServiceModel.CommunicationException:套接字连接被中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题造成的。本地套接字超时为“00:01:59.6870000”。---> System.IO.IOException: 读操作失败,见内部异常。---> System.ServiceModel.CommunicationException:套接字连接已中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题造成的。本地套接字超时为“00:01:59.6870000”。--->System.Net.Sockets.SocketException:现有连接被远程主机强行关闭
上层异常表明存在超时,但下层异常没有表明超时(从命令返回只需要几秒钟)。在服务器无法访问的情况下,最低级别的异常消息说明了很多,但是这个特定的措辞让我认为这里存在某种身份验证(或其他安全)问题。
2013 年 2 月 19 日更新:使用此处描述的模拟方法时,脚本按预期运行。这让我认为问题可能是 Windows 身份验证提供的 WindowsIdentity 对象可能不适合基本上对 AD 进行 RPC 调用的脚本。不幸的是,我真的不希望放弃 Windows 身份验证,因为我必须在我的应用程序代码中处理用户的密码(这不是我想要的责任)。
我还没有找到任何关于 windows auth 到底在做什么或允许使用它的模拟结果的任何文档。是否可以在使用 Windows 身份验证时执行此操作,还是我必须要求用户给我他们的密码?