我已经编写了一些使用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,函数,脚本文件或可操作程序的名称。请检查名称的拼写,或者如果包含路径,请验证路径是正确的,然后再试一次。“
当我冒充“管理员”帐户时,我认为该位置是正确的。
使用调用的“get-location”进行的某些日志记录报告该目录应该是什么。
出于血腥的心态,我试图强迫它:
System.Environment.CurrentDirectory = dir;
...还尝试了一个被调用的'set-location'。这些工作,但如果我从一个运行空间调用'get-location'它报告与以前相同的目录(正确的目录)。
我认为,也许,模拟可能存在问题,因此我编写了一些测试,以应用程序池无法完成的方式触及文件系统。这些工作。
我也检查了这个:
string contextUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
当模仿中的代码被“包装”时,以及通过应用程序池标识执行代码时,会报告正确的用户。然后我绝望了,试着调用:
@"cmd /c dir"
......(还有get-Childitem)。两个命令都返回:
{}
...在应用程序池标识下运行(无论是否模仿),但在应用程序池以“管理员”身份运行时,是正确目录的完整且准确的目录列表。
我确信我在这里错过了一些愚蠢和根本的东西,如果有人能给我一些关于我在思考(和代码)中犯了错误的指导,那就太好了。
答案 0 :(得分:3)
在模拟的上下文中,在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是localhost WinRM端点,默认情况下,它侦听版本3中的端口5985,并为连接指定凭据。