我试图从C#.NET WinForms应用程序连接到远程PowerShell。我的目标是创建自己的Microsoft PowerShell ISE版本。所以我需要一种从远程计算机上的应用程序执行PowerShell脚本的方法。我已经创建了几种方法,并在我的应用程序中在本地计算机上进行了测试。如果我不使用 WSManConnectionInfo 并使用使用(Runspace remoteRunspace = RunspaceFactory.CreateRunspace()),我可以在本地执行脚本,就好像它是真的powershell(小脚本) ,使用变量,输出数据使用 ft , fl ,执行我通常使用PowerShell做的很多其他事情。当我添加 WSManConnectionInfo 并将其指向我的Exchange Server,而不是使用本地连接。它似乎能够执行基本的东西,例如" get-mailbox"但是一旦我尝试管道,就使用一些脚本像$变量一样的功能,它说它不受支持。
同样,我必须在本地不使用 powershell.AddCommand(" out-string"); 时禁用它。
未处理的类型' System.Management.Automation.RemoteException'发生在System.Management.Automation.dll。
附加信息:术语“Out-String'不被识别为cmdlet,函数,脚本文件或可操作程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。
如果我不强制进行远程连接而只是在本地执行此操作,则不会出现同样的错误。似乎 SchemaUri 使得只执行基本命令非常严格。我看到其他人使用非常直接的信息的例子:
powershell.AddCommand("Get-Users");
powershell.AddParameter("ResultSize", count);
但是使用这种方法我必须定义很多可能的选项,我不想通过定义参数和其他东西。我只是想加载"脚本"并像在PowerShell窗口中一样执行它。这是我现在使用的一个例子。
public static WSManConnectionInfo PowerShellConnectionInformation(string serverUrl, PSCredential psCredentials)
{
var connectionInfo = new WSManConnectionInfo(new Uri(serverUrl), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", psCredentials);
//var connectionInfo = new WSManConnectionInfo(new Uri(serverUrl), "http://schemas.microsoft.com/powershell", psCredentials);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
connectionInfo.SkipCACheck = true;
connectionInfo.SkipCNCheck = true;
connectionInfo.SkipRevocationCheck = true;
connectionInfo.MaximumConnectionRedirectionCount = 5;
connectionInfo.OperationTimeout = 150000;
return connectionInfo;
}
public static PSCredential SecurePassword(string login, string password)
{
SecureString ssLoginPassword = new SecureString();
foreach (char x in password) { ssLoginPassword.AppendChar(x); }
return new PSCredential(login, ssLoginPassword);
}
public static string RunScriptPs(WSManConnectionInfo connectionInfo, string scriptText)
{
StringBuilder stringBuilder = new StringBuilder();
// Create a remote runspace using the connection information.
//using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace())
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
// Establish the connection by calling the Open() method to open the runspace.
// The OpenTimeout value set previously will be applied while establishing
// the connection. Establishing a remote connection involves sending and
// receiving some data, so the OperationTimeout will also play a role in this process.
remoteRunspace.Open();
// Create a PowerShell object to run commands in the remote runspace.
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddScript(scriptText);
//powershell.AddCommand("out-string");
powershell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
Collection<PSObject> results = powershell.Invoke();
foreach (PSObject result in results) {
stringBuilder.AppendLine(result.ToString());
}
}
// Close the connection. Call the Close() method to close the remote
// runspace. The Dispose() method (called by using primitive) will call
// the Close() method if it is not already called.
remoteRunspace.Close();
}
// convert the script result into a single string
return stringBuilder.ToString();
}
关于为什么会发生这种情况的任何建议,并解决如何让它以相同的方式运行?我已经看过许多像this这样的博客,但定义每个简单的命令对我来说都没有意义。我还看到了创建本地连接的选项,然后执行remote connection within that,但这是最后的选择,因为它依赖于多个其他因素。
答案 0 :(得分:9)
Exchange 2010通过PowerShell提供的管理体验 已经从本地移动到远程。 [...]只有交换cmdlet才能在此远程处理方案中运行,您将无法运行大多数PowerShell cmdlet 。 [...]是的,这确实意味着您将无法运行远程运行空间中的Where-Object和.PS1脚本等cmdlet 。
这是一个限制吗?我不这么认为。我们可以通过创建新会话并导入来轻松绕过它。
所以你需要做这样的事情:
PSCredential creds = new PSCredential(userName, securePassword);
System.Uri uri = new Uri("http://Exchange-Server/powershell?serializationLevel=Full");
Runspace runspace = RunspaceFactory.CreateRunspace();
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", uri);
command.AddParameter("Credential", creds);
command.AddParameter("Authentication", "Default");
powershell.Commands = command;
runspace.Open(); powershell.Runspace = runspace;
Collection<PSSession> result = powershell.Invoke<PSSession>();
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
powershell = PowerShell.Create();
command = new PSCommand();
command.AddScript("Import-PSSession -Session $ra");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
# now you can use remote PS like it's local one
答案 1 :(得分:2)
从Exchange Server 2010开始,您需要使用远程PowerShell会话,而不是直接添加交换PowerShell管理单元(由于在Exchange 2010中使用RBAC而不是ACL)。 因此,您需要创建新的PowerShell会话(使用New-PSSession),然后导入它(使用Import-PSSession)。 您可以使用这样的代码来执行PowerShell命令remote:
void ExecutePowerShellUsingRemotimg()
{
RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create();
PSSnapInException snapInException = null;
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfig);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
string serverFqdn = "FQDN of you server";
pipeline.Commands.AddScript(string.Format("$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://{0}/PowerShell/ -Authentication Kerberos", serverFqdn));
pipeline.Commands.AddScript("Import-PSSession $Session");
pipeline.Commands.AddScript("your PowerShell script text");
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder sb = new StringBuilder();
if (pipeline.Error != null && pipeline.Error.Count > 0)
{
// Read errors
succeeded = false;
Collection<object> errors = pipeline.Error.ReadToEnd();
foreach (object error in errors)
sb.Append(error.ToString());
}
else
{
// Read output
foreach (PSObject obj in results)
sb.Append(obj.ToString());
}
runspace.Dispose();
pipeline.Dispose();
}
答案 2 :(得分:0)
看起来您遇到了双跃点身份验证问题,我在尝试此问题时遇到了同样的问题。
在搞乱之后,我最终在本地安装了Exchange Powershell插件,并使用它们远程连接到Exchange服务器。
粗略的例子:
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
PSSnapInInfo info = runspaceConfiguration.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out snapInException);
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = runspace;
string script = string.Format(@"Get-Mailbox -Server {0} -Identity {1}", serverName, identity);
powershell.AddScript(script);
powershell.Invoke();
// Do something with the output
}