#requires -Version 3
param($Work)
# restart PowerShell with -noexit, the same script, and 1
if ((!$Work) -and ($host.name -eq 'ConsoleHost'))
{
powershell.exe -noexit -file $MyInvocation.MyCommand.Path 1
return
}
# Set Variables
$SyncHash = [hashtable]::Synchronized(@{})
$SyncHash.Host = $host
$SyncHash.IperfFolder = $PSScriptRoot + '\Bin'
# UI Runspace
$UiRunspace = [runspacefactory]::CreateRunspace()
$UiRunspace.ApartmentState = 'STA'
$UiRunspace.ThreadOptions = 'ReuseThread'
$UiRunspace.Open()
$UiRunspace.SessionStateProxy.SetVariable('syncHash',$SyncHash)
# UI Script
$UiPowerShell = [PowerShell]::Create().AddScript(
{
$SyncHash.host.ui.WriteVerboseLine(' UI Script Started')
trap {$SyncHash.host.ui.WriteErrorLine("$_`nError was in Line {0}`n{1}" -f ($_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.Line))}
function Write-Status
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true, Position=0)]
[String]$Text,
[Parameter(Mandatory=$true, Position=1)]
[String]$Colore
)
$syncHash.Form.Dispatcher.invoke([action]{
if (![string]::IsNullOrWhitespace([System.Windows.Documents.TextRange]::new($SyncHash.IperfJobOutputTextBox.Document.ContentStart, $SyncHash.IperfJobOutputTextBox.Document.ContentEnd).Text))
{
$SyncHash.IperfJobOutputTextBox.AppendText("`r")
}
$TextRange = [System.Windows.Documents.TextRange]::new($SyncHash.IperfJobOutputTextBox.Document.ContentEnd, $SyncHash.IperfJobOutputTextBox.Document.ContentEnd)
$TextRange.Text = $Text
$TextRange.ApplyPropertyValue([System.Windows.Documents.TextElement]::ForegroundProperty, [System.Windows.Media.Brushes]::$Colore)
$SyncHash.IperfJobOutputTextBox.ScrollToEnd()
})
}
function Start-Iperf
{
$SyncHash.host.ui.WriteVerboseLine('Start-Iperf')
if ($SyncHash.IperfJobMonitorRunspace.RunspaceStateInfo.State -eq 'Opened')
{
Write-Status -Text 'Iperf Already Running' -Colore 'Orange'
}
else
{
#Get-Job | Remove-Job -Force
#$SyncHash.Remove('IperfJob')
# Iperf Job Monitor with Register-ObjectEvent in Runspace
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$InitialSessionState.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Stop-Iperf', (Get-Content Function:\Stop-Iperf)))
$InitialSessionState.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Write-Status', (Get-Content Function:\Write-Status)))
$SyncHash.IperfJobMonitorRunspace = [runspacefactory]::CreateRunspace($InitialSessionState)
$SyncHash.IperfJobMonitorRunspace.ApartmentState = 'STA'
$SyncHash.IperfJobMonitorRunspace.ThreadOptions = 'ReuseThread'
$SyncHash.IperfJobMonitorRunspace.Open()
$SyncHash.IperfJobMonitorRunspace.SessionStateProxy.SetVariable('syncHash',$SyncHash)
$SyncHash.IperfJobMonitorRunspace.SessionStateProxy.SetVariable('CsvFilePath',$SyncHash.CsvFilePathTextBox.Text)
$SyncHash.IperfJobMonitorRunspace.SessionStateProxy.SetVariable('Command',$SyncHash.CommandTextBox.Text)
$SyncHash.IperfJobMonitorRunspace.SessionStateProxy.SetVariable('IperfVersion',$IperfVersion)
$SyncHash.IperfJobMonitorRunspace.SessionStateProxy.SetVariable('IperfExe',$IperfExe)
$SyncHash.IperfJobMonitorPowerShell = [PowerShell]::Create().AddScript(
{
trap {$SyncHash.host.ui.WriteErrorLine("$_`nError was in Line {0}`n{1}" -f ($_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.Line))}
trap [System.Management.Automation.PipelineStoppedException] {$SyncHash.host.ui.WriteVerboseLine($_)}
$SyncHash.host.ui.WriteVerboseLine('Start-Iperf Running')
Set-Location -Path $SyncHash.IperfFolder
try
{
$ErrorActionPreferenceOrg = $ErrorActionPreference
if ($IperfVersion -eq 2)
{
'Time,localIp,localPort,RemoteIp,RemotePort,Id,Interval,Transfer,Bandwidth' | Out-File -FilePath $CsvFilePath
Write-Status -Text ((Invoke-Expression -Command "$IperfExe -v") 2>&1) -Colore 'Blue'
$ErrorActionPreference = 'stop'
Invoke-Expression -Command $Command | Out-File -FilePath $CsvFilePath -Append
}
else
{
Set-Content -Path $CsvFilePath -Value $null
#Write-Status -Text ((Invoke-Expression -Command "$IperfExe -v") -join ' ') -Colore 'Blue'
Invoke-Expression -Command $Command
if ($ErrorOut = Get-Content -Tail 5 -Path $CsvFilePath | Select-String -Pattern 'iperf3: error')
{
Write-Error -Message $ErrorOut -ErrorAction Stop
}
}
}
catch
{
Write-Status -Text $_ -Colore 'Red'
Stop-Iperf
}
$ErrorActionPreference = $ErrorActionPreferenceOrg
Write-Status -Text 'Iperf Finished' -Colore 'Green'
Stop-Iperf
#Get-EventSubscriber | Unregister-Event
#$SyncHash.Remove('IperfJobMonitor')
})
$SyncHash.IperfJobMonitorPowerShell.Runspace = $SyncHash.IperfJobMonitorRunspace
$SyncHash.IperfJobMonitorHandle = $SyncHash.IperfJobMonitorPowerShell.BeginInvoke()
}
}
function Stop-Iperf
{
$SyncHash.host.ui.WriteVerboseLine('Stop-Iperf')
if ($SyncHash.IperfJobMonitorRunspace.RunspaceStateInfo.State -eq 'Opened')
{
$SyncHash.host.ui.WriteVerboseLine('Stop-Iperf Running')
#$SyncHash.IperfJobMonitorPowerShell.EndInvoke($SyncHash.IperfJobMonitorHandle)
$SyncHash.IperfJobMonitorRunspace.Close()
$SyncHash.IperfJobMonitorPowerShell.Dispose()
}
}
function Start-Analyzer
{
$SyncHash.host.ui.WriteVerboseLine('Start-Analyzer')
if (!(Test-Path -Path $SyncHash.CsvFilePathTextBox.Text))
{
Write-Status -Text 'File not found' -Colore 'Red'
}
elseif ($SyncHash.AnalyzerRunspace.RunspaceStateInfo.State -eq 'Opened')
{
Write-Status -Text 'Analyzer Already Running' -Colore 'Orange'
}
else
{
# Analyzer Runspace
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$InitialSessionState.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Stop-Analyzer', (Get-Content Function:\Stop-Analyzer)))
$InitialSessionState.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Write-Status', (Get-Content Function:\Write-Status)))
$SyncHash.AnalyzerRunspace = [runspacefactory]::CreateRunspace($InitialSessionState)
$SyncHash.AnalyzerRunspace.ApartmentState = 'STA'
$SyncHash.AnalyzerRunspace.ThreadOptions = 'ReuseThread'
$SyncHash.AnalyzerRunspace.Open()
$SyncHash.AnalyzerRunspace.SessionStateProxy.SetVariable('syncHash',$SyncHash)
$SyncHash.AnalyzerRunspace.SessionStateProxy.SetVariable('CsvFilePath',$SyncHash.CsvFilePathTextBox.Text)
$SyncHash.AnalyzerRunspace.SessionStateProxy.SetVariable('LastX',$SyncHash.LastXTextBox.Text)
$SyncHash.AnalyzerRunspace.SessionStateProxy.SetVariable('IperfVersion',$IperfVersion)
$SyncHash.AnalyzerPowerShell = [powershell]::Create()
$SyncHash.AnalyzerPowerShell.Runspace = $SyncHash.AnalyzerRunspace
$null = $SyncHash.AnalyzerPowerShell.AddScript($AnalyzerScript)
$SyncHash.AnalyzerHandle = $SyncHash.AnalyzerPowerShell.BeginInvoke()
}
}
# Analyzer Runspace Script
$AnalyzerScript =
{
$SyncHash.host.ui.WriteVerboseLine('Start-Analyzer Running')
trap {$SyncHash.host.ui.WriteErrorLine("$_`nError was in Line {0}`n{1}" -f ($_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.Line))}
trap [System.Management.Automation.PipelineStoppedException] {$SyncHash.host.ui.WriteVerboseLine($_)}
$First = $true
$Header = $null
$AnalyzerDataLength = 0
$ChartDataAction0 = [Action]{
$SyncHash.Chart.Series['Bandwidth (Mbits/sec)'].Points.Clear()
$SyncHash.Chart.Series['Transfer (MBytes)'].Points.Clear()
$SyncHash.host.ui.WriteVerboseLine('Clear Data: ' + ($SyncHash.Chart.Series['Transfer (MBytes)'].Points.Count | Out-String))
}
$SyncHash.Chart.Invoke($ChartDataAction0)
Get-Content -Path $CsvFilePath -ReadCount 0 -Wait | ForEach-Object {
trap {$SyncHash.host.ui.WriteErrorLine("$_`nError was in Line {0}`n{1}" -f ($_.InvocationInfo.ScriptLineNumber, $_.InvocationInfo.Line))}
#$SyncHash.host.ui.WriteVerboseLine('Loop Data: ' + ($_ | Out-String)) ###
$AnalyzerData = New-Object -TypeName System.Collections.Generic.List[System.Object]
if ($IperfVersion -eq 2)
{
foreach ($Line in $_)
{
if ($Line -like '*Bandwidth*')
{
$Header = $Line -split ','
}
else
{
if ($First -and !$Header)
{
Write-Status -Text 'CSV Error' -Colore 'Red'
Stop-Analyzer
}
else
{
$First = $false
}
$CsvLine = $Line | ConvertFrom-Csv -Header $Header
$CsvLine.Bandwidth = $CsvLine.Bandwidth /1Mb
$CsvLine.Transfer = $CsvLine.Transfer /1Mb
if (!($CsvLine.Interval).StartsWith('0.0-') -or ($CsvLine.Interval -eq '0.0-1.0'))
{
$AnalyzerData.add($CsvLine)
}
else
{
$SyncHash.host.ui.WriteVerboseLine('Remove Total Line: ' + $CsvLine.Time)
}
}
}
}
else
{
$Csv = $_ | Where-Object {$_ -match '\[...\]'}
#$Csv = $a | Select-String -Pattern '\[...\]'
foreach ($Line in $Csv)
{
$Line = $Line -replace '[][]'
if ($Line -like ' ID *')
{
$Header = ($Line = $Line -replace 'Total Datagram','Total-Datagram' -replace 'Lost/Total Datagrams','Lost/Total-Datagrams') -split '\s+' | Where-Object {$_}
$HeaderIndex = @()
foreach ($Head in $Header)
{
$HeaderIndex += $Line.IndexOf($Head)
}
}
elseif ($Header -and $Line -notlike '*connected to*' -and $Line -notlike '*sender*' -and $Line -notlike '*receiver*' -and $Line -cnotlike '*datagrams*')
{
$i=0
$CsvLine = New-Object System.Object
foreach ($Head in $Header)
{
if ($i -lt $HeaderIndex.Length-1)
{
$Cell = $Line.Substring($HeaderIndex[$i],$HeaderIndex[$i + 1] - $HeaderIndex[$i])
}
else
{
$Cell = $Line.Substring($HeaderIndex[$i])
}
if ($Head -eq 'Transfer')
{
$TransferData = $Cell.Trim() -split '\s+'
if ($TransferData[1] -eq 'KBytes')
{
$Cell = $TransferData[0] /1kb
}
elseif ($TransferData[1] -eq 'GBytes')
{
$Cell = $TransferData[0] *1kb
}
}
$i++
Add-Member -InputObject $CsvLine -NotePropertyName $Head -NotePropertyValue ("$Cell".Trim() -split '\s+')[0]
}
$AnalyzerData.add($CsvLine)
}
}
}
if ($AnalyzerData.Count -gt $LastX -and $LastX -gt 0)
{
$SyncHash.host.ui.WriteVerboseLine('Trim Data 1')
$AnalyzerData = $AnalyzerData.GetRange($AnalyzerData.Count - $LastX, $LastX)
}
$SyncHash.host.ui.WriteVerboseLine('New Points: ' + $AnalyzerData.Count)
if ($AnalyzerData.Count -gt 0)
{
if ($AnalyzerDataLength -eq 0 -and $AnalyzerData.Count -gt 1)
{
$ChartDataAction1 = [Action]{
$SyncHash.Chart.Series['Bandwidth (Mbits/sec)'].Points.DataBindXY($AnalyzerData.Interval, $AnalyzerData.Bandwidth)
$SyncHash.Chart.Series['Transfer (MBytes)'].Points.DataBindXY($AnalyzerData.Interval, $AnalyzerData.Transfer)
$SyncHash.host.ui.WriteVerboseLine('Show Data: ' + ($SyncHash.Chart.Series['Transfer (MBytes)'].Points.Count | Out-String))
}
$SyncHash.Chart.Invoke($ChartDataAction1)
}
else
{
$ChartDataAction2 = [Action]{
while ($AnalyzerDataLength + $AnalyzerData.Count -gt $LastX -and $LastX -gt 0)
{
$SyncHash.Chart.Series['Bandwidth (Mbits/sec)'].Points.RemoveAt(0)
$SyncHash.Chart.Series['Transfer (MBytes)'].Points.RemoveAt(0)
$Global:AnalyzerDataLength --
}
foreach ($Point in $AnalyzerData)
{
$SyncHash.Chart.Series['Bandwidth (Mbits/sec)'].Points.AddXY($Point.Interval, $Point.Bandwidth)
$SyncHash.Chart.Series['Transfer (MBytes)'].Points.AddXY($Point.Interval, $Point.Transfer)
$SyncHash.host.ui.WriteVerboseLine('Add Data Point: ' + ($SyncHash.Chart.Series['Transfer (MBytes)'].Points.Count | Out-String))
}
}
$SyncHash.Chart.Invoke($ChartDataAction2)
}
$AnalyzerDataLength += $AnalyzerData.Count
}
else
{
$SyncHash.host.ui.WriteVerboseLine('Point Skipped')
}
$SyncHash.host.ui.WriteVerboseLine('Analyzer Loop End: ' + ($AnalyzerDataLength | Out-String))
}
}
function Stop-Analyzer
{
$SyncHash.host.ui.WriteVerboseLine('Stop-Analyzer')
if ($SyncHash.AnalyzerRunspace.RunspaceStateInfo.State -eq 'Opened')
{
$SyncHash.host.ui.WriteVerboseLine('Stop-Analyzer Running')
$SyncHash.AnalyzerRunspace.Close()
$SyncHash.AnalyzerPowerShell.Dispose()
}
}
function Set-IperfCommand
{
if ($SyncHash.ClientRadio.IsChecked)
{
$IperfMode = ' -c ' + $SyncHash.IpTextBox.Text
$SyncHash.IpTextBox.IsEnabled = $true
$IperfTime = ' -t ' + $SyncHash.TimeTextBox.Text
$SyncHash.TimeTextBox.IsEnabled = $true
}
else
{
$IperfMode = ' -s'
$SyncHash.IpTextBox.IsEnabled = $false
$IperfTime = $null
$SyncHash.TimeTextBox.IsEnabled = $false
}
if ($SyncHash.Version2Radio.IsChecked)
{
$IperfVersionParams = ' -y c'
$Global:IperfVersion = 2
$Global:IperfExe = '.\iperf.exe'
}
else
{
$IperfVersionParams = ' -f m --logfile ' + $SyncHash.CsvFilePathTextBox.Text
$Global:IperfVersion = 3
$Global:IperfExe = '.\iperf3.exe'
}
$SyncHash.CommandTextBox.Text = $IperfExe + $IperfMode + $IperfTime + $IperfVersionParams + ' -i 1'
}
# UI
$InputXml = @"
"@
$InputXml = $InputXml -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^