diff --git a/plugins/inputs/ping/ping_windows.go b/plugins/inputs/ping/ping_windows.go
index b1d3ef06ff295407b5590c06d0f571ef21738b72..d36f44526f644b43c649765a2dece2295bc0c5ee 100644
--- a/plugins/inputs/ping/ping_windows.go
+++ b/plugins/inputs/ping/ping_windows.go
@@ -1,3 +1,210 @@
 // +build windows
-
 package ping
+
+import (
+	"errors"
+	"github.com/influxdata/telegraf"
+	"github.com/influxdata/telegraf/internal"
+	"github.com/influxdata/telegraf/plugins/inputs"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+// HostPinger is a function that runs the "ping" function using a list of
+// passed arguments. This can be easily switched with a mocked ping function
+// for unit test purposes (see ping_test.go)
+type HostPinger func(timeout float64, args ...string) (string, error)
+
+type Ping struct {
+	// Number of pings to send (ping -c <COUNT>)
+	Count int
+
+	// Ping timeout, in seconds. 0 means no timeout (ping -W <TIMEOUT>)
+	Timeout float64
+
+	// URLs to ping
+	Urls []string
+
+	// host ping function
+	pingHost HostPinger
+}
+
+func (s *Ping) Description() string {
+	return "Ping given url(s) and return statistics"
+}
+
+const sampleConfig = `
+	## urls to ping
+	urls = ["www.google.com"] # required
+	
+	## number of pings to send per collection (ping -n <COUNT>)
+	count = 4 # required
+	
+	## Ping timeout, in seconds. 0 means default timeout (ping -w <TIMEOUT>)
+	Timeout = 0
+`
+
+func (s *Ping) SampleConfig() string {
+	return sampleConfig
+}
+
+func hostPinger(timeout float64, args ...string) (string, error) {
+	bin, err := exec.LookPath("ping")
+	if err != nil {
+		return "", err
+	}
+	c := exec.Command(bin, args...)
+	out, err := internal.CombinedOutputTimeout(c,
+		time.Second*time.Duration(timeout+1))
+	return string(out), err
+}
+
+// processPingOutput takes in a string output from the ping command
+// based on linux implementation but using regex ( multilanguage support ) ( shouldn't affect the performance of the program )
+// It returns (<transmitted packets>, <received packets>, <average response>, <min response>, <max response>)
+func processPingOutput(out string) (int, int, int, int, int, error) {
+	// So find a line contain 3 numbers except reply lines
+	var stats, aproxs []string = nil, nil
+	err := errors.New("Fatal error processing ping output")
+	stat := regexp.MustCompile(`=\W*(\d+)\D*=\W*(\d+)\D*=\W*(\d+)`)
+	aprox := regexp.MustCompile(`=\W*(\d+)\D*ms\D*=\W*(\d+)\D*ms\D*=\W*(\d+)\D*ms`)
+	lines := strings.Split(out, "\n")
+	for _, line := range lines {
+		if !strings.Contains(line, "TTL") {
+			if stats == nil {
+				stats = stat.FindStringSubmatch(line)
+			}
+			if stats != nil && aproxs == nil {
+				aproxs = aprox.FindStringSubmatch(line)
+			}
+		}
+	}
+
+	// stats data should contain 4 members: entireExpression + ( Send, Receive, Lost )
+	if len(stats) != 4 {
+		return 0, 0, 0, 0, 0, err
+	}
+	trans, err := strconv.Atoi(stats[1])
+	if err != nil {
+		return 0, 0, 0, 0, 0, err
+	}
+	rec, err := strconv.Atoi(stats[2])
+	if err != nil {
+		return 0, 0, 0, 0, 0, err
+	}
+
+	// aproxs data should contain 4 members: entireExpression + ( min, max, avg )
+	if len(aproxs) != 4 {
+		return trans, rec, 0, 0, 0, err
+	}
+	min, err := strconv.Atoi(aproxs[1])
+	if err != nil {
+		return trans, rec, 0, 0, 0, err
+	}
+	max, err := strconv.Atoi(aproxs[2])
+	if err != nil {
+		return trans, rec, 0, 0, 0, err
+	}
+	avg, err := strconv.Atoi(aproxs[3])
+	if err != nil {
+		return 0, 0, 0, 0, 0, err
+	}
+
+	return trans, rec, avg, min, max, err
+}
+
+func (p *Ping) timeout() float64 {
+	// According to MSDN, default ping timeout for windows is 4 second
+	// Add also one second interval
+
+	if p.Timeout > 0 {
+		return p.Timeout + 1
+	}
+	return 4 + 1
+}
+
+// args returns the arguments for the 'ping' executable
+func (p *Ping) args(url string) []string {
+	args := []string{"-n", strconv.Itoa(p.Count)}
+
+	if p.Timeout > 0 {
+		args = append(args, "-w", strconv.FormatFloat(p.Timeout*1000, 'f', 0, 64))
+	}
+
+	args = append(args, url)
+
+	return args
+}
+
+func (p *Ping) Gather(acc telegraf.Accumulator) error {
+	var wg sync.WaitGroup
+	errorChannel := make(chan error, len(p.Urls)*2)
+	var pendingError error = nil
+	// Spin off a go routine for each url to ping
+	for _, url := range p.Urls {
+		wg.Add(1)
+		go func(u string) {
+			defer wg.Done()
+			args := p.args(u)
+			totalTimeout := p.timeout() * float64(p.Count)
+			out, err := p.pingHost(totalTimeout, args...)
+			// ping host return exitcode != 0 also when there was no response from host
+			// but command was execute succesfully
+			if err != nil {
+				// Combine go err + stderr output
+				pendingError = errors.New(strings.TrimSpace(out) + ", " + err.Error())
+			}
+			tags := map[string]string{"url": u}
+			trans, rec, avg, min, max, err := processPingOutput(out)
+			if err != nil {
+				// fatal error
+				if pendingError != nil {
+					errorChannel <- pendingError
+				}
+				errorChannel <- err
+				return
+			}
+			// Calculate packet loss percentage
+			loss := float64(trans-rec) / float64(trans) * 100.0
+			fields := map[string]interface{}{
+				"packets_transmitted": trans,
+				"packets_received":    rec,
+				"percent_packet_loss": loss,
+			}
+			if avg > 0 {
+				fields["average_response_ms"] = avg
+			}
+			if min > 0 {
+				fields["minimum_response_ms"] = min
+			}
+			if max > 0 {
+				fields["maximum_response_ms"] = max
+			}
+			acc.AddFields("ping", fields, tags)
+		}(url)
+	}
+
+	wg.Wait()
+	close(errorChannel)
+
+	// Get all errors and return them as one giant error
+	errorStrings := []string{}
+	for err := range errorChannel {
+		errorStrings = append(errorStrings, err.Error())
+	}
+
+	if len(errorStrings) == 0 {
+		return nil
+	}
+	return errors.New(strings.Join(errorStrings, "\n"))
+}
+
+func init() {
+	inputs.Add("ping", func() telegraf.Input {
+		return &Ping{pingHost: hostPinger}
+	})
+}
diff --git a/plugins/inputs/ping/ping_windows_test.go b/plugins/inputs/ping/ping_windows_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a4d0609e6dda07968fe833ffef2b8bc9f24d02cc
--- /dev/null
+++ b/plugins/inputs/ping/ping_windows_test.go
@@ -0,0 +1,218 @@
+// +build windows
+package ping
+
+import (
+	"errors"
+	"github.com/influxdata/telegraf/testutil"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+// Windows ping format ( should support multilanguage ?)
+var winPLPingOutput = `
+Badanie 8.8.8.8 z 32 bajtami danych:
+Odpowiedz z 8.8.8.8: bajtow=32 czas=49ms TTL=43
+Odpowiedz z 8.8.8.8: bajtow=32 czas=46ms TTL=43
+Odpowiedz z 8.8.8.8: bajtow=32 czas=48ms TTL=43
+Odpowiedz z 8.8.8.8: bajtow=32 czas=57ms TTL=43
+
+Statystyka badania ping dla 8.8.8.8:
+    Pakiety: Wyslane = 4, Odebrane = 4, Utracone = 0
+             (0% straty),
+Szacunkowy czas bladzenia pakietww w millisekundach:
+    Minimum = 46 ms, Maksimum = 57 ms, Czas sredni = 50 ms
+`
+
+// Windows ping format ( should support multilanguage ?)
+var winENPingOutput = `
+Pinging 8.8.8.8 with 32 bytes of data:
+Reply from 8.8.8.8: bytes=32 time=52ms TTL=43
+Reply from 8.8.8.8: bytes=32 time=50ms TTL=43
+Reply from 8.8.8.8: bytes=32 time=50ms TTL=43
+Reply from 8.8.8.8: bytes=32 time=51ms TTL=43
+
+Ping statistics for 8.8.8.8:
+    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
+Approximate round trip times in milli-seconds:
+    Minimum = 50ms, Maximum = 52ms, Average = 50ms
+`
+
+func TestHost(t *testing.T) {
+	trans, rec, avg, min, max, err := processPingOutput(winPLPingOutput)
+	assert.NoError(t, err)
+	assert.Equal(t, 4, trans, "4 packets were transmitted")
+	assert.Equal(t, 4, rec, "4 packets were received")
+	assert.Equal(t, 50, avg, "Average 50")
+	assert.Equal(t, 46, min, "Min 46")
+	assert.Equal(t, 57, max, "max 57")
+
+	trans, rec, avg, min, max, err = processPingOutput(winENPingOutput)
+	assert.NoError(t, err)
+	assert.Equal(t, 4, trans, "4 packets were transmitted")
+	assert.Equal(t, 4, rec, "4 packets were received")
+	assert.Equal(t, 50, avg, "Average 50")
+	assert.Equal(t, 50, min, "Min 50")
+	assert.Equal(t, 52, max, "Max 52")
+}
+
+func mockHostPinger(timeout float64, args ...string) (string, error) {
+	return winENPingOutput, nil
+}
+
+// Test that Gather function works on a normal ping
+func TestPingGather(t *testing.T) {
+	var acc testutil.Accumulator
+	p := Ping{
+		Urls:     []string{"www.google.com", "www.reddit.com"},
+		pingHost: mockHostPinger,
+	}
+
+	p.Gather(&acc)
+	tags := map[string]string{"url": "www.google.com"}
+	fields := map[string]interface{}{
+		"packets_transmitted": 4,
+		"packets_received":    4,
+		"percent_packet_loss": 0.0,
+		"average_response_ms": 50,
+		"minimum_response_ms": 50,
+		"maximum_response_ms": 52,
+	}
+	acc.AssertContainsTaggedFields(t, "ping", fields, tags)
+
+	tags = map[string]string{"url": "www.reddit.com"}
+	acc.AssertContainsTaggedFields(t, "ping", fields, tags)
+}
+
+var errorPingOutput = `
+Badanie nask.pl [195.187.242.157] z 32 bajtami danych:
+Upłynął limit czasu żądania.
+Upłynął limit czasu żądania.
+Upłynął limit czasu żądania.
+Upłynął limit czasu żądania.
+
+Statystyka badania ping dla 195.187.242.157:
+    Pakiety: Wysłane = 4, Odebrane = 0, Utracone = 4
+             (100% straty),
+`
+
+func mockErrorHostPinger(timeout float64, args ...string) (string, error) {
+	return errorPingOutput, errors.New("No packets received")
+}
+
+// Test that Gather works on a ping with no transmitted packets, even though the
+// command returns an error
+func TestBadPingGather(t *testing.T) {
+	var acc testutil.Accumulator
+	p := Ping{
+		Urls:     []string{"www.amazon.com"},
+		pingHost: mockErrorHostPinger,
+	}
+
+	p.Gather(&acc)
+	tags := map[string]string{"url": "www.amazon.com"}
+	fields := map[string]interface{}{
+		"packets_transmitted": 4,
+		"packets_received":    0,
+		"percent_packet_loss": 100.0,
+	}
+	acc.AssertContainsTaggedFields(t, "ping", fields, tags)
+}
+
+var lossyPingOutput = `
+Badanie thecodinglove.com [66.6.44.4] z 9800 bajtami danych:
+Upłynął limit czasu żądania.
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=118ms TTL=48
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=114ms TTL=48
+Upłynął limit czasu żądania.
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=119ms TTL=48
+Odpowiedź z 66.6.44.4: bajtów=9800 czas=116ms TTL=48
+
+Statystyka badania ping dla 66.6.44.4:
+    Pakiety: Wysłane = 9, Odebrane = 7, Utracone = 2
+             (22% straty),
+Szacunkowy czas błądzenia pakietów w millisekundach:
+    Minimum = 114 ms, Maksimum = 119 ms, Czas średni = 115 ms
+`
+
+func mockLossyHostPinger(timeout float64, args ...string) (string, error) {
+	return lossyPingOutput, nil
+}
+
+// Test that Gather works on a ping with lossy packets
+func TestLossyPingGather(t *testing.T) {
+	var acc testutil.Accumulator
+	p := Ping{
+		Urls:     []string{"www.google.com"},
+		pingHost: mockLossyHostPinger,
+	}
+
+	p.Gather(&acc)
+	tags := map[string]string{"url": "www.google.com"}
+	fields := map[string]interface{}{
+		"packets_transmitted": 9,
+		"packets_received":    7,
+		"percent_packet_loss": 22.22222222222222,
+		"average_response_ms": 115,
+		"minimum_response_ms": 114,
+		"maximum_response_ms": 119,
+	}
+	acc.AssertContainsTaggedFields(t, "ping", fields, tags)
+}
+
+// Fatal ping output (invalid argument)
+var fatalPingOutput = `
+Bad option -d.
+
+
+Usage: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]
+            [-r count] [-s count] [[-j host-list] | [-k host-list]]
+            [-w timeout] [-R] [-S srcaddr] [-4] [-6] target_name
+
+Options:
+    -t             Ping the specified host until stopped.
+                   To see statistics and continue - type Control-Break;
+                   To stop - type Control-C.
+    -a             Resolve addresses to hostnames.
+    -n count       Number of echo requests to send.
+    -l size        Send buffer size.
+    -f             Set Don't Fragment flag in packet (IPv4-only).
+    -i TTL         Time To Live.
+    -v TOS         Type Of Service (IPv4-only. This setting has been deprecated
+                   and has no effect on the type of service field in the IP Header).
+    -r count       Record route for count hops (IPv4-only).
+    -s count       Timestamp for count hops (IPv4-only).
+    -j host-list   Loose source route along host-list (IPv4-only).
+    -k host-list   Strict source route along host-list (IPv4-only).
+    -w timeout     Timeout in milliseconds to wait for each reply.
+    -R             Use routing header to test reverse route also (IPv6-only).
+    -S srcaddr     Source address to use.
+    -4             Force using IPv4.
+    -6             Force using IPv6.
+
+`
+
+func mockFatalHostPinger(timeout float64, args ...string) (string, error) {
+	return fatalPingOutput, errors.New("So very bad")
+}
+
+// Test that a fatal ping command does not gather any statistics.
+func TestFatalPingGather(t *testing.T) {
+	var acc testutil.Accumulator
+	p := Ping{
+		Urls:     []string{"www.amazon.com"},
+		pingHost: mockFatalHostPinger,
+	}
+
+	p.Gather(&acc)
+	assert.False(t, acc.HasMeasurement("packets_transmitted"),
+		"Fatal ping should not have packet measurements")
+	assert.False(t, acc.HasMeasurement("packets_received"),
+		"Fatal ping should not have packet measurements")
+	assert.False(t, acc.HasMeasurement("percent_packet_loss"),
+		"Fatal ping should not have packet measurements")
+	assert.False(t, acc.HasMeasurement("average_response_ms"),
+		"Fatal ping should not have packet measurements")
+}