Вызов cmd.exe с помощью PowerShell вызывает несколько экземпляров асинхронно. Не ждите закрытия cmd.exe - PullRequest
0 голосов
/ 06 мая 2019

Я пишу функцию, которая будет устанавливать удаленные сеансы захвата пакетов Wireshark для виртуальных машин, работающих на хостах ESXi.

Эта функция получит массив объектов vNIC, затем на основе информации для каждого vNIC будет использовать plink и Wireshark локально для установки удаленного живого канала pcap с использованием plink stdout> wireshark stdin.

Я решил использовать cmd.exe для вызова plink / wireshark, так как нюансы конвейера при вызове внешних команд в powershell меня победили, хотя я счастлив, что мне показали другой способ сделать это.

Мне нужно вызвать команду plink / wireshark следующим образом:

"C:\Program Files\PuTTY\plink.exe" -batch -l root -pw PASSWORD -P 22 remotehost.com pktcap-uw --switchport 1112222 -o - |
    "C:\Program Files\Wireshark\wireshark.exe" -o "gui.window_title:VMName - Network adapter X - 1112222 - Portgroupname - VMHost" -k -i -

Код для создания вышеуказанной команды выглядит следующим образом:

$command = "`"$($PlinkPath)`" -batch -l $($ESXiRootCredential.Username) -pw $($ESXiRootCredential.GetNetworkCredential().password) -P 22 $($currentHost.Name) pktcap-uw --switchport $($currentvNICSwitchPortInfo.portID) -o - `| `"$($WireSharkPath)`" -o `"gui.window_title:$($currentvNICSwitchPortInfo.VM.Name) - $($currentvNICSwitchPortInfo.Name) - $($currentvNICSwitchPortInfo.PortID) - $($currentvNICSwitchPortInfo.PortgroupName) - $($currentvNICSwitchPortInfo.VMHost.Name)`" -k -i - &"

Эта часть сценария работает. Проблема заключается в вызове $command в cmd.exe с использованием powershell, но асинхронно, так что если я передам несколько vNIC, цикл for вызовет cmd.exe с командой $, а затем сразу же перейдет к выполнению того же для следующего vNIC, и поэтому на.

Я пробовал комбинацию нескольких методов:

Invoke-Command
Invoke-Expression
& cmd.exe /c
и т.д.

#Requires -Modules VMware.VimAutomation.Common

function New-RemoteVMvNICPacketCapture {
    [CmdletBinding()]
    Param(
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [VMware.VimAutomation.Types.NetworkAdapter[]]$vNIC,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$true )]
        [System.Management.Automation.PSCredential]$ESXiRootCredential,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$false)]
        [String]$WireSharkPath = 'C:\Program Files\Wireshark\wireshark.exe',

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$false)]
        [String]$PlinkPath = 'C:\Program Files\PuTTY\plink.exe'
    )

    Begin {
        $ErrorActionPreference = 'Stop'
        Write-Debug $MyInvocation.MyCommand.Name

        # Import function needed to get switch port ID(s)
        try {
            . "$PSScriptRoot\Get-VMvNICSwitchPortInfo.ps1"
        } catch {
            Write-Error "Unable to import function Get-VMvNICSwitchPortInfo, exiting!"
            break
        }
    }

    Process {
        try {
            # Get unique list of ESXi hosts from supplied vNICs(s)
            $uniqueESXiHosts = $vNIC |
                               Sort-Object -Property {$_.Parent.VMHost} |
                               Select-Object @{N="VMHost";E={$_.Parent.VMHost}} -Unique

            foreach ($ESXiHost in $uniqueESXiHosts) {
                # Get VMHost handle from current array index
                $currentHost = $ESXiHost.VMHost

                $sshService = $currentHost |
                              Get-VMHostService |
                              Where-Object {$_.Key -eq 'TSM-SSH'}

                if ($sshService.Running -ne $true) {
                    $sshService | Start-VMHostService
                }

                if (-not (Test-NetConnection -Port 22 -ComputerName $currentHost)) {
                    Write-Error "Unable to connect to \"$currentHost\" on port 22. Skipping the following VMs: " +  + ([String]::Join(', ',($vNIC | Where-Object {$_.Parent.VMHost -eq $currentHost} | Sort-Object -Property Parent).Parent.Name))
                    break
                } else {
                    Write-Host "Able to connect to $currentHost on port 22"
                }

                foreach ($vnic in ($vNIC | Where-Object {$_.Parent.VMHost -eq $currentHost} | Sort-Object -Property Parent)) {
                    $currentvNICSwitchPortInfo = $vnic | Get-VMvNICSwitchPortInfo

                    # Create remote wireshark capture session
                    $command = "`"$($PlinkPath)`" -batch -l $($ESXiRootCredential.Username) -pw $($ESXiRootCredential.GetNetworkCredential().password) -P 22 $($currentHost.Name) pktcap-uw --switchport $($currentvNICSwitchPortInfo.portID) -o - `| `"$($WireSharkPath)`" -o `"gui.window_title:$($currentvNICSwitchPortInfo.VM.Name) - $($currentvNICSwitchPortInfo.Name) - $($currentvNICSwitchPortInfo.PortID) - $($currentvNICSwitchPortInfo.PortgroupName) - $($currentvNICSwitchPortInfo.VMHost.Name)`" -k -i - &"

                    Write-Host $command -ForegroundColor Yellow

                    Invoke-Command -ScriptBlock {& cmd.exe /c "$($command)"}
                }    

                if ($sshService.Running -eq $false) {
                    $sshService | Stop-VMHostService -Confirm:$false
                }
            }
        } catch [Exception] {
            Write-Host $_.Exception.Message
            throw "Unable to establish remote pcap"
        }
    }

    End {}
}

Это должно порождать несколько экземпляров plink / wireshark один за другим без необходимости ждать. В настоящий момент он порождает первый, а затем ожидает закрытия Wireshark (и связанного с ним процесса cmd.exe), прежде чем продолжить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...