Use PowerShell to find IP Geolocation

In log files from web servers you often find strange requests. For example requests for wp-login.php on server that don’t have PHP or WordPress installed. Or that someone is requesting the same page over and over. Most of the times this is not a real problem. But it gets a problem or at least annoying when you get hundreds or thousands of these requests from the same IP address.

If I see things like that happening the first step is to find out where the request is coming from. For that I would go the certain websites. Based on the outcome I would then block that IP address or even the whole subnet in the firewall. Problem is that some of these website only allow a limit amount of lookups.

To make it more easier for myself I created a PowerShell function that uses a Rest API to do the lookup.

function Get-MvaIpLocation {
Retrieves Geo IP location data
This command retrieves the Geo IP Location data for one or more IP addresses
.PARAMETER IPAddress <String[]>
Specifies one or more IP Addresses for which you want to retrieve data for.
Get-MvaIpLocation -ipaddress '',''
'','' | Get-MvaIpLocation
Author: Mario van Antwerpen
Param (
[Parameter(ValueFromPipeline, Mandatory, Position = 0, HelpMessage = "Enter an IP Address")]
if ($_ -match '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$') {
} else {
Throw "$_ is not a valid IPv4 Address!"
begin {
Write-Verbose -message "Starting $($MyInvocation.Mycommand)"
process {
foreach ($entry in $ipaddress) {
$restUrl = "$entry"
try {
Write-Verbose -Message "Connecting to rest endpoint"
$result = Invoke-RestMethod -Method get -Uri $restUrl
Write-output $result
catch {
Write-Verbose -Message "Catched and error"
end {
Write-Verbose -message "Ending $($MyInvocation.Mycommand)"

The function is easy to use. It has one parameter -IPAddress that can contain one more IP Addresses. It also accepts pipeline input.

Edit firewall rule scope with PowerShell

One of our managed server customer frequently asked me to add an IP address to the scope of a firewall. Specially when they were still testing and did not want HTTP/HTTPS to be open for everyone.

Recent versions of PowerShell have Cmdlets that you can use to manage firewall rules. To set the scope you can use Set-NetFirewallAddressFilter Cmdlet. You use it like this.

Get-NetFirewallrule -DisplayName 'Test-Rule' | Get-NetFirewallAddressFilter | Set-NetFirewallAddressFilter -RemoteAddress

This works well and fast. The only problem is that it also overwrites everything that is already in the RemoteAddress list. To add an IP address you need to get the current value first, then add the new IP address to that value and finally set the new scope.

To make my life more easier I created a function to do all this. It is essentially a wrapper around Set-NetFirewallAddressFilter. And you can use it the same way.

Get-NetFirewallrule -DisplayName 'Test-Rule' | Get-NetFirewallAddressFilter | Add-MvaNetFirewallRemoteAdressFilter -IPAddresses
function Add-MvaNetFirewallRemoteAdressFilter {
This function adds one or more ipaddresses to the firewall remote address filter
With the default Set-NetFirewallAddressFilter you can set an address filter for a firewall rule. You can not use it to
add a ip address to an existing address filter. The existing address filter will be replaced by the new one.
The Add-MvaNetFirewallRemoteAdressFilter function will add the ip address. Which is very usefull when there are already
many ip addresses in de address filter.
.PARAMETER fwAddressFilter
This parameter conntains the AddressFilter that you want to change. It accepts pipeline output from the command
.PARAMETER IPaddresses
This parameter is mandatory and can contain one or more ip addresses. You can also use a subnet.
Get-NetFirewallrule -DisplayName 'Test-Rule' | Get-NetFirewallAddressFilter | Add-MvaNetFirewallRemoteAdressFilter -IPAddresses
Add a single IP address to the remote address filter of the firewall rule 'Test-Rule'
Get-NetFirewallrule -DisplayName 'Test-Rule' | Get-NetFirewallAddressFilter | Add-MvaNetFirewallRemoteAdressFilter -IPAddresses,,
Add multiple IP address to the remote address filter of the firewall rule 'Test-Rule'
You need to be Administator to manage the firewall.
[Parameter(ValueFromPipeline = $true,
Mandatory = $True)]
# Parameter help description
[Parameter(Position = 0,
Mandatory = $True,
HelpMessage = "Enter one or more IP Addresses.")]
process {
try {
#Get the current list of remote addresses
[string[]]$remoteAddresses = $fwAddressFilter.RemoteAddress
Write-Verbose -Message "Current address filter contains: $remoteAddresses"
#Add new ip address to the current list
if ($remoteAddresses -in 'Any', 'LocalSubnet', 'LocalSubnet6', 'PlayToDevice') {
$remoteAddresses = $IPAddresses
else {
$remoteAddresses += $IPAddresses
#set new address filter
$fwAddressFilter | Set-NetFirewallAddressFilter -RemoteAddress $remoteAddresses -ErrorAction Stop
Write-Verbose -Message "New remote address filter is set to: $remoteAddresses"
catch {

Disable IIS Server Headers

For security reasons some administrators want to hide what web server they are using. Personally I am not convinced that it would stop hackers to attack your server. But is is good practice to expose as little information as possible and security audits also require not to expose these pieces of information in the response headers.

In this post I will show you how to disable some common and not so common headers in Windows Server 2016 and higher. In the examples I disable the headers on the server level. It is however possible to disable some headers on site level.

Response headers that get returned by IIS

In the image above you can see that 2 headers can be interesting for attackers. The headers ‘Server’ and ‘X-Powered-By’.

To stop IIS returning the header ‘Server’ you can use the following command.

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST'  -filter "system.webServer/security/requestFiltering" -name "removeServerHeader" -value "True"
The header ‘Server’ is now disabled

Disabling the header ‘X-Powered-By’ can be done in two ways. You can do it from a prompt or from the GUI. From the prompt you use the following command.

Remove-WebConfigurationProperty  -pspath 'MACHINE/WEBROOT/APPHOST'  -filter "system.webServer/httpProtocol/customHeaders" -name "." -AtElement @{name='X-Powered-By'}

To turn it off in the GUI you open the Internet Information Services Manager, select the server and go to HTTP Response Headers. There you can remove the header.

Remove the X-Powered-By header in the GUI

After you have removed the header it will no longer show in the response. However it can come back when you install for example Application and Request Routing. But with a different value.

No more ‘Server’ and ‘X-Powered-By’ headers

When using another header will be returned. The ‘X-AspNet-Version’ header. This header can also be disabled. You do that with the following command.

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT'  -filter "system.web/httpRuntime" -name "enableVersionHeader" -value "False"

Earlier I mentioned that the ‘X-Powered-By’ header can come back when you install
Application and Request Routing. You can see that in the image below. Notice the same name but different value.

Notice the reappearance of the ‘X-Powered-By’ header

To turn this off you need the use the next commands.

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST'  -filter "system.webServer/proxy" -name "arrResponseHeader" -value "False"
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST'  -filter "webFarms/webFarm[@name='test']/applicationRequestRouting/protocol" -name "arrResponseHeader" -value "False"

You will have to restart IIS after these commands. Otherwise the headers will keep showing up.
The first command is to disable the header at the proxy level. The second command is to disable the header at the webfarm level. In my example the name of the webfarm is called test. You need to replace that with the name of your webfarm.

Now the server will return clean response headers.

Disable PowerShell beep on backspace

One thing that have found very annoying of the recent PowerShell versions is the beep that you hear when you press <BackSpace> and hit the beginning of the line. Fist I thought it was a setting in Windows 10 but I could not find it. And apparently it is the wrong place to look for it.

The beep sound is actually provided by the PSReadLine module which is used my default and also gives us these time saving keyboard shortcuts. See yesterday’s post. To turn it off is very easy. Just use the next command:

Set-PSReadlineOption -BellStyle None

After you executed this command you will not hear the beep anymore. At least not in your current PowerShell session. To make it permanent you need to put it in your profile script.

PowerShell Shortcuts

Unix Shells have many shortcuts that make life easier when using the shell. What people often forget is that de good old Command Prompt also had shortcuts. HowToGeek wrote a good article about it at

Recent versions of PowerShell also have even more powerful keyboard shortcuts. This are implemented by the PSReadLine Module. This module is included with PowerShell 5 and higher. The documentation can be found here:

When you are working in PowerShell and forgot which short cutes are available. Then you have two options. The first one is to go to the documentation, see the link above. Or you can type <Ctrl+Alt+?>. You will then get the full list of shortcuts. The list you see in the image below is only halve of the keyboard shortcuts. See for yourself in your own PowerShell Window.

You probably have been using some of these shortcuts without knowing it. Like the <UpArrow> and <DownArrow> keys to scroll thought the history. But did you know there are als keyboard shortcuts to search in the history? 
These are <Ctrl+r> and <Ctrl+s>. With the first one you can search backwards in your history. And with the second one you can search forward in your history. The screen will show if you do a backward for forward search.

To search backward in your history you first press <Ctrl+r> and then type part of the command or parameter you want to search for. The first result will be shown. Press <Ctrl+r> to scroll through the results. Press <Enter> to select the result and the press <Enter> again to execute the command. Forward search <Ctrl-s> works in the same way. 

Another useful shortcut is <Ctrl+SpaceBar>, this is like <Tab> on steroids. We have all used <Tab> to complete commands. But finding the right command can take some time. There are for example 16 commands that start with Get-NetIP. Instead of pressing <Tab> many times until you find the right one. You can also press <Ctrl+SpaceBar> and then get a nice menu with all the possible commands. You can then select the command you want with the <Arrow> keys and the press <SpaceBar> to use the command. To execute the command immediately just press <Enter>.

The shortcut <Ctrl+SpaceBar> not only works for command, but also for parameters and parameter values.

As you can see using shortcuts can make your life in PowerShell more easier and efficient. Give it a try.

New site, new start

I have been writing about IT stuff on and off on my blogĀ Lately it has been mostly off because I was busy with other things. I used to use my old blog as a sort of notebook for myself so I could easily find things that I learned and were important enough to write down. Of course I have written down things I did not want to forget in a notebook, in my case I used One Note from Microsoft.

For my job I use the Internet a lot for problem solving and learning. So it is only fair to share my knowledge with the world. And I will try to post here on a more regular basis.

English is not my native language, it is Dutch, so it is possible that not everything I will write is grammatically correct. Because not everyone can read Dutch I decided to keep my notes in English. So they can be helpful for more people.

See you soon!