【问题标题】:Invoking Powershell via C# in a web application - issues with app pool identity在 Web 应用程序中通过 C# 调用 Powershell - 应用程序池标识问题
【发布时间】:2013-09-05 01:55:06
【问题描述】:

我已经编写了一些东西来使用 RunspaceFactory 通过 C# 执行 Powershell。

我正在像这样加载默认的 Powershell 配置文件:

   Runspace runspace = RunspaceFactory.CreateRunspace();
   runspace.Open();
   string scriptText = @". .\" + scriptFileName + "; " + command;
   Pipeline pipeline = runspace.CreatePipeline(scriptText);

Command = 我知道的配置文件中的一个函数。

所有这些 Powershell 的东西都包裹在 Impersonator 中。

为免生疑问,$profile = C:\Users\Administrator\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

这是在 IIS 7.5 下运行的 Web 应用程序

如果我的 IIS 应用程序在“管理员”帐户下运行,它可以工作。在任何其他帐户下都会引发错误:

“术语 '.\Microsoft.PowerShell_profile.ps1' 未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,或者如果包含路径,请确认路径正确,然后重试。”

当我冒充“管理员”帐户时,我认为该位置是正确的。

使用调用的“获取位置”进行一些日志记录会报告该目录应该是什么。

出于血腥的想法,我试图强迫它:

  System.Environment.CurrentDirectory = dir;

... 并且还尝试调用“set-location”。这些工作,但如果我从运行空间调用“get-location”,它会报告与以前相同的目录(正确的目录)。

我认为,也许,模拟可能存在问题,所以我编写了一些测试,以应用程序池不应该做的方式接触文件系统。这些工作。

我也检查了这个:

string contextUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

当代码被“包装”在模拟程序中以及通过应用程序池身份执行时,它都会报告正确的用户。然后我绝望了,尝试调用:

 @"cmd /c dir"

...(还有 get-Childitem)。两个命令都返回:

{}

...当以应用程序池身份运行时(无论模拟如何),但当应用程序池以“管理员”身份运行时,正确目录的完整且准确的目录列表。

我确信我在这里遗漏了一些愚蠢和基本的东西,如果有人可以就我在思考(和代码)中犯错误的地方给我一些指导,那就太好了。

【问题讨论】:

    标签: c# powershell


    【解决方案1】:

    这是在模拟上下文中在 ASP.NET 中使用 PowerShell 的一种“众所周知”的问题:它不像人们认为的那样工作。

    这是因为 PowerShell 在幕后启动了另一个线程来实际完成所有工作。 PowerShell 中的新线程不会继承模拟的上下文。

    修复并不完全漂亮。 This MSDN blog post 建议将 ASP.NET 设置为始终流模拟策略(以便幕后线程获取身份):

    <configuration>
        <runtime>
            <legacyImpersonationPolicy enabled="false"/>
            <alwaysFlowImpersonationPolicy enabled="true"/>
        </runtime>
    </configuration>
    

    另一种更丑陋的方法(虽然不那么老套)是使用WinRM。您可以通过 PowerShell 使用环回 PowerShell 会话(连接到 localhost),并让 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 是一个本地 WinRM 端点,默认情况下它在版本 3 中侦听端口 5985,并为连接指定凭据。

    【讨论】:

    • 非常感谢。我知道我找错了树。
    • 我不认为您知道我可以从应用程序中检查 alwaysFlowImpersonationPolicy 的值的任何方法吗?我已经对相关框架的 aspnet.config 文件进行了更改,但没有任何区别,但这几乎可以肯定是原因,我确信现在已经阅读了一些内容。愚蠢的问题,但如果编辑 C:\Windows\Microsoft.NET\Framework\ 中的文件,Visual Studio 将尊重对机器配置的更改,不是吗?我的测试是通过使用完整版 IIS 7.5 的 Visual Studio 中的调试完成的。
    • @hobgadling 嗯,对不起,我没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-31
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 2011-07-06
    • 2013-04-09
    相关资源
    最近更新 更多