从 C# 应用程序运行 PowerShell 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11120452/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Run PowerShell-Script from C# Application
提问by HW90
I'm trying to execute a PowerShell script from a c# application. The script has to be executed under a special usercontext.
我正在尝试从 ac# 应用程序执行 PowerShell 脚本。该脚本必须在特殊的用户上下文下执行。
I've tried different scenarios some are working some not:
我尝试了不同的场景,有些正在工作,有些则没有:
1. direct call from PowerShell
1.直接从PowerShell调用
I've called the script directly from a ps-console which is running under the correct usercredentials.
我直接从在正确的用户凭据下运行的 ps-console 调用了该脚本。
C:\Scripts\GroupNewGroup.ps1 1
Result:Successfully running the script.
结果:成功运行脚本。
2. from a c# console application
2. 来自 ac# 控制台应用程序
I've called the script from a c# consoleapplication which is started under the correct usercredentials.
我从 ac# consoleapplication 调用了脚本,该脚本在正确的用户凭据下启动。
Code:
代码:
string cmdArg = "C:\Scripts\GroupNewGroup.ps1 1"
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.ApartmentState = System.Threading.ApartmentState.STA;
runspace.ThreadOptions = PSThreadOptions.UseCurrentThread;
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(cmdArg);
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
Collection<PSObject> results = pipeline.Invoke();
var error = pipeline.Error.ReadToEnd();
runspace.Close();
if (error.Count >= 1)
{
string errors = "";
foreach (var Error in error)
{
errors = errors + " " + Error.ToString();
}
}
Result:No Success. And a lot of "Null-Array" exceptions.
结果:没有成功。还有很多“空数组”异常。
3. from a c# console application - code side impersonating
3. 从 ac# 控制台应用程序 - 代码端模拟
(http://platinumdogs.me/2008/10/30/net-c-impersonation-with-network-credentials)
(http://platinumdogs.me/2008/10/30/net-c-impersonation-with-network-credentials)
I've called the script from a c# consoleapplication which is started under the correct usercredentials and the code contains impersonation.
我从 ac# consoleapplication 调用了脚本,该脚本在正确的用户凭据下启动,并且代码包含模拟。
Code:
代码:
using (new Impersonator("Administrator2", "domain", "testPW"))
{
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
}
string cmdArg = "C:\Scripts\GroupNewGroup.ps1 1";
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.ApartmentState = System.Threading.ApartmentState.STA;
runspace.ThreadOptions = PSThreadOptions.UseCurrentThread;
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(cmdArg);
pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
Collection<PSObject> results = pipeline.Invoke();
var error = pipeline.Error.ReadToEnd();
runspace.Close();
if (error.Count >= 1)
{
string errors = "";
foreach (var Error in error)
{
errors = errors + " " + Error.ToString();
}
}
}
Results:
结果:
- The term 'Get-Contact' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
- The term 'C:\Scripts\FunctionsObjects.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
- No snap-ins have been registered for Windows PowerShell version 2. Microsoft.Office.Server, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
- System.DirectoryServices.AccountManagement, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- Exception calling ".ctor" with "1" argument(s): "The Web application
at
http://XXXX/websites/Test4/could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application." - You cannot call a method on a null-valued expression. Cannot index into a null array.
- 术语“Get-Contact”不被识别为 cmdlet、函数、脚本文件或可运行程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。
- 术语“C:\Scripts\FunctionsObjects.ps1”未被识别为 cmdlet、函数、脚本文件或可运行程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。
- 没有为 Windows PowerShell 版本 2 注册管理单元。Microsoft.Office.Server,版本=14.0.0.0,文化=中性,PublicKeyToken=71e9bce111e9429c
- System.DirectoryServices.AccountManagement,版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089
- 使用“1”参数调用“.ctor”时出现异常:“
http://XXXX/websites/Test4/找不到位于映射到预期应用程序的新请求 URL。” - 不能在空值表达式上调用方法。无法索引到空数组。
Until now there is no working answer
直到现在还没有有效的答案
Does anyone know why there are differences and how to solve the problem?
有谁知道为什么存在差异以及如何解决问题?
采纳答案by Chris Gessler
Have you tried Set-ExecutionPolicy Unrestricted
你有没有尝试过 Set-ExecutionPolicy Unrestricted
using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
}
}
Edit:
编辑:
Found this little gem... http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User
发现这个小宝石... http://www.codeproject.com/Articles/10090/A-small-C-Class-for-impersonating-a-User
namespace Tools
{
#region Using directives.
// ----------------------------------------------------------------------
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.ComponentModel;
// ----------------------------------------------------------------------
#endregion
/////////////////////////////////////////////////////////////////////////
/// <summary>
/// Impersonation of a user. Allows to execute code under another
/// user context.
/// Please note that the account that instantiates the Impersonator class
/// needs to have the 'Act as part of operating system' privilege set.
/// </summary>
/// <remarks>
/// This class is based on the information in the Microsoft knowledge base
/// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
///
/// Encapsulate an instance into a using-directive like e.g.:
///
/// ...
/// using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
/// {
/// ...
/// [code that executes under the new context]
/// ...
/// }
/// ...
///
/// Please contact the author Uwe Keim (mailto:[email protected])
/// for questions regarding this class.
/// </remarks>
public class Impersonator :
IDisposable
{
#region Public methods.
// ------------------------------------------------------------------
/// <summary>
/// Constructor. Starts the impersonation with the given credentials.
/// Please note that the account that instantiates the Impersonator class
/// needs to have the 'Act as part of operating system' privilege set.
/// </summary>
/// <param name="userName">The name of the user to act as.</param>
/// <param name="domainName">The domain name of the user to act as.</param>
/// <param name="password">The password of the user to act as.</param>
public Impersonator(
string userName,
string domainName,
string password )
{
ImpersonateValidUser( userName, domainName, password );
}
// ------------------------------------------------------------------
#endregion
#region IDisposable member.
// ------------------------------------------------------------------
public void Dispose()
{
UndoImpersonation();
}
// ------------------------------------------------------------------
#endregion
#region P/Invoke.
// ------------------------------------------------------------------
[DllImport("advapi32.dll", SetLastError=true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
// ------------------------------------------------------------------
#endregion
#region Private member.
// ------------------------------------------------------------------
/// <summary>
/// Does the actual impersonation.
/// </summary>
/// <param name="userName">The name of the user to act as.</param>
/// <param name="domainName">The domain name of the user to act as.</param>
/// <param name="password">The password of the user to act as.</param>
private void ImpersonateValidUser(
string userName,
string domain,
string password )
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if ( RevertToSelf() )
{
if ( LogonUser(
userName,
domain,
password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
ref token ) != 0 )
{
if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
{
tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
finally
{
if ( token!= IntPtr.Zero )
{
CloseHandle( token );
}
if ( tokenDuplicate!=IntPtr.Zero )
{
CloseHandle( tokenDuplicate );
}
}
}
/// <summary>
/// Reverts the impersonation.
/// </summary>
private void UndoImpersonation()
{
if ( impersonationContext!=null )
{
impersonationContext.Undo();
}
}
private WindowsImpersonationContext impersonationContext = null;
// ------------------------------------------------------------------
#endregion
}
/////////////////////////////////////////////////////////////////////////
}
回答by Angshuman Agarwal
Several PowerShell cmddlets take a PSCredential object to run using a particular user account. May have a look at this article -
http://letitknow.wordpress.com/2011/06/20/run-powershell-script-using-another-account/
Several PowerShell cmddlets take a PSCredential object to run using a particular user account. 可以看看这篇文章 -
http://letitknow.wordpress.com/2011/06/20/run-powershell-script-using-another-account/
Here's how you can create the Credential object containing the username and password you want to use:
以下是创建包含要使用的用户名和密码的 Credential 对象的方法:
$username = 'domain\user'
$password = 'something'
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList @($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
Once you have the password ready for use in a credential object, you can do a number of things, such as call Start-Process to launch PowerShell.exe, specifying the credential in the -Credential parameter, or Invoke-Command to invoke a "remote" command locally, specifying the credential in the -Credential parameter, or you could call Start-Job to do the work as a background job, passing the credentials you want into the -Credential parameter.
一旦您准备好在凭证对象中使用的密码,您就可以执行许多操作,例如调用 Start-Process 以启动 PowerShell.exe,在 -Credential 参数中指定凭证,或 Invoke-Command 以调用“远程”命令在本地,specifying the credential in the -Credential parameter或者您可以调用 Start-Job 将工作作为后台作业来完成,passing the credentials you want into the -Credential parameter。
See here, here& in msdnfor more information
回答by Gunnar Steinn
I just spent the day fixing this for myself.
我只是花了一天时间为自己解决这个问题。
I finally was able to make it work by adding -Scope Processto Set-ExecutionPolicy
我终于能够通过将-Scope Process添加到 Set-ExecutionPolicy使其工作
invoker.Invoke("Set-ExecutionPolicy Unrestricted -Scope Process");

