Ip addresses on your subnet with xargs

[xargs](tag_xargs.html) strikes again. This time I'm going to use it's parallel
feature to ping 255 machines very quickly. xargs has a parem `-Px` where x is 
the number of parallel processes to spawn of the subsequent process. 

---

## Update - 11/04/2019 Added MacOS Xargs syntax

Together with the bash `{1..255}` expression that expands to output 1 to 255, we
can do something like this
    
            $ s=192.168.11.
            $ echo ${s}{1..254} | xargs -P254 -d' ' -L1 ping -c1 -w1 | grep 'bytes from'

In this example, `-P254` tells xargs to spawn 254 procceses, `-d' '` says to 
split commands with a space instead of the normal newline, and `-L1` says to 
finish building the command after `1` amount of input.

To achieve the same result in powershell is not quite as simple. Out of the box
you could use a `ForeEach-Object` loop like so:


            PS> $s='192.168.11.'
            PS> echo $s[1..254] | %{ Test-Connection $_ -Count 1 -TTL 1 -EA SilentlyContinue }

But it's just a sequential loop. Instead we are going to have to leverage 
the .Net [ping](docs.microsoft.com/dotnet/api/system.net.networkinformation.ping)
class.

Lee Holmes [shared](https://twitter.com/Lee_Holmes/status/646890380995067904) 
this on twitter back in 2015:

> Sweep a /16 in 30s: 
>
>               $t=$ips|%{
>                   (New-Object Net.NetworkInformation.Ping).SendPingAsync($_,250)};
>                   [Threading.Tasks.Task]::WaitAll($t);
>                   $t.Result

Before you run this, build out an array of ips, like so:

    PS> $ips=[1..254] | %{"192.168.11.$_"}

This use of powershell seems a bit too obtuse for me, and not something likely
to stick in my head. 

I did find other ways to do it in powershell. A collegue of mine Darryl, 
[dardie](https://github.com/dardie) on github added [this](https://github.com/zigford/USC-SCCM/commit/d9813d5626cbb52201541a574a0adf51e99466d8#diff-73c8dfd0435ecc73e3fc408a851841c2)
commit to a module I maintain which has pretty good results. Again however not
something you could commit to memory as you need to write a function to use it.

## Final thoughts

In this case it looks to me like bash wins, if not in performance, but by being
simpler to implement and commit to memory, or recreate from memory. But if I
ever need to do this in powershell again, I can just come back to my site for
reference.

If you have any comments or feedback, please [email](mailto:jesse@zigford.org) me
and let me know if you will allow your feedback to be posted here.

## MacOS

For completeness and because I tried to run this and failed on MacOS today I'm
adding it's syntax:

Xargs on MacOS is a BSD variant, seemlingly pulled from FreeBSD going by the
man page. It still supports the `-Px`, however `-d` is not required as it
splits on newline and spaces by default. The other difference is that instead
of `-L1` we use `-n1` with essentially the same effect.

Also of note is the differences with ping. Rather than `-w1` to reduce time
waiting for a ping reply, `-t1` is used.

            echo "192.168.11."{1..254} | xargs -P254 -n1 ping -c1 -t1 |
            awk '/bytes from/ {
                match($0,"[0-9]+.[0-9]+.[0-9]+.[0-9]+");
                n=substr($0,RSTART,RLENGTH);
                print n
            }'

_In this example, I'm using an awk script to only print hosts that respond_

Tags: bash-v-powershell, powershell, xargs, bash, ping, awk
