使用PowerShell调用cmd.exe,异步生成多个实例。不要等待cmd.exe关闭

时间:2019-05-06 07:13:44

标签: powershell asynchronous cmd

我正在编写一个功能,用于为ESXi主机上的VM建立远程Wireshark数据包捕获会话。

此功能将被分配一个vNIC对象数组,然后基于每个vNIC的信息,将使用plink和Wireshark在本地使用plink stdout> wirehark stdin建立远程实时pcap提要。

我决定使用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 - &"

脚本的这一部分有效。问题是使用Powershell在$command中调用cmd.exe,但异步进行,因此,如果我传入多个vNIC,for循环将使用$ command生成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进程),然后继续。

0 个答案:

没有答案