I wrote a small function in powershell that works fine, however I feel its extremely hacky and I'm sure there must be a smarter way to do this. In the interests of learning, what can I do to improve on this?

function WhatsMyIP
return ((Invoke-RestMethod -Uri http://ifconfig.co).split("`n") | where {$_ -match "`"ip`""}).split("<").split(">")[4]

I tried this with Invoke-WebRequest but the returned data is the same, except you need to expand the .content property to get at it, making this slightly more clunky than before.

I'd like to do this natively, I realise I can just invoke CURL or what ever but the point is that I am very likely to be on systems where CURL isn't available when I need this.


the easiest way to get Public/External IP from ifconfig.co using CMD or Powershell is:

In Powershell:

Invoke-RestMethod -Uri http://ifconfig.co -UserAgent "curl"

in CMD:

powershell Invoke-RestMethod -Uri http://ifconfig.co -UserAgent "curl"

In a BATCH (.bat/.cmd) file:

@echo off
for /f "usebackq" %%i in (`powershell -Command Invoke-RestMethod -Uri http://ifconfig.co -UserAgent "curl"`) do set IP=%%i
echo My ip is: %IP%


cmd results from powershell Invoke-RestMethod -Uri http://ifconfig.co

  • \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit it to explain your reasoning (how your solution works and how it improves upon the original) so that everyone can learn from your thought process. \$\endgroup\$ – Toby Speight Jun 5 '18 at 10:39

I don't like the idea of using Invoke-RestMethod here. Normally it would return an object, but here it just returns html as a string, which isn't much use to us. I guess that's because the payload is not XML or JSON, so PowerShell can't turn it into an object for us.

Invoke-WebRequest in contrast will parse the HTML for us, and then we can filter out the element we want:

function WhatsMyIP
    $x = Invoke-WebRequest -Uri http://ifconfig.co
    $elt = $x.AllElements | ? { $_.tagName -eq 'CODE' -and $_.class -eq 'ip' }

The question mark ? means "where". (It's an alias for Where-Object.) So, what we are doing is we get all the HTML elements on the page, and we filter out all of them except the ones that have a tagName of 'CODE' and a class of 'ip'. (There will only be one of them on this particular page.) We are catching this element: <code class="ip"></code>.

That's "screen scraping" though, which is a bit crappy. I notice on the web site that they provide JSON if you give them the right URL. Now we can use Invoke-RestMethod:

function WhatsMyIP
    $x = Invoke-RestMethod -Uri ifconfig.co/all.json

Note that there's no need to use return. Any unconsumed objects will be put in the pipeline. If you don't understand the pipeline, you should read up on it, because it is key to understanding PowerShell.

  • \$\begingroup\$ Thanks for this, your second example makes sense and works for me but your first does not. Breaking it down $x.allelements returns as expected, when I append the piped commands nothing is returned. I admit I don't really understand the function of the ? nor do i understand the purpose of the $tagname variable you call within the script block. Do you mind expanding on these? \$\endgroup\$ – Patrick Nov 12 '15 at 12:08
  • \$\begingroup\$ @Patrick, sorry about that, there was a typo. I have fixed it now. (I don't know how that happened. I do test, and I always copy-and-paste.) I will add some explanatory text above about the question mark. \$\endgroup\$ – Dangph Nov 12 '15 at 15:09
  • \$\begingroup\$ Thank you for this. I can't believe I hadn't grasped the concept that ? (or indeed %) after a pipe was simply an alias. Mindblown.gif. Thank you for your answer, I really appreciate the time and thought. \$\endgroup\$ – Patrick Nov 13 '15 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.