diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs
index 19974c8891b..043cf0432f7 100644
--- a/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs
+++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/TestConnectionCommand.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Internal;
using System.Net;
@@ -16,134 +17,126 @@ namespace Microsoft.PowerShell.Commands
///
/// The implementation of the "Test-Connection" cmdlet.
///
- [Cmdlet(VerbsDiagnostic.Test, "Connection", DefaultParameterSetName = ParameterSetPingCount, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135266")]
- [OutputType(typeof(PingReport), ParameterSetName = new string[] { ParameterSetPingCount })]
- [OutputType(typeof(PingReply), ParameterSetName = new string[] { ParameterSetPingContinues, ParameterSetDetectionOfMTUSize })]
- [OutputType(typeof(bool), ParameterSetName = new string[] { ParameterSetPingCount, ParameterSetPingContinues, ParameterSetConnectionByTCPPort })]
- [OutputType(typeof(Int32), ParameterSetName = new string[] { ParameterSetDetectionOfMTUSize })]
- [OutputType(typeof(TraceRouteReply), ParameterSetName = new string[] { ParameterSetTraceRoute })]
- public class TestConnectionCommand : PSCmdlet
+ [Cmdlet(VerbsDiagnostic.Test, "Connection", DefaultParameterSetName = PingSet,
+ HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135266")]
+ [OutputType(typeof(PingStatus), ParameterSetName = new[] { PingSet, RepeatPingSet })]
+ [OutputType(typeof(TraceStatus), ParameterSetName = new[] { TraceRouteSet })]
+ [OutputType(typeof(PingMtuStatus), ParameterSetName = new[] { MtuSizeDetectSet })]
+ [OutputType(typeof(bool), ParameterSetName = new[] { PingSet, RepeatPingSet, TcpPortSet })]
+ [OutputType(typeof(int), ParameterSetName = new[] { MtuSizeDetectSet })]
+ public class TestConnectionCommand : PSCmdlet, IDisposable
{
- private const string ParameterSetPingCount = "PingCount";
- private const string ParameterSetPingContinues = "PingContinues";
- private const string ParameterSetTraceRoute = "TraceRoute";
- private const string ParameterSetConnectionByTCPPort = "ConnectionByTCPPort";
- private const string ParameterSetDetectionOfMTUSize = "DetectionOfMTUSize";
+ private const string PingSet = "Ping";
+ private const string RepeatPingSet = "RepeatPing";
+ private const string TraceRouteSet = "TraceRoute";
+ private const string TcpPortSet = "TcpPort";
+ private const string MtuSizeDetectSet = "MtuSizeDetect";
+ private const int DefaultMaxHops = 128;
+
+ private readonly Ping _sender = new Ping();
#region Parameters
///
- /// Do ping test.
+ /// Gets or sets the Ping parameter.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
public SwitchParameter Ping { get; set; } = true;
///
- /// Force using IPv4 protocol.
+ /// Gets or sets whether to force use of the IPv4 protocol.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- [Parameter(ParameterSetName = ParameterSetTraceRoute)]
- [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)]
- [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)]
+ [Parameter]
public SwitchParameter IPv4 { get; set; }
///
- /// Force using IPv6 protocol.
+ /// Gets or sets whether to force use of the IPv6 protocol.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- [Parameter(ParameterSetName = ParameterSetTraceRoute)]
- [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)]
- [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)]
+ [Parameter]
public SwitchParameter IPv6 { get; set; }
///
- /// Do reverse DNS lookup to get names for IP addresses.
+ /// Gets or sets whether to do reverse DNS lookup to get names for IP addresses.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- [Parameter(ParameterSetName = ParameterSetTraceRoute)]
- [Parameter(ParameterSetName = ParameterSetDetectionOfMTUSize)]
- [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)]
+ [Parameter]
public SwitchParameter ResolveDestination { get; set; }
///
- /// Source from which to do a test (ping, trace route, ...).
- /// The default is Local Host.
+ /// Gets or sets the source hostname from which to perform a test (ping, trace route, ...).
+ /// The default is localhost.
/// Remoting is not yet implemented internally in the cmdlet.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- [Parameter(ParameterSetName = ParameterSetTraceRoute)]
- [Parameter(ParameterSetName = ParameterSetConnectionByTCPPort)]
- public string Source { get; } = Dns.GetHostName();
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
+ [Parameter(ParameterSetName = TraceRouteSet)]
+ [Parameter(ParameterSetName = TcpPortSet)]
+ public string Source { get; set; } = Dns.GetHostName();
///
- /// The number of times the Ping data packets can be forwarded by routers.
- /// As gateways and routers transmit packets through a network,
- /// they decrement the Time-to-Live (TTL) value found in the packet header.
+ /// Gets or sets the number of times the Ping data packets can be forwarded by routers.
+ /// As gateways and routers transmit packets through a network, they decrement the Time-to-Live (TTL) value
+ /// found in the packet header.
/// The default (from Windows) is 128 hops.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- [Parameter(ParameterSetName = ParameterSetTraceRoute)]
- [ValidateRange(0, sMaxHops)]
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
+ [Parameter(ParameterSetName = TraceRouteSet)]
+ [ValidateRange(0, DefaultMaxHops)]
[Alias("Ttl", "TimeToLive", "Hops")]
- public int MaxHops { get; set; } = sMaxHops;
-
- private const int sMaxHops = 128;
+ public int MaxHops { get; set; } = DefaultMaxHops;
///
- /// Count of attempts.
+ /// Gets or sets the number of pings to attempt.
/// The default (from Windows) is 4 times.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
+ [Parameter(ParameterSetName = PingSet)]
[ValidateRange(ValidateRangeKind.Positive)]
public int Count { get; set; } = 4;
///
- /// Delay between attempts.
+ /// Gets or sets the delay between ping attempts.
/// The default (from Windows) is 1 second.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
[ValidateRange(ValidateRangeKind.Positive)]
public int Delay { get; set; } = 1;
///
- /// Buffer size to send.
+ /// Gets or sets the size of the buffer to send.
/// The default (from Windows) is 32 bites.
/// Max value is 65500 (limit from Windows API).
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
[Alias("Size", "Bytes", "BS")]
[ValidateRange(0, 65500)]
public int BufferSize { get; set; } = DefaultSendBufferSize;
///
- /// Don't fragment ICMP packages.
+ /// Gets or sets whether to prevent fragmentation of ICMP packages.
/// Currently CoreFX not supports this on Unix.
///
- [Parameter(ParameterSetName = ParameterSetPingCount)]
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
+ [Parameter(ParameterSetName = PingSet)]
+ [Parameter(ParameterSetName = RepeatPingSet)]
public SwitchParameter DontFragment { get; set; }
///
- /// Continue ping until user press Ctrl-C
- /// or Int.MaxValue threshold reached.
+ /// Gets or sets whether to ping the target endlessly, until the user presses Ctrl+C or the maximum threshold of
+ /// Int.MaxValue pings is reached.
///
- [Parameter(ParameterSetName = ParameterSetPingContinues)]
- public SwitchParameter Continues { get; set; }
+ [Parameter(Mandatory = true, ParameterSetName = RepeatPingSet)]
+ [Alias("Continues")]
+ public SwitchParameter Repeat { get; set; }
///
- /// Set short output kind ('bool' for Ping, 'int' for MTU size ...).
+ /// Gets or sets whether to return simplified output.
/// Default is to return typed result object(s).
+ /// When used with standard -Ping parameter set or -TraceRoute, a simple $true/$false value is returned.
///
- [Parameter()]
- public SwitchParameter Quiet;
+ [Parameter]
+ public SwitchParameter Quiet { get; set; }
///
/// Time-out value in seconds.
@@ -151,39 +144,41 @@ public class TestConnectionCommand : PSCmdlet
/// It is not the cmdlet timeout! It is a timeout for waiting one ping response.
/// The default (from Windows) is 5 second.
///
- [Parameter()]
+ [Parameter]
[ValidateRange(ValidateRangeKind.Positive)]
public int TimeoutSeconds { get; set; } = 5;
///
/// Destination - computer name or IP address.
///
- [Parameter(Mandatory = true,
- Position = 0,
- ValueFromPipeline = true,
- ValueFromPipelineByPropertyName = true)]
+ [Parameter(
+ Mandatory = true,
+ Position = 0,
+ ValueFromPipeline = true,
+ ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
[Alias("ComputerName")]
public string[] TargetName { get; set; }
///
- /// Detect MTU size.
+ /// Gets or sets whether to detect MTU size.
///
- [Parameter(Mandatory = true, ParameterSetName = ParameterSetDetectionOfMTUSize)]
- public SwitchParameter MTUSizeDetect { get; set; }
+ [Parameter(Mandatory = true, ParameterSetName = MtuSizeDetectSet)]
+ [Alias("MtuSizeDetect")]
+ public SwitchParameter DetectMtuSize { get; set; }
///
- /// Do traceroute test.
+ /// Gets or sets whether to perform a traceroute test.
///
- [Parameter(Mandatory = true, ParameterSetName = ParameterSetTraceRoute)]
+ [Parameter(Mandatory = true, ParameterSetName = TraceRouteSet)]
public SwitchParameter Traceroute { get; set; }
///
- /// Do tcp connection test.
+ /// Gets or sets whether to do a tcp connection test on the specified port.
///
[ValidateRange(0, 65535)]
- [Parameter(Mandatory = true, ParameterSetName = ParameterSetConnectionByTCPPort)]
- public int TCPPort { get; set; }
+ [Parameter(Mandatory = true, ParameterSetName = TcpPortSet)]
+ public int TcpPort { get; set; }
#endregion Parameters
@@ -192,13 +187,9 @@ public class TestConnectionCommand : PSCmdlet
///
protected override void BeginProcessing()
{
- base.BeginProcessing();
-
- switch (ParameterSetName)
+ if (ParameterSetName == RepeatPingSet)
{
- case ParameterSetPingContinues:
- Count = int.MaxValue;
- break;
+ Count = int.MaxValue;
}
}
@@ -211,17 +202,17 @@ protected override void ProcessRecord()
{
switch (ParameterSetName)
{
- case ParameterSetPingCount:
- case ParameterSetPingContinues:
+ case PingSet:
+ case RepeatPingSet:
ProcessPing(targetName);
break;
- case ParameterSetDetectionOfMTUSize:
+ case MtuSizeDetectSet:
ProcessMTUSize(targetName);
break;
- case ParameterSetTraceRoute:
+ case TraceRouteSet:
ProcessTraceroute(targetName);
break;
- case ParameterSetConnectionByTCPPort:
+ case TcpPortSet:
ProcessConnectionByTCPPort(targetName);
break;
}
@@ -230,29 +221,21 @@ protected override void ProcessRecord()
#region ConnectionTest
- private void ProcessConnectionByTCPPort(String targetNameOrAddress)
+ private void ProcessConnectionByTCPPort(string targetNameOrAddress)
{
- string resolvedTargetName = null;
- IPAddress targetAddress = null;
-
- if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress))
+ if (!InitProcessPing(targetNameOrAddress, out _, out IPAddress targetAddress))
{
return;
}
- WriteConnectionTestHeader(resolvedTargetName, targetAddress.ToString());
-
- TcpClient client = new TcpClient();
+ var client = new TcpClient();
try
{
- Task connectionTask = client.ConnectAsync(targetAddress, TCPPort);
- string targetString = targetAddress.ToString();
+ Task connectionTask = client.ConnectAsync(targetAddress, TcpPort);
for (var i = 1; i <= TimeoutSeconds; i++)
{
- WriteConnectionTestProgress(targetNameOrAddress, targetString, i);
-
Task timeoutTask = Task.Delay(millisecondsDelay: 1000);
Task.WhenAny(connectionTask, timeoutTask).Result.Wait();
@@ -277,273 +260,154 @@ private void ProcessConnectionByTCPPort(String targetNameOrAddress)
finally
{
client.Close();
- WriteConnectionTestFooter();
}
WriteObject(false);
}
- private void WriteConnectionTestHeader(string resolvedTargetName, string targetAddress)
- {
- _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.ConnectionTestStart, resolvedTargetName, targetAddress);
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- WriteProgress(record);
- }
-
- private void WriteConnectionTestProgress(string targetNameOrAddress, string targetAddress, int timeout)
- {
- var msg = StringUtil.Format(TestConnectionResources.ConnectionTestDescription,
- targetNameOrAddress,
- targetAddress,
- timeout);
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg);
- WriteProgress(record);
- }
-
- private void WriteConnectionTestFooter()
- {
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- record.RecordType = ProgressRecordType.Completed;
- WriteProgress(record);
- }
-
#endregion ConnectionTest
#region TracerouteTest
- private void ProcessTraceroute(String targetNameOrAddress)
+ private void ProcessTraceroute(string targetNameOrAddress)
{
- string resolvedTargetName = null;
- IPAddress targetAddress = null;
byte[] buffer = GetSendBuffer(BufferSize);
- if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress))
+ if (!InitProcessPing(targetNameOrAddress, out string resolvedTargetName, out IPAddress targetAddress))
{
return;
}
- WriteConsoleTraceRouteHeader(resolvedTargetName, targetAddress.ToString());
+ WriteVerbose(StringUtil.Format(
+ TestConnectionResources.TraceRouteStart,
+ resolvedTargetName,
+ targetAddress,
+ MaxHops));
- TraceRouteResult traceRouteResult = new TraceRouteResult(Source, targetAddress, resolvedTargetName);
+ int currentHop = 1;
+ int timeout = TimeoutSeconds * 1000;
+ string hostname;
- Int32 currentHop = 1;
- Ping sender = new Ping();
- PingOptions pingOptions = new PingOptions(currentHop, DontFragment.IsPresent);
- PingReply reply = null;
- Int32 timeout = TimeoutSeconds * 1000;
+ var pingOptions = new PingOptions(currentHop, DontFragment.IsPresent);
+
+ //var timer = new Stopwatch();
+ PingReply reply;
do
{
- TraceRouteReply traceRouteReply = new TraceRouteReply();
-
- pingOptions.Ttl = traceRouteReply.Hop = currentHop;
- currentHop++;
+ reply = null;
+ hostname = null;
+ pingOptions.Ttl = currentHop;
- // In the specific case we don't use 'Count' property.
+ // We don't allow -Count parameter for -TraceRoute.
// If we change 'DefaultTraceRoutePingCount' we should change 'ConsoleTraceRouteReply' resource string.
- for (int i = 1; i <= DefaultTraceRoutePingCount; i++)
+ for (uint i = 1; i <= DefaultTraceRoutePingCount; i++)
{
try
{
- reply = sender.Send(targetAddress, timeout, buffer, pingOptions);
+ reply = _sender.Send(targetAddress, timeout, buffer, pingOptions);
- traceRouteReply.PingReplies.Add(reply);
+ if (hostname == null
+ && ResolveDestination
+ && (reply.Status == IPStatus.Success || reply.Status == IPStatus.TtlExpired))
+ {
+ try
+ {
+ hostname = Dns.GetHostEntry(reply.Address).HostName;
+ }
+ catch
+ {
+ // Swallow hostname resolve exceptions and continue with trace
+ }
+ }
+
+ var status = new TraceStatus(
+ currentHop,
+ new PingStatus(
+ Source,
+ hostname,
+ reply,
+ pingOptions,
+ reply.RoundtripTime,
+ buffer.Length,
+ i),
+ Source,
+ resolvedTargetName ?? targetNameOrAddress,
+ targetAddress);
+
+ WriteObject(status);
+ //timer.Reset();
}
catch (PingException ex)
{
- string message = StringUtil.Format(TestConnectionResources.NoPingResult,
- resolvedTargetName,
- ex.Message);
- Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- resolvedTargetName);
+ string message = StringUtil.Format(
+ TestConnectionResources.NoPingResult,
+ resolvedTargetName,
+ ex.Message);
+ var pingException = new PingException(message, ex.InnerException);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ resolvedTargetName);
WriteError(errorRecord);
continue;
}
- catch
- {
- // Ignore host resolve exceptions.
- }
// We use short delay because it is impossible DoS with trace route.
Thread.Sleep(200);
}
- if (ResolveDestination && reply.Status == IPStatus.Success)
- {
- traceRouteReply.ReplyRouterName = Dns.GetHostEntry(reply.Address).HostName;
- }
-
- traceRouteReply.ReplyRouterAddress = reply.Address;
-
- WriteTraceRouteProgress(traceRouteReply);
-
- traceRouteResult.Replies.Add(traceRouteReply);
- } while (reply != null && currentHop <= sMaxHops && (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut));
-
- WriteTraceRouteFooter();
-
- if (Quiet.IsPresent)
- {
- WriteObject(currentHop <= sMaxHops);
- }
- else
- {
- WriteObject(traceRouteResult);
- }
- }
-
- private void WriteConsoleTraceRouteHeader(string resolvedTargetName, string targetAddress)
- {
- _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.TraceRouteStart, resolvedTargetName, targetAddress, MaxHops);
-
- WriteInformation(_testConnectionProgressBarActivity, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- WriteProgress(record);
- }
-
- private string _testConnectionProgressBarActivity;
- private static string[] s_PSHostTag = new string[] { "PSHOST" };
-
- private void WriteTraceRouteProgress(TraceRouteReply traceRouteReply)
- {
- string msg = string.Empty;
-
- if (traceRouteReply.PingReplies[2].Status == IPStatus.TtlExpired || traceRouteReply.PingReplies[2].Status == IPStatus.Success)
- {
- var routerAddress = traceRouteReply.ReplyRouterAddress.ToString();
- var routerName = traceRouteReply.ReplyRouterName ?? routerAddress;
- var roundtripTime0 = traceRouteReply.PingReplies[0].Status == IPStatus.TimedOut ? "*" : traceRouteReply.PingReplies[0].RoundtripTime.ToString();
- var roundtripTime1 = traceRouteReply.PingReplies[1].Status == IPStatus.TimedOut ? "*" : traceRouteReply.PingReplies[1].RoundtripTime.ToString();
- msg = StringUtil.Format(TestConnectionResources.TraceRouteReply,
- traceRouteReply.Hop, roundtripTime0, roundtripTime1, traceRouteReply.PingReplies[2].RoundtripTime.ToString(),
- routerName, routerAddress);
- }
- else
- {
- msg = StringUtil.Format(TestConnectionResources.TraceRouteTimeOut, traceRouteReply.Hop);
- }
-
- WriteInformation(msg, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg);
- WriteProgress(record);
- }
-
- private void WriteTraceRouteFooter()
- {
- WriteInformation(TestConnectionResources.TraceRouteComplete, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- record.RecordType = ProgressRecordType.Completed;
- WriteProgress(record);
- }
-
- ///
- /// The class contains an information about a trace route attempt.
- ///
- public class TraceRouteReply
- {
- internal TraceRouteReply()
- {
- PingReplies = new List(DefaultTraceRoutePingCount);
+ currentHop++;
}
+ while (reply != null
+ && currentHop <= MaxHops
+ && (reply.Status == IPStatus.TtlExpired || reply.Status == IPStatus.TimedOut));
- ///
- /// Number of current hop (router).
- ///
- public int Hop;
-
- ///
- /// List of ping replies for current hop (router).
- ///
- public List PingReplies;
-
- ///
- /// Router IP address.
- ///
- public IPAddress ReplyRouterAddress;
-
- ///
- /// Resolved router name.
- ///
- public string ReplyRouterName;
- }
+ WriteVerbose(TestConnectionResources.TraceRouteComplete);
- ///
- /// The class contains an information about the source, the destination and trace route results.
- ///
- public class TraceRouteResult
- {
- internal TraceRouteResult(string source, IPAddress destinationAddress, string destinationHost)
+ if (Quiet.IsPresent)
{
- Source = source;
- DestinationAddress = destinationAddress;
- DestinationHost = destinationHost;
- Replies = new List();
+ WriteObject(currentHop <= MaxHops);
}
-
- ///
- /// Source from which to trace route.
- ///
- public string Source { get; }
-
- ///
- /// Destination to which to trace route.
- ///
- public IPAddress DestinationAddress { get; }
-
- ///
- /// Destination to which to trace route.
- ///
- public string DestinationHost { get; }
-
- ///
- ///
- public List Replies { get; }
}
#endregion TracerouteTest
#region MTUSizeTest
- private void ProcessMTUSize(String targetNameOrAddress)
+ private void ProcessMTUSize(string targetNameOrAddress)
{
PingReply reply, replyResult = null;
- string resolvedTargetName = null;
- IPAddress targetAddress = null;
-
- if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress))
+ if (!InitProcessPing(targetNameOrAddress, out _, out IPAddress targetAddress))
{
return;
}
- WriteMTUSizeHeader(resolvedTargetName, targetAddress.ToString());
-
- // Cautious! Algorithm is sensitive to changing boundary values.
+ // Caution! Algorithm is sensitive to changing boundary values.
int HighMTUSize = 10000;
int CurrentMTUSize = 1473;
int LowMTUSize = targetAddress.AddressFamily == AddressFamily.InterNetworkV6 ? 1280 : 68;
- Int32 timeout = TimeoutSeconds * 1000;
+ int timeout = TimeoutSeconds * 1000;
try
{
- Ping sender = new Ping();
- PingOptions pingOptions = new PingOptions(MaxHops, true);
+ var pingOptions = new PingOptions(MaxHops, true);
int retry = 1;
+ int pingCount = 0;
while (LowMTUSize < (HighMTUSize - 1))
{
+ pingCount++;
byte[] buffer = GetSendBuffer(CurrentMTUSize);
- WriteMTUSizeProgress(CurrentMTUSize, retry);
-
- WriteDebug(StringUtil.Format("LowMTUSize: {0}, CurrentMTUSize: {1}, HighMTUSize: {2}", LowMTUSize, CurrentMTUSize, HighMTUSize));
+ WriteVerbose(StringUtil.Format(
+ TestConnectionResources.MtuSizeDetectDebug,
+ LowMTUSize,
+ CurrentMTUSize,
+ HighMTUSize));
- reply = sender.Send(targetAddress, timeout, buffer, pingOptions);
+ reply = _sender.Send(targetAddress, timeout, buffer, pingOptions);
// Cautious! Algorithm is sensitive to changing boundary values.
if (reply.Status == IPStatus.PacketTooBig)
@@ -562,14 +426,16 @@ private void ProcessMTUSize(String targetNameOrAddress)
// Target host don't reply - try again up to 'Count'.
if (retry >= Count)
{
- string message = StringUtil.Format(TestConnectionResources.NoPingResult,
- targetAddress,
- reply.Status.ToString());
- Exception pingException = new System.Net.NetworkInformation.PingException(message);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- targetAddress);
+ string message = StringUtil.Format(
+ TestConnectionResources.NoPingResult,
+ targetAddress,
+ reply.Status.ToString());
+ var pingException = new PingException(message);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ targetAddress);
WriteError(errorRecord);
return;
}
@@ -589,129 +455,86 @@ private void ProcessMTUSize(String targetNameOrAddress)
catch (PingException ex)
{
string message = StringUtil.Format(TestConnectionResources.NoPingResult, targetAddress, ex.Message);
- Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- targetAddress);
+ var pingException = new PingException(message, ex.InnerException);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ targetAddress);
WriteError(errorRecord);
return;
}
- WriteMTUSizeFooter();
-
if (Quiet.IsPresent)
{
WriteObject(CurrentMTUSize);
}
else
{
- var res = PSObject.AsPSObject(replyResult);
-
- PSMemberInfo sourceProperty = new PSNoteProperty("Source", Source);
- res.Members.Add(sourceProperty);
- PSMemberInfo destinationProperty = new PSNoteProperty("Destination", targetNameOrAddress);
- res.Members.Add(destinationProperty);
- PSMemberInfo mtuSizeProperty = new PSNoteProperty("MTUSize", CurrentMTUSize);
- res.Members.Add(mtuSizeProperty);
- res.TypeNames.Insert(0, "PingReply#MTUSize");
-
- WriteObject(res);
+ WriteObject(new PingMtuStatus(Source, targetNameOrAddress, replyResult));
}
}
- private void WriteMTUSizeHeader(string resolvedTargetName, string targetAddress)
- {
- _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.MTUSizeDetectStart,
- resolvedTargetName,
- targetAddress,
- BufferSize);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- WriteProgress(record);
- }
-
- private void WriteMTUSizeProgress(int currentMTUSize, int retry)
- {
- var msg = StringUtil.Format(TestConnectionResources.MTUSizeDetectDescription, currentMTUSize, retry);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg);
- WriteProgress(record);
- }
-
- private void WriteMTUSizeFooter()
- {
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- record.RecordType = ProgressRecordType.Completed;
- WriteProgress(record);
- }
-
#endregion MTUSizeTest
#region PingTest
- private void ProcessPing(String targetNameOrAddress)
+ private void ProcessPing(string targetNameOrAddress)
{
- string resolvedTargetName = null;
- IPAddress targetAddress = null;
-
- if (!InitProcessPing(targetNameOrAddress, out resolvedTargetName, out targetAddress))
+ if (!InitProcessPing(targetNameOrAddress, out string resolvedTargetName, out IPAddress targetAddress))
{
return;
}
- if (!Continues.IsPresent)
+ if (!Repeat.IsPresent)
{
- WritePingHeader(resolvedTargetName, targetAddress.ToString());
+ WriteVerbose(StringUtil.Format(
+ TestConnectionResources.PingStart,
+ resolvedTargetName,
+ targetAddress,
+ BufferSize));
}
bool quietResult = true;
byte[] buffer = GetSendBuffer(BufferSize);
- Ping sender = new Ping();
- PingOptions pingOptions = new PingOptions(MaxHops, DontFragment.IsPresent);
- PingReply reply = null;
- PingReport pingReport = new PingReport(Source, resolvedTargetName);
- Int32 timeout = TimeoutSeconds * 1000;
- Int32 delay = Delay * 1000;
+ PingReply reply;
+ var pingOptions = new PingOptions(MaxHops, DontFragment.IsPresent);
+ int timeout = TimeoutSeconds * 1000;
+ int delay = Delay * 1000;
- for (int i = 1; i <= Count; i++)
+ for (uint i = 1; i <= Count; i++)
{
try
{
- reply = sender.Send(targetAddress, timeout, buffer, pingOptions);
+ reply = _sender.Send(targetAddress, timeout, buffer, pingOptions);
}
catch (PingException ex)
{
- string message = StringUtil.Format(TestConnectionResources.NoPingResult, resolvedTargetName, ex.Message);
- Exception pingException = new System.Net.NetworkInformation.PingException(message, ex.InnerException);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- resolvedTargetName);
+ string message = StringUtil.Format(
+ TestConnectionResources.NoPingResult,
+ resolvedTargetName,
+ ex.Message);
+ var pingException = new PingException(message, ex.InnerException);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ resolvedTargetName);
WriteError(errorRecord);
quietResult = false;
continue;
}
- if (Continues.IsPresent)
+ if (Quiet.IsPresent)
{
- WriteObject(reply);
+ // Return 'true' only if all pings have completed successfully.
+ quietResult &= reply.Status == IPStatus.Success;
}
else
{
- if (Quiet.IsPresent)
- {
- // Return 'true' only if all pings have completed successfully.
- quietResult &= reply.Status == IPStatus.Success;
- }
- else
- {
- pingReport.Replies.Add(reply);
- }
-
- WritePingProgress(reply);
+ WriteObject(new PingStatus(Source, resolvedTargetName, reply, i));
}
// Delay between ping but not after last ping.
@@ -721,103 +544,27 @@ private void ProcessPing(String targetNameOrAddress)
}
}
- if (!Continues.IsPresent)
+ if (!Repeat.IsPresent)
{
- WritePingFooter();
+ WriteVerbose(TestConnectionResources.PingComplete);
}
if (Quiet.IsPresent)
{
WriteObject(quietResult);
}
- else
- {
- WriteObject(pingReport);
- }
- }
-
- private void WritePingHeader(string resolvedTargetName, string targetAddress)
- {
- _testConnectionProgressBarActivity = StringUtil.Format(TestConnectionResources.MTUSizeDetectStart,
- resolvedTargetName,
- targetAddress,
- BufferSize);
-
- WriteInformation(_testConnectionProgressBarActivity, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId,
- _testConnectionProgressBarActivity,
- ProgressRecordSpace);
- WriteProgress(record);
- }
-
- private void WritePingProgress(PingReply reply)
- {
- string msg = string.Empty;
- if (reply.Status != IPStatus.Success)
- {
- msg = TestConnectionResources.PingTimeOut;
- }
- else
- {
- msg = StringUtil.Format(TestConnectionResources.PingReply,
- reply.Address.ToString(),
- reply.Buffer.Length,
- reply.RoundtripTime,
- reply.Options?.Ttl);
- }
-
- WriteInformation(msg, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, msg);
- WriteProgress(record);
- }
-
- private void WritePingFooter()
- {
- WriteInformation(TestConnectionResources.PingComplete, s_PSHostTag);
-
- ProgressRecord record = new ProgressRecord(s_ProgressId, _testConnectionProgressBarActivity, ProgressRecordSpace);
- record.RecordType = ProgressRecordType.Completed;
- WriteProgress(record);
- }
-
- ///
- /// The class contains an information about the source, the destination and ping results.
- ///
- public class PingReport
- {
- internal PingReport(string source, string destination)
- {
- Source = source;
- Destination = destination;
- Replies = new List();
- }
-
- ///
- /// Source from which to ping.
- ///
- public string Source { get; }
-
- ///
- /// Destination to which to ping.
- ///
- public string Destination { get; }
-
- ///
- /// Ping results for every ping attempt.
- ///
- public List Replies { get; }
}
#endregion PingTest
- private bool InitProcessPing(String targetNameOrAddress, out string resolvedTargetName, out IPAddress targetAddress)
+ private bool InitProcessPing(
+ string targetNameOrAddress,
+ out string resolvedTargetName,
+ out IPAddress targetAddress)
{
- IPHostEntry hostEntry = null;
-
resolvedTargetName = targetNameOrAddress;
+ IPHostEntry hostEntry;
if (IPAddress.TryParse(targetNameOrAddress, out targetAddress))
{
if (ResolveDestination)
@@ -835,26 +582,27 @@ private bool InitProcessPing(String targetNameOrAddress, out string resolvedTarg
if (ResolveDestination)
{
resolvedTargetName = hostEntry.HostName;
- hostEntry = Dns.GetHostEntry(hostEntry.HostName);
}
}
catch (Exception ex)
{
- string message = StringUtil.Format(TestConnectionResources.NoPingResult,
- resolvedTargetName,
- TestConnectionResources.CannotResolveTargetName);
- Exception pingException = new System.Net.NetworkInformation.PingException(message, ex);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- resolvedTargetName);
+ string message = StringUtil.Format(
+ TestConnectionResources.NoPingResult,
+ resolvedTargetName,
+ TestConnectionResources.CannotResolveTargetName);
+ var pingException = new PingException(message, ex);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ resolvedTargetName);
WriteError(errorRecord);
return false;
}
- if (IPv6 || IPv4)
+ if (IPv6.IsPresent || IPv4.IsPresent)
{
- AddressFamily addressFamily = IPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
+ var addressFamily = IPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
foreach (var address in hostEntry.AddressList)
{
@@ -867,14 +615,16 @@ private bool InitProcessPing(String targetNameOrAddress, out string resolvedTarg
if (targetAddress == null)
{
- string message = StringUtil.Format(TestConnectionResources.NoPingResult,
- resolvedTargetName,
- TestConnectionResources.TargetAddressAbsent);
- Exception pingException = new System.Net.NetworkInformation.PingException(message, null);
- ErrorRecord errorRecord = new ErrorRecord(pingException,
- TestConnectionExceptionId,
- ErrorCategory.ResourceUnavailable,
- resolvedTargetName);
+ string message = StringUtil.Format(
+ TestConnectionResources.NoPingResult,
+ resolvedTargetName,
+ TestConnectionResources.TargetAddressAbsent);
+ var pingException = new PingException(message, null);
+ var errorRecord = new ErrorRecord(
+ pingException,
+ TestConnectionExceptionId,
+ ErrorCategory.ResourceUnavailable,
+ resolvedTargetName);
WriteError(errorRecord);
return false;
}
@@ -912,6 +662,232 @@ private byte[] GetSendBuffer(int bufferSize)
return sendBuffer;
}
+ ///
+ /// IDisposable implementation.
+ ///
+ public void Dispose()
+ {
+ _sender?.Dispose();
+ }
+
+ ///
+ /// The class contains an information about a trace route attempt.
+ ///
+ public class TraceStatus
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The hop number of this trace hop.
+ /// The PingStatus response from this trace hop.
+ /// The source computer name or IP address of the traceroute.
+ /// The target destination of the traceroute.
+ /// The target IPAddress of the overall traceroute.
+ internal TraceStatus(
+ int hop,
+ PingStatus status,
+ string source,
+ string destination,
+ IPAddress destinationAddress)
+ {
+ _status = status;
+ Hop = hop;
+ Source = source;
+ Target = destination;
+ TargetAddress = destinationAddress;
+ }
+
+ private readonly PingStatus _status;
+
+ ///
+ /// Gets the number of the current hop / router.
+ ///
+ public int Hop { get; }
+
+ ///
+ /// Gets the hostname of the current hop point.
+ ///
+ ///
+ public string Hostname
+ {
+ get => _status.Destination != "0.0.0.0"
+ ? _status.Destination
+ : null;
+ }
+
+ ///
+ /// Gets the sequence number of the ping in the sequence of pings to the hop point.
+ ///
+ public uint Ping { get => _status.Ping; }
+
+ ///
+ /// Gets the IP address of the current hop point.
+ ///
+ public IPAddress HopAddress { get => _status.Address; }
+
+ ///
+ /// Gets the latency values of each ping to the current hop point.
+ ///
+ public long Latency { get => _status.Latency; }
+
+ ///
+ /// Gets the status of the traceroute hop.
+ /// It is considered successful if the individual pings report either Success or TtlExpired.
+ ///
+ public IPStatus Status
+ {
+ get => _status.Status == IPStatus.TtlExpired
+ ? IPStatus.Success
+ : _status.Status;
+ }
+
+ ///
+ /// Gets the source address of the traceroute command.
+ ///
+ public string Source { get; }
+
+ ///
+ /// Gets the final destination hostname of the trace.
+ ///
+ public string Target { get; }
+
+ ///
+ /// Gets the final destination IP address of the trace.
+ ///
+ public IPAddress TargetAddress { get; }
+
+ ///
+ /// Gets the raw PingReply object received from the ping to this hop point.
+ ///
+ public PingReply Reply { get => _status.Reply; }
+
+ ///
+ /// Gets the PingOptions used to send the ping to the trace hop.
+ ///
+ public PingOptions Options { get => _status.Options; }
+ }
+
+ ///
+ /// The class contains information about the source, the destination and ping results.
+ ///
+ public class PingStatus
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// This constructor allows manually specifying the initial values for the cases where the PingReply
+ /// object may be missing some information, specifically in the instances where PingReply objects are
+ /// utilised to perform a traceroute.
+ ///
+ /// The source machine name or IP of the ping.
+ /// The destination machine name of the ping.
+ /// The response from the ping attempt.
+ /// The PingOptions specified when the ping was sent.
+ /// The manually measured latency of the ping attempt.
+ /// The buffer size.
+ /// The sequence number in the sequence of pings to the hop point.
+ internal PingStatus(
+ string source,
+ string destination,
+ PingReply reply,
+ PingOptions options,
+ long latency,
+ int bufferSize,
+ uint pingNum)
+ : this(source, destination, reply, pingNum)
+ {
+ _options = options;
+ _latency = latency;
+ _bufferSize = bufferSize;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source machine name or IP of the ping.
+ /// The destination machine name of the ping.
+ /// The response from the ping attempt.
+ /// The sequence number of the ping in the sequence of pings to the target.
+ internal PingStatus(string source, string destination, PingReply reply, uint pingNum)
+ {
+ Ping = pingNum;
+ Reply = reply;
+ Source = source;
+ Destination = destination ?? reply.Address.ToString();
+ }
+
+ // These values should only be set if this PingStatus was created as part of a traceroute.
+ private readonly int _bufferSize = -1;
+ private readonly long _latency = -1;
+ private readonly PingOptions _options;
+
+ ///
+ /// Gets the sequence number of this ping in the sequence of pings to the
+ ///
+ public uint Ping { get; }
+
+ ///
+ /// Gets the source from which the ping was sent.
+ ///
+ public string Source { get; }
+
+ ///
+ /// Gets the destination which was pinged.
+ ///
+ public string Destination { get; }
+
+ ///
+ /// Gets the target address of the ping.
+ ///
+ public IPAddress Address { get => Reply.Status == IPStatus.Success ? Reply.Address : null; }
+
+ ///
+ /// Gets the roundtrip time of the ping in milliseconds.
+ ///
+ public long Latency { get => _latency >= 0 ? _latency : Reply.RoundtripTime; }
+
+ ///
+ /// Gets the returned status of the ping.
+ ///
+ public IPStatus Status { get => Reply.Status; }
+
+ ///
+ /// Gets the size in bytes of the buffer data sent in the ping.
+ ///
+ public int BufferSize { get => _bufferSize >= 0 ? _bufferSize : Reply.Buffer.Length; }
+
+ ///
+ /// Gets the reply object from this ping.
+ ///
+ public PingReply Reply { get; }
+
+ ///
+ /// Gets the options used when sending the ping.
+ ///
+ public PingOptions Options { get => _options ?? Reply.Options; }
+ }
+
+ ///
+ /// The class contains information about the source, the destination and ping results.
+ ///
+ public class PingMtuStatus : PingStatus
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The source machine name or IP of the ping.
+ /// The destination machine name of the ping.
+ /// The response from the ping attempt.
+ internal PingMtuStatus(string source, string destination, PingReply reply)
+ : base(source, destination, reply, 1)
+ {
+ }
+
+ ///
+ /// Gets the maximum transmission unit size on the network path between the source and destination.
+ ///
+ public int MtuSize { get => BufferSize; }
+ }
+
// Count of pings sent per each trace route hop.
// Default = 3 (from Windows).
// If we change 'DefaultTraceRoutePingCount' we should change 'ConsoleTraceRouteReply' resource string.
@@ -921,12 +897,6 @@ private byte[] GetSendBuffer(int bufferSize)
private const int DefaultSendBufferSize = 32;
private static byte[] s_DefaultSendBuffer = null;
- // Random value for WriteProgress Activity Id.
- private static readonly int s_ProgressId = 174593053;
-
- // Empty message string for Progress Bar.
- private const string ProgressRecordSpace = " ";
-
private const string TestConnectionExceptionId = "TestConnectionException";
}
}
diff --git a/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx b/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx
index 794680166cc..6dc729dc250 100644
--- a/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx
+++ b/src/Microsoft.PowerShell.Commands.Management/resources/TestConnectionResources.resx
@@ -120,26 +120,14 @@
Tracing route to {0} [{1}] over a maximum of {2} hops:
-
- {0,3} {1} ms {2} ms {3} ms {4} [{5}]
-
-
- {0,3} * ms * ms * ms Request timed out.
-
Trace complete.
Trying to connect to {0} [{1}]:
-
- Target: {0} [{1}]. Seconds: {2}
-
-
- Pinging {0} [{1}] with {2} bytes of data:
-
-
- MTU size: {0}. Attempt: {1}
+
+ LowMTUSize: {0}, CurrentMTUSize: {1}, HighMTUSize: {2}
Testing connection to computer '{0}' failed: {1}
@@ -153,12 +141,6 @@
Pinging {0} [{1}] with {2} bytes of data:
-
- Request timed out.
-
-
- Reply from {0}: bytes={1} time={2}ms TTL={3}
-
Ping complete.
diff --git a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs
index 35d34c60670..a7f793972b7 100644
--- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs
+++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/PowerShellCore_format_ps1xml.cs
@@ -255,6 +255,122 @@ internal static IEnumerable GetFormatData()
yield return new ExtendedTypeDefinition(
"Microsoft.PowerShell.MarkdownRender.PSMarkdownOptionInfo",
ViewsOf_Microsoft_PowerShell_MarkdownRender_MarkdownOptionInfo());
+
+ yield return new ExtendedTypeDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus",
+ ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_PingStatus());
+
+ yield return new ExtendedTypeDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+PingMtuStatus",
+ ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_PingMtuStatus());
+
+ yield return new ExtendedTypeDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+TraceStatus",
+ ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_TraceStatus());
+ }
+
+ private static IEnumerable ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_PingStatus()
+ {
+ yield return new FormatViewDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus",
+ TableControl.Create()
+ .AddHeader(Alignment.Right, label: "Ping", width: 4)
+ .AddHeader(Alignment.Left, label: "Source", width: 16)
+ .AddHeader(Alignment.Left, label: "Address", width: 15)
+ .AddHeader(Alignment.Right, label: "Latency(ms)", width: 7)
+ .AddHeader(Alignment.Right, label: "BufferSize(B)", width: 10)
+ .AddHeader(Alignment.Center, label: "Status", width: 16)
+ .StartRowDefinition()
+ .AddPropertyColumn("Ping")
+ .AddPropertyColumn("Source")
+ .AddScriptBlockColumn(@"
+ if ($_.Address) {
+ $_.Address
+ }
+ else {
+ '*'
+ }
+ ")
+ .AddScriptBlockColumn(@"
+ if ($_.Status -eq 'TimedOut') {
+ '*'
+ }
+ else {
+ $_.Latency
+ }
+ ")
+ .AddPropertyColumn("BufferSize")
+ .AddPropertyColumn("Status")
+ .EndRowDefinition()
+ .GroupByProperty("Destination")
+ .EndTable());
+ }
+
+ private static IEnumerable ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_PingMtuStatus()
+ {
+ yield return new FormatViewDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+PingMtuStatus",
+ TableControl.Create()
+ .AddHeader(Alignment.Left, label: "Source", width: 16)
+ .AddHeader(Alignment.Left, label: "Address", width: 15)
+ .AddHeader(Alignment.Right, label: "Latency(ms)", width: 7)
+ .AddHeader(Alignment.Center, label: "Status", width: 16)
+ .AddHeader(Alignment.Right, label: "MtuSize(B)", width: 7)
+ .StartRowDefinition()
+ .AddPropertyColumn("Source")
+ .AddPropertyColumn("Address")
+ .AddScriptBlockColumn(@"
+ if ($_.Status -eq 'TimedOut') {
+ '*'
+ }
+ else {
+ $_.Latency
+ }
+ ")
+ .AddPropertyColumn("Status")
+ .AddPropertyColumn("MtuSize")
+ .EndRowDefinition()
+ .GroupByProperty("Destination")
+ .EndTable());
+ }
+
+ private static IEnumerable ViewsOf_Microsoft_PowerShell_Commands_TestConnectionCommand_TraceStatus()
+ {
+ yield return new FormatViewDefinition(
+ "Microsoft.PowerShell.Commands.TestConnectionCommand+TraceStatus",
+ TableControl.Create()
+ .AddHeader(Alignment.Right, label: "Hop", width: 3)
+ .AddHeader(Alignment.Left, label: "Hostname", width: 22)
+ .AddHeader(Alignment.Right, label: "Ping", width: 4)
+ .AddHeader(Alignment.Right, label: "Latency(ms)", width: 7)
+ .AddHeader(Alignment.Center, label: "Status", width: 16)
+ .AddHeader(Alignment.Left, label: "Source", width: 12)
+ .AddHeader(Alignment.Left, label: "TargetAddress", width: 15)
+ .StartRowDefinition()
+ .AddPropertyColumn("Hop")
+ .AddScriptBlockColumn(@"
+ if ($_.Hostname) {
+ $_.HostName
+ }
+ else {
+ '*'
+ }
+ ")
+ .AddPropertyColumn("Ping")
+ .AddScriptBlockColumn(@"
+ if ($_.Status -eq 'TimedOut') {
+ '*'
+ }
+ else {
+ $_.Latency
+ }
+ ")
+ .AddPropertyColumn("Status")
+ .AddPropertyColumn("Source")
+ .AddPropertyColumn("TargetAddress")
+ .EndRowDefinition()
+ .GroupByProperty("Target")
+ .EndTable());
}
private static IEnumerable ViewsOf_System_RuntimeType()
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1
index a4a2c14433f..9b592061f64 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1
@@ -5,11 +5,6 @@ Import-Module HelpersCommon
Describe "Test-Connection" -tags "CI" {
BeforeAll {
- $oldInformationPreference = $InformationPreference
- $oldProgressPreference = $ProgressPreference
- $InformationPreference = "Ignore"
- $ProgressPreference = "SilentlyContinue"
-
$hostName = [System.Net.Dns]::GetHostName()
$targetName = "localhost"
$targetAddress = "127.0.0.1"
@@ -22,36 +17,31 @@ Describe "Test-Connection" -tags "CI" {
# this resolves to an actual IP rather than 127.0.0.1
# this can also include both IPv4 and IPv6, so select InterNetwork rather than InterNetworkV6
$realAddress = [System.Net.Dns]::GetHostEntry($hostName).AddressList |
- Where-Object {$_.AddressFamily -eq "InterNetwork"} |
+ Where-Object { $_.AddressFamily -eq "InterNetwork" } |
Select-Object -First 1 |
- Foreach-Object {$_.IPAddressToString}
+ ForEach-Object { $_.IPAddressToString }
# under some environments, we can't round trip this and retrieve the real name from the address
# in this case we will simply use the hostname
- $jobContinues = Start-Job { Test-Connection $using:targetAddress -Continues }
- }
-
- AfterAll {
- $InformationPreference = $oldInformationPreference
- $ProgressPreference = $oldProgressPreference
+ $jobContinues = Start-Job { Test-Connection $using:targetAddress -Repeat }
}
Context "Ping" {
It "Default parameter set is 'Ping'" {
$result = Test-Connection $targetName
- $replies = $result.Replies
- $result.Count | Should -Be 1
- $result[0] | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+PingReport"
- $result[0].Source | Should -BeExactly $hostName
+ $result.Count | Should -Be 4
+ $result[0] | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+PingStatus"
+ $result[0].Ping | Should -Be 1
+ $result[0].Source | Should -BeExactly $hostName
$result[0].Destination | Should -BeExactly $targetName
-
- $replies.Count | Should -Be 4
- $replies[0] | Should -BeOfType "System.Net.NetworkInformation.PingReply"
- $replies[0].Address | Should -BeExactly $targetAddressIPv6
- $replies[0].Status | Should -BeExactly "Success"
+ $result[0].Address | Should -BeExactly $targetAddressIPv6
+ $result[0].Status | Should -BeExactly "Success"
+ $result[0].Latency | Should -BeOfType "long"
+ $result[0].Reply | Should -BeOfType "System.Net.NetworkInformation.PingReply"
+ $result[0].Options | Should -BeOfType "System.Net.NetworkInformation.PingOptions"
# TODO: Here and below we skip the check on Unix because .Net Core issue
if ($isWindows) {
- $replies[0].Buffer.Count | Should -Be 32
+ $replies[0].BufferSize | Should -Be 32
}
}
@@ -60,8 +50,8 @@ Describe "Test-Connection" -tags "CI" {
$result1 = Test-Connection -Ping $targetName -Count 1
$result2 = Test-Connection $targetName -Count 2
- $result1.Replies.Count | Should -Be 1
- $result2.Replies.Count | Should -Be 2
+ $result1.Count | Should -Be 1
+ $result2.Count | Should -Be 2
}
It "Quiet works" {
@@ -75,11 +65,13 @@ Describe "Test-Connection" -tags "CI" {
It "Ping fake host" {
- { $result = Test-Connection "fakeHost" -Count 1 -Quiet -ErrorAction Stop } | Should -Throw -ErrorId "TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { $result = Test-Connection "fakeHost" -Count 1 -Quiet -ErrorAction Stop } |
+ Should -Throw -ErrorId "TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand"
# Error code = 11001 - Host not found.
if (!$isWindows) {
$Error[0].Exception.InnerException.ErrorCode | Should -Be -131073
- } else {
+ }
+ else {
$Error[0].Exception.InnerException.ErrorCode | Should -Be 11001
}
}
@@ -88,10 +80,10 @@ Describe "Test-Connection" -tags "CI" {
It "Force IPv4 with implicit PingOptions" {
$result = Test-Connection $hostName -Count 1 -IPv4
- $result.Replies[0].Address | Should -BeExactly $realAddress
- $result.Replies[0].Options.Ttl | Should -BeLessOrEqual 128
+ $result[0].Address | Should -BeExactly $realAddress
+ $result[0].Options.Ttl | Should -BeLessOrEqual 128
if ($isWindows) {
- $result.Replies[0].Options.DontFragment | Should -BeFalse
+ $result[0].Options.DontFragment | Should -BeFalse
}
}
@@ -103,48 +95,53 @@ Describe "Test-Connection" -tags "CI" {
# it's more about breaking out of the loop
$result2 = Test-Connection 8.8.8.8 -Count 1 -IPv4 -MaxHops 1 -DontFragment
- $result1.Replies[0].Address | Should -BeExactly $realAddress
+ $result1[0].Address | Should -BeExactly $realAddress
# .Net Core (.Net Framework) returns Options based on default PingOptions() constructor (Ttl=128, DontFragment = false).
# After .Net Core fix we should have 'DontFragment | Should -Be $true' here.
- $result1.Replies[0].Options.Ttl | Should -BeLessOrEqual 128
+ $result1[0].Options.Ttl | Should -BeLessOrEqual 128
if (!$isWindows) {
- $result1.Replies[0].Options.DontFragment | Should -BeNullOrEmpty
- # depending on the network configuration any of the following should be returned
- $result2.Replies[0].Status | Should -BeIn "TtlExpired","TimedOut","Success"
- } else {
- $result1.Replies[0].Options.DontFragment | Should -BeFalse
+ $result1[0].Options.DontFragment | Should -BeNullOrEmpty
+ # Depending on the network configuration any of the following should be returned
+ $result2[0].Status | Should -BeIn "TtlExpired", "TimedOut", "Success"
+ }
+ else {
+ $result1[0].Options.DontFragment | Should -BeFalse
# We expect 'TtlExpired' but if a router don't reply we get `TimedOut`
# AzPipelines returns $null
- $result2.Replies[0].Status | Should -BeIn "TtlExpired","TimedOut",$null
+ $result2[0].Status | Should -BeIn "TtlExpired", "TimedOut", $null
}
}
It "Force IPv6" -Pending {
$result = Test-Connection $targetName -Count 1 -IPv6
- $result.Replies[0].Address | Should -BeExactly $targetAddressIPv6
+ $result[0].Address | Should -BeExactly $targetAddressIPv6
# We should check Null not Empty!
- $result.Replies[0].Options | Should -Be $null
+ $result[0].Options | Should -Be $null
}
It "MaxHops Should -Be greater 0" {
- { Test-Connection $targetName -MaxHops 0 } | Should -Throw -ErrorId "System.ArgumentOutOfRangeException,Microsoft.PowerShell.Commands.TestConnectionCommand"
- { Test-Connection $targetName -MaxHops -1 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -MaxHops 0 } |
+ Should -Throw -ErrorId "System.ArgumentOutOfRangeException,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -MaxHops -1 } |
+ Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
}
It "Count Should -Be greater 0" {
- { Test-Connection $targetName -Count 0 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -Count 0 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
{ Test-Connection $targetName -Count -1 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
}
It "Delay Should -Be greater 0" {
- { Test-Connection $targetName -Delay 0 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
- { Test-Connection $targetName -Delay -1 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -Delay 0 } |
+ Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -Delay -1 } |
+ Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
}
It "Delay works" {
- $result1 = measure-command {Test-Connection localhost -Count 2}
- $result2 = measure-command {Test-Connection localhost -Delay 4 -Count 2}
+ $result1 = Measure-Command { Test-Connection localhost -Count 2 }
+ $result2 = Measure-Command { Test-Connection localhost -Delay 4 -Count 2 }
$result1.TotalSeconds | Should -BeGreaterThan 1
$result1.TotalSeconds | Should -BeLessThan 3
@@ -152,16 +149,18 @@ Describe "Test-Connection" -tags "CI" {
}
It "BufferSize Should -Be between 0 and 65500" {
- { Test-Connection $targetName -BufferSize 0 } | Should Not Throw
- { Test-Connection $targetName -BufferSize -1 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
- { Test-Connection $targetName -BufferSize 65501 } | Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -BufferSize 0 } | Should -Not Throw
+ { Test-Connection $targetName -BufferSize -1 } |
+ Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
+ { Test-Connection $targetName -BufferSize 65501 } |
+ Should -Throw -ErrorId "ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand"
}
It "BufferSize works" -Pending:(!$IsWindows) {
$result = Test-Connection $targetName -Count 1 -BufferSize 2
if ($isWindows) {
- $result.Replies[0].Buffer.Count | Should -Be 2
+ $result.BufferSize | Should -Be 2
}
}
@@ -170,7 +169,7 @@ Describe "Test-Connection" -tags "CI" {
$resolvedName = [System.Net.DNS]::GetHostEntry($targetAddress).HostName
$result.Destination | Should -BeExactly $resolvedName
- $result.Replies[0].Address | Should -BeExactly $targetAddress
+ $result.Address | Should -BeExactly $targetAddress
}
It "ResolveDestination for name" {
@@ -182,42 +181,44 @@ Describe "Test-Connection" -tags "CI" {
$resolvedAddress = ([System.Net.DNS]::GetHostAddresses($resolvedName)[0] -split "%")[0]
$result.Destination | Should -BeExactly $resolvedName
- $result.Replies[0].Address | Should -BeExactly $resolvedAddress
+ $result.Address | Should -BeExactly $resolvedAddress
}
It "TimeOut works" {
- (Measure-Command { Test-Connection $UnreachableAddress -Count 1 -TimeOut 1 }).TotalSeconds | Should -BeLessThan 3
- (Measure-Command { Test-Connection $UnreachableAddress -Count 1 -TimeOut 4 }).TotalSeconds | Should -BeGreaterThan 3
+ (Measure-Command { Test-Connection $UnreachableAddress -Count 1 -TimeOut 1 }).TotalSeconds |
+ Should -BeLessThan 3
+ (Measure-Command { Test-Connection $UnreachableAddress -Count 1 -TimeOut 4 }).TotalSeconds |
+ Should -BeGreaterThan 3
}
- It "Continues works" {
- # By default we do 4 ping so for '-Continues' we expect to get >4 results.
+ It "Repeat works" {
+ # By default we do 4 ping so for '-Repeat' we expect to get >4 results.
# Also we should wait >4 seconds before check results but previous tests already did the pause.
$result = Receive-Job $jobContinues
Remove-Job $jobContinues -Force
- $result.Count | Should -BeGreaterThan 4
- $result[0].Address | Should -BeExactly $targetAddress
- $result[0].Status | Should -BeExactly "Success"
+ $result.Count | Should -BeGreaterThan 4
+ $result[0].Address | Should -BeExactly $targetAddress
+ $result[0].Status | Should -BeExactly "Success"
if ($isWindows) {
- $result[0].Buffer.Count | Should -Be 32
+ $result[0].BufferSize | Should -Be 32
}
}
-}
+ }
- # TODO: We skip the MTUSizeDetect tests on Unix because we expect 'TtlExpired' but get 'TimeOut' internally from .Net Core
+ # TODO: We skip the MTUSizeDetect tests on Unix because we expect 'PacketTooBig' but get 'TimeOut' internally from .Net Core
Context "MTUSizeDetect" {
It "MTUSizeDetect works" -pending:($IsMacOS) {
- $result = Test-Connection $hostName -MTUSizeDetect
+ $result = Test-Connection $hostName -DetectMtuSize
- $result | Should -BeOfType "System.Net.NetworkInformation.PingReply"
+ $result | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+PingMtuStatus"
$result.Destination | Should -BeExactly $hostName
$result.Status | Should -BeExactly "Success"
- $result.MTUSize | Should -BeGreaterThan 0
+ $result.MtuSize | Should -BeGreaterThan 0
}
It "Quiet works" -pending:($IsMacOS) {
- $result = Test-Connection $hostName -MTUSizeDetect -Quiet
+ $result = Test-Connection $hostName -DetectMtuSize -Quiet
$result | Should -BeOfType "Int32"
$result | Should -BeGreaterThan 0
@@ -228,32 +229,24 @@ Describe "Test-Connection" -tags "CI" {
It "TraceRoute works" {
# real address is an ipv4 address, so force IPv4
$result = Test-Connection $hostName -TraceRoute -IPv4
- $replies = $result.Replies
- # Check target host reply.
- $pingReplies = $replies[-1].PingReplies
-
- $result.Count | Should -Be 1
- $result | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+TraceRouteResult"
- $result.Source | Should -BeExactly $hostName
- $result.DestinationAddress | Should -BeExactly $realAddress
- $result.DestinationHost | Should -BeExactly $hostName
-
- $replies.Count | Should -BeGreaterThan 0
- $replies[0] | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+TraceRouteReply"
- $replies[0].Hop | Should -Be 1
-
- $pingReplies.Count | Should -Be 3
- $pingReplies[0].Address | Should -BeExactly $realAddress
- $pingReplies[0].Status | Should -BeExactly "Success"
+
+ $result[0] | Should -BeOfType "Microsoft.PowerShell.Commands.TestConnectionCommand+TraceStatus"
+ $result[0].Source | Should -BeExactly $hostName
+ $result[0].TargetAddress | Should -BeExactly $realAddress
+ $result[0].Target | Should -BeExactly $hostName
+ $result[0].Hop | Should -Be 1
+ $result[0].HopAddress | Should -BeExactly $realAddress
+ $result[0].Status | Should -BeExactly "Success"
if (!$isWindows) {
- $pingReplies[0].Buffer.Count | Should -Match '^0$|^32$'
- } else {
- $pingReplies[0].Buffer.Count | Should -Be 32
+ $result[0].Reply.Buffer.Count | Should -Match '^0$|^32$'
+ }
+ else {
+ $result[0].Reply.Buffer.Count | Should -Be 32
}
}
It "Quiet works" {
- $result = Test-Connection $hostName -TraceRoute -Quiet 6> $null
+ $result = Test-Connection $hostName -TraceRoute -Quiet
$result | Should -BeTrue
}
@@ -268,10 +261,10 @@ Describe "Connection" -Tag "CI", "RequireAdminOnWindows" {
}
It "Test connection to local host port 80" {
- Test-Connection '127.0.0.1' -TCPPort $WebListener.HttpPort | Should -BeTrue
+ Test-Connection '127.0.0.1' -TcpPort $WebListener.HttpPort | Should -BeTrue
}
It "Test connection to unreachable host port 80" {
- Test-Connection $UnreachableAddress -TCPPort 80 -TimeOut 1 | Should -BeFalse
+ Test-Connection $UnreachableAddress -TcpPort 80 -TimeOut 1 | Should -BeFalse
}
}