powershell - 使用 PowerShell 调用 cmd.exe,异步生成多个实例。不要等待 cmd.exe 关闭
问题描述
我正在编写一个函数,它将为 ESXi 主机上的虚拟机建立远程 Wireshark 数据包捕获会话。
该函数将获得一个 vNIC 对象数组,然后根据每个 vNIC 的信息,将在本地使用 plink 和 Wireshark 使用 plink stdout > wireshark 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 - &"
这部分脚本有效。$command
问题在于使用 powershell 但异步调用,cmd.exe
因此如果我传入多个 vNIC,for 循环将cmd.exe
使用 $command 生成,然后立即继续为下一个 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进程),然后再继续。