我正在编写一个功能,用于为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进程),然后继续。