Как я могу получить команду invoke для возврата вывода в переменную? - PullRequest
0 голосов
/ 14 мая 2019

Я пытаюсь перебрать массив серверов и запустить эту команду тестового пути в качестве фонового потока.Это должен быть поток, потому что я буду следить за ним и убивать поток, если он превысит это время.

Я не могу получить возвращаемое значение переменной, и при этом я не знаю, как бы у меня были отдельные переменные для нескольких машин или как я передаю переменные правильно.В 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;
}

Вот как я могу сделать это в Powershell с c # (работает ниже)

$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 Ответ

1 голос
/ 14 мая 2019

Во-первых, 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>

...