在web应用程序中通过C#调用Powershell-应用程序池标识问题
本文关键字:应用程序 应用 Powershell- 程序池 标识 问题 调用 web | 更新日期: 2023-09-27 18:30:07
我已经写了一些东西来使用RunspaceFactory通过C#执行Powershell。
我正在加载默认的Powershell配置文件,如下所示:
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
string scriptText = @". .'" + scriptFileName + "; " + command;
Pipeline pipeline = runspace.CreatePipeline(scriptText);
命令=我知道配置文件中的一个函数有效。
所有这些Powershell的东西都封装在Impersonator中。
为免生疑问,$profile=C:''Users''Administrator''Documents''WindowsShell''MicrosoftPowerShell_profile.ps1
这是一个在IIS 7.5 下运行的web应用程序
如果我的IIS应用程序在"administrator"帐户下运行,它就可以工作。在任何其他帐户下,它都会抛出错误:
术语".''Microsoft.PowerShell_profile.ps1"未被识别为cmdlet、函数、脚本文件或可操作程序的名称。请检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。
由于我正在模拟"管理员"帐户,我认为位置是正确的。
一些调用了"获取位置"的日志记录报告目录应该是什么。
出于血腥的思想,我试图用来强迫它
System.Environment.CurrentDirectory = dir;
以及在调用的"设置位置"处的尝试。这些都有效,但如果我从运行空间调用"getlocation",它会报告与以前相同的目录(正确的目录)。
我想,也许,模拟可能有问题,所以我写了一些测试,以应用程序池不应该做的方式接触文件系统。这些都有效。
我还检查了这个:
string contextUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
当代码被"包装"在模拟程序中时,以及通过应用程序池标识执行时,它都会报告正确的用户。然后我绝望了,试着调用:
@"cmd /c dir"
(同时获得Childitem)。两个命令都返回:
{}
当在应用程序池标识下运行时(无论模拟),但当应用程序池以"管理员"身份运行时,正确目录的完整而准确的目录列表。
我确信我在这里错过了一些愚蠢和基本的东西,如果有人能给我一些指导,告诉我我在思维(和代码)中犯了什么错误,那就太好了。
在模拟上下文中在ASP.NET中使用PowerShell时,这是一个"众所周知"的问题:它不能按照人们认为的方式工作。
原因是PowerShell在幕后启动了另一个线程来实际完成其所有工作。PowerShell中的新线程没有继承模拟的上下文。
修复并不完全美观。这篇MSDN博客文章建议将ASP.NET设置为始终流动模拟策略(以便后台线程获得标识):
<configuration>
<runtime>
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
</runtime>
</configuration>
另一种更丑陋的方法(虽然不那么狡猾)是使用WinRM。您可以将环回PowerShell会话(连接到localhost)与PowerShell一起使用,并让WinRM处理模拟。这需要System.Management.Automation.的3.0.0.0版本
var password = "HelloWorld";
var ss = new SecureString();
foreach (var passChar in password)
{
ss.AppendChar(passChar);
}
var psCredential = new PSCredential("username", ss);
var connectionInfo = new WSManConnectionInfo(new Uri("http://localhost:5985/wsman"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", psCredential);
using (var runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
connectionInfo.EnableNetworkAccess = true;
using (var powershell = PowerShell.Create())
{
这也是一个俗气的解决方案,因为它需要WinRM的Windows服务运行并配置WinRM。WinRM并不完全是"只起作用"的东西,但它能完成第一个选项中的工作并不合适。
WSManConnectionInfo中使用的URL是localhost WinRM端点,默认情况下,它侦听版本3中的端口5985,并为连接指定凭据。