在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)。两个命令都返回:

{}

当在应用程序池标识下运行时(无论模拟),但当应用程序池以"管理员"身份运行时,正确目录的完整而准确的目录列表。

我确信我在这里错过了一些愚蠢和基本的东西,如果有人能给我一些指导,告诉我我在思维(和代码)中犯了什么错误,那就太好了。

在web应用程序中通过C#调用Powershell-应用程序池标识问题

在模拟上下文中在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,并为连接指定凭据。