【问题标题】:Run PowerShell scripts after connect to remote machine连接到远程计算机后运行 PowerShell 脚本
【发布时间】:2019-02-25 15:16:40
【问题描述】:

我有一个 C# 控制台应用程序。我想从中访问远程机器,然后在退出会话之前使用相同的会话运行一些 PowerShell 脚本文件(在远程机器中可用)。

我现在可以通过参考post 连接远程机器。这是我尝试过的代码...

ConnectionOptions options = new ConnectionOptions();
options.Username = "user1";
options.Password = "password123";
options.Impersonation = System.Management.ImpersonationLevel.Impersonate;

ManagementScope scope = new ManagementScope("\\\\compName\\root\\cimv2", options);
scope.Connect();

//Query system for Operating System information
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);

ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
    // Display the remote computer information
    Console.WriteLine("Computer Name     : {0}", m["csname"]);
    Console.WriteLine("Windows Directory : {0}", m["WindowsDirectory"]);
}

但我无法运行其他 PowerShell 脚本文件。我不知道如何继续下一步以运行远程计算机中的 .ps1 文件。

【问题讨论】:

  • 为什么需要 C# 控制台应用程序?为什么不只是Enter-PSSession
  • 我需要它在 c# 中使用,因为这是要求。

标签: c# powershell remote-access


【解决方案1】:

该控制台应用程序只是重现 PowerShell Remoting 正在执行的操作或 MS SysInternals psexec 正在执行的操作。

为什么要重新创建这个?

我知道这是一项要求,但从长远来看,这是一个您不必管理的过于复杂的问题。

这听起来像是未启用 PSRemoting,因此是此控制台应用程序的原因。

无论如何,您仍将实例化 PowerShell 主机以运行 PowerShell 内容。因此,您只是在 C# 应用程序中托管 PowerShell。

从 C# 运行 PowerShell 是一件很常见的事情,并且有据可查。快速搜索将为您提供大量的点击和示例。

How to run PowerShell scripts from C#

Calling C# code in Powershell and vice versa

添加以下“使用”语句以导入所需的类型:

using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

以下代码块显示了执行所有操作的 RunScript 方法 努力工作。它接受脚本文本,执行它,然后返回 结果为字符串。

private string RunScript(string scriptText)
{
    // create Powershell runspace

    Runspace runspace = RunspaceFactory.CreateRunspace();

    // open it

    runspace.Open();

    // create a pipeline and feed it the script text

    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript(scriptText);

    // add an extra command to transform the script
    // output objects into nicely formatted strings

    // remove this line to get the actual objects
    // that the script returns. For example, the script

    // "Get-Process" returns a collection
    // of System.Diagnostics.Process instances.

    pipeline.Commands.Add("Out-String");

    // execute the script

    Collection<psobject /> results = pipeline.Invoke();

    // close the runspace

    runspace.Close();

    // convert the script result into a single string

    StringBuilder stringBuilder = new StringBuilder();
    foreach (PSObject obj in results)
    {
        stringBuilder.AppendLine(obj.ToString());
    }

    return stringBuilder.ToString();
}

如何让脚本与您的程序交互

在使用 pipeline.Invoke() 调用执行脚本之前,它是 可以通过使用将程序的对象公开给脚本 方法 runspace.SessionStateProxy.SetVariable("someName", 一些对象)。

这将创建一个脚本可以访问的命名变量 (获取/设置属性,甚至调用方法)。

例如,假设我们将示例的主要形式暴露给 通过像这样添加 SetVariable() 调用来编写脚本:

...
// open it

runspace.Open();
runspace.SessionStateProxy.SetVariable("DemoForm", this);
....
Then, the following script would print the caption of the window:

$DemoForm.Text
The following script would show all the properties and methods of the window:

$DemoForm | Get-Member

但是请注意,脚本对您的对象进行的任何调用 将来自另一个线程上下文,因为 pipeline.Invoke() 似乎 启动自己的工作线程。这意味着您暴露的对象将 必须是线程安全的。

这甚至可以被视为此问答的副本

Run PowerShell-Script from C# Application

OP 更新

至于……

c# 控制台应用程序需要像中心一样处理 几个 .ps1 脚本文件,

因此,C# 应用程序是 C&C,取代了 PSRemoting / PSExec 会话。 但是,您没有说明脚本文件在哪里,或者您打算如何将它们传送到远程系统。

但首先它需要先访问远程机器。

这是什么PSRemoting...

$s = New-PSSession -ComputerName (Get-Content Servers.txt) -Credential Domain01\Admin01
Invoke-Command -Session $s -ScriptBlock {
# Run these PowerShell commands or scripts.
Get-Process PowerShell
}

或作为后台作业

$s = New-PSSession -ComputerName (Get-Content Servers.txt) -Credential Domain01\Admin01 
Invoke-Command -Session $s -ScriptBlock {
# Run these PowerShell commands or scripts.
Get-Process PowerShell
} -AsJob

PSExec 可以。

psexec \RemotePCName [-u 用户名[-p 密码]] 命令[参数]

至于……

只有在所有 .ps1 文件成功运行后,才应注销 从远程机器返回任何输出到控制台。

同样,PSRemoting 和 PSExec 所做的正是如此。

这就是为什么我想先使用 c# 连接远程,然后 然后调用所有的 .ps1 文件。

您的控制台应用只需执行上述操作。这是可行的,正如这些问答所指出的那样,只是使用命令,而不是调用脚本,但同样的规则适用......

Execute powershell script on a remote computer using C#

Invoke remote powershell command from C#

例子:

InitialSessionState initial = InitialSessionState.CreateDefault();
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddCommand("invoke-command");
ps.AddParameter("ComputerName", "mycomp.mylab.com");
ScriptBlock filter = ScriptBlock.Create("Get-childitem C:\\windows");
ps.AddParameter("ScriptBlock", filter);
foreach (PSObject obj in ps.Invoke())
{
   // Do Something
}

但同样,它只是复制上述内容。所以,是的,这是一个选择。使用 PSRemoting,使用 PSExec,构建不同的解决方案。

【讨论】:

  • 感谢您的及时回复。现在我明白这确实是一个过于复杂的问题。但是,我被困住了。不知道应该怎么做。 c# 控制台应用程序需要像中心一样处理多个 .ps1 脚本文件,但首先它需要先访问远程机器。只有在所有 .ps1 文件成功运行后,它才应该从远程计算机上注销并将任何输出返回到控制台。这就是为什么我想先使用 c# 连接远程,然后调用所有 .ps1 文件。也许您还有其他一些我可以遵循的建议?
  • .ps1 文件已经在远程机器中。你的意思是它可以使用命令而不是直接调用/添加脚本吗?
  • 是的,这些脚本中的任何命令都可以在您的 C# 应用程序中使用,如上所述。这里的交易,这些脚本有多复杂/多长?您真的想将所有内容复制并粘贴回您的应用程序吗?如果他们在那里,我会打电话给他们,但是将它们添加到您的应用程序会删除该依赖项
  • but adding them to your app removes that dependency 抱歉,您是这个意思吗?
  • 按照示例展示,只需将需要运行的命令/代码放在脚本块中--- ScriptBlock filter = ScriptBlock.Create("Get-childitem C:\\windows");
猜你喜欢
  • 2014-07-26
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 2015-11-06
  • 1970-01-01
相关资源
最近更新 更多