如何获取invoke命令以将输出返回到变量?

时间:2019-05-14 16:07:12

标签: multithreading powershell jobs invoke-command

我正在尝试遍历服务器阵列,并将此测试路径命令作为后台线程运行。它必须是一个线程,因为我将对其进行超时监视,并在超时后终止该线程。

我无法获得变量的返回值,也不知道如何在多台计算机上使用单独的变量,或者我是否正确传递了变量。在c#中,我将使用线程集合,但似乎无法弄清楚Powershell的语法。

foreach ($server in $servers)
{
    Write-Host $server;

    $scriptBlock = 
    {
        $returnVal = Test-Path "\\$server\c$";
        return $returnVal;
    }
    $remoteReturnVal = Invoke-Command -ComputerName [Environment]::MachineName -ScriptBlock { $script } –AsJob;
}

这是我如何使用c#在Powershell中进行操作(以下工作原理)

$shareCheck = 
@'

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace powershellConsoleForm
{
    public class shares
    {
        public List<string> shareExists(List<string> servers, int timeOut)
        {
            List<string> returnValue = new List<string>();
            foreach (string server in servers)
            {
                string path = @"\\" + server + @"\c$";
                Func<bool> func = () => Directory.Exists(path);
                Task<bool> task = new Task<bool>(func);
                task.Start();
                if (task.Wait(timeOut))
                {
                    //return task.Value;
                    Console.Write(" ");
                    Console.Write("success " + task.Result);
                    Console.Write(" ");
                    returnValue.Add(server + "|" + task.Result.ToString());
                }
                else
                {
                    Console.Write("timeout");
                    returnValue.Add(server + "|timeout");
                }
            }
            Console.Write("Done");
            return returnValue;
        }
    }
}
'@

try
{
    $shareChecker = New-Object powershellConsoleForm.shares;
}
catch
{
    $assemblies = ("System", "System.Collections", "System.ComponentModel", "System.Data", "System.Drawing", "System.IO", "System.Linq", "System.Management.Automation", "System.Security", "System.Threading.Tasks", "System.Windows.Forms", "System.Threading", "System.Collections.Concurrent", "System.Security.Principal");
    Add-Type -TypeDefinition $shareCheck -ReferencedAssemblies $assemblies -Language CSharp
    $shareChecker = New-Object powershellConsoleForm.shares;
}

$servers = @("server1", "server2", "server3", "server4", "server5");
$timeOut = 11000;

[int] $counter = 0;
do
{
    $counter ++;
    Write-Host $counter;
    $shareAvailibilities = $shareChecker.shareExists($servers, $timeOut);
    foreach ($shareAvailibility in $shareAvailibilities)
    {
        Write-Host $shareAvailibility;
    }

    Write-Host " ";
    Write-Host " ";

    Sleep 5;
}while ($true)

1 个答案:

答案 0 :(得分:1)

首先,默认情况下,Invoke-Command返回脚本块的输出。因此,您的脚本块可能类似于$ScriptBlock = {Test-Path "\\$server\c$"}

然后,Invoke-Command行存在多个问题。

  • 由于使用的是-AsJob,因此无需将输出分配给变量。您将使用Get-Job访问工作结果。
  • 然后您可以添加-JobName $server,以便更轻松地按服务器查看结果。
  • 删除-ComputerName,因为它默认在本地主机上运行。附带说明一下,我个人更喜欢使用$env:COMPUTERNAME,因为它在眼睛和操作上都更容易一些。
  • 您已经将$script变量包装在脚本块中(如果它已经是脚本块)。取下花括号。但是,由于该命令非常简单,因此保留括号并用该命令替换变量可能更有意义。

这是根据我的调整(以及一些格式调整)而得到的脚本的修订版本:

foreach ($server in $servers) {
  Write-Host $server
  Invoke-Command -ScriptBlock { Test-Path "\\$server\c$" } –AsJob -JobName $server
}
Get-Job

我正在考虑它,由于您只是在本地计算机上运行它们,因此仅使用Start-Job会更有意义:

foreach ($server in $servers) {
  Write-Host $server
  Start-Job -Name $server -ScriptBlock { Test-Path "\\$server\c$" }
}
Get-Job

然后要获取作业本身的结果,可以使用Receive-Job。用管道将Get-Job传递到Receive-Job,或通过名称Receive-Job -Name <servername>

访问每个