validate IP address entered by user - powershell

I am making a script to set the IP, subnet mask, gateway and DNS server address on a localhost. I have a working script but I would like to make sure that the IP addresses entered are numeric characters and within the range 0-255 for each Octet.
Any help would be appreciated.
$IP = Read-Host -Prompt 'Please enter the Static IP Address. Format 192.168.x.x'
$MaskBits = 24 # This means subnet mask = 255.255.255.0
$Gateway = Read-Host -Prompt 'Please enter the defaut gateway IP Address. Format 192.168.x.x'
$Dns = Read-Host -Prompt 'Please enter the DNS IP Address. Format 192.168.x.x'
$IPType = "IPv4"
# Retrieve the network adapter that you want to configure
$adapter = Get-NetAdapter | ? {$_.Status -eq "up"}
# Remove any existing IP, gateway from our ipv4 adapter
If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) {
$adapter | Remove-NetIPAddress -AddressFamily $IPType -Confirm:$false
}
If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) {
$adapter | Remove-NetRoute -AddressFamily $IPType -Confirm:$false
}
# Configure the IP address and default gateway
$adapter | New-NetIPAddress `
-AddressFamily $IPType `
-IPAddress $IP `
-PrefixLength $MaskBits `
-DefaultGateway $Gateway
# Configure the DNS client server IP addresses
$adapter | Set-DnsClientServerAddress -ServerAddresses $DNS

Check this link. You can cast the given string to [ipaddress].
PS C:\Windows\system32> [ipaddress]"192.168.1.1"
Above sample does not produce an error. If you're using an invalid ip address:
PS C:\Windows\system32> [ipaddress]"260.0.0.1"
Cannot convert value "260.0.0.1" to type "System.Net.IPAddress". Error: "An
invalid IP address was specified."
At line:1 char:1
+ [ipaddress]"260.0.0.1"
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastParseTargetInvocation
You'll receive an exception that can be caught.

Here is the aproach that combines the above two answers.
For a basic validation this oneliner could help
[bool]("text" -as [ipaddress])
But user may type something like "100" and it will successfully validate to ip address 0.0.0.100.
That's might be something not what you expect.
So i like to use regex and type validation combined:
function IsValidIPv4Address ($ip) {
return ($ip -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" -and [bool]($ip -as [ipaddress]))
}

Use regular expressions
$ipRegEx="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
if($ip -notmatch $ipRegEx)
{
#error code
}
You can search online about regular expressions and examples for IP. Just keep in mind that powershell is built on top of .NET, therefore when searching and reading for regular expressions, focus on the .NET or C# ones. For example this.
update
As it was pointed out afterwards by comments, the regex is not correct but it was posted as an example for the regular expressions validation. An alternative could be ((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]?)

Related

How to select specific string from the output table in PowerShell

I am trying to create the script which will resolve the IP address to DNS name and then
ping output computer number:
$name = Read-Host "Please enter IP address"
$comp = Resolve-DnsName $name | select NameHost -First 1
The output is
NameHost
COMPPL01-NB0128.domain.com ```
When I try to format the output, it gives me
#{NameHost=COMPPL01-NB0128.domain.com}
So then I can't ping the result using the command test connection
Test-Connection -ComputerName $comp
As I understood, test-connection cmdl is trying to ping the whole string NameHost=COMPPL01-NB0128.domain.com
How can I select only the computer name from that output and ping it?
So far it gives me an error message:
Test-Connection : Testing connection to computer '#{NameHost=COMPPL01-NB0128.domain.com}' failed:
A non-recoverable error occurred during a database
lookup
At line:1 char:1
Test-Connection -ComputerName $comp
CategoryInfo : ResourceUnavailable: (#{NameHost=COMPPL01-NB0128.domain.com}:String) [Test-Connection], PingException
FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand
There are two options:
Resolve-DnsName 8.8.8.8 | Select-Object -ExpandProperty NameHost
You can use Expand property to get host name value alone.
(Resolve-DnsName 8.8.8.8).NameHost
Using the Dot operator to get its properties.

How to see the hostname when you ping the server?

I pinged the servers and it is working (it shows me the ip address that could be pinged) but I want it to show the hostname and the ip address.
I tried to incorporate [System.Net.Data.Dns]::GetHostName(), but I don't know where to put it. I am a beginner using PowerShell. I also tried to used -and, but it doesn't work.
I understand how to do it python I just don't know how to translate it to PowerShell.
$columnC = "n1-1mon-i3fp04","n1-1mon-i3fp06","n1-1mon-i3fp07","n1-r-1mon-i3fp09","n1-r-1mon-i3fp10","n1-1mon-i3fp08","n1-1mon-i3fp03","n1-1mon-i3fp02","n1-1mon-i3fp111"
$columnC | % $_ {$Device = Resolve-DnsName -Name $_
$Device.[System.Net.Data.Dns]::GetHostName()
if (test-connection $Device.("IPAddress")) {write-host Device.("IPAddress") "Ping succeeded." -foreground green}
else {write-host $Device.("IPAddress") "Ping failed." -foreground red}}
The result shows an error message like the syntax is wrong. I want it to show both ip address and the hostname.
[edit - Theo pointed out that GetHostByName has been deprecated in favor of GetHostEntry. when i tested that, it gave more consistent results, so i swapped them.]
this will get the ComputerName, HostName, and Online status. then save those into a custom object, send the object to the $Results collection, and - finally - show what is in the collection. [grin]
# fake reading in a text file
# in real life use Get-Content
$ComputerList = #'
BetterNotBeThere
LocalHost
10.0.0.1
127.0.0.1
'# -split [environment]::NewLine
$Results = foreach ($CL_Item in $ComputerList)
{
try
{
$HostName = [System.Net.Dns]::GetHostEntry($CL_Item).HostName
}
catch
{
$HostName = '__Not Found__'
}
[PSCustomObject]#{
ComputerName = $CL_Item
HostName = $HostName
Online = Test-Connection -ComputerName $CL_Item -Count 1 -Quiet
}
}
$Results
output ...
ComputerName HostName Online
------------ -------- ------
BetterNotBeThere __Not Found__ False
LocalHost [MySysName] True
10.0.0.1 __Not Found__ False
127.0.0.1 [MySysName] True

powershell - storing cmdlet Get-DhcpServerv4Reservation into a variable and then printing it, doesn't give expected output

I'm running a DHCP server in Windows Server 2012 R2 with an active scope and I've made a script which asks the user for a MAC address and will then reserve an available ip from the scope to the user's MAC.
The actual reservation works without a problem but I've introduced an IF ELSE statement, with the hope that the conditional expression is evaluated as TRUE when a reservation is successful and to FALSE otherwise.
But the expression always evaluates to FALSE because storing the execution of the cmdlet Get-DhcpServerv4Reservation into a variable and then printing it, yields a really messed up output: basically it will print "DHCPServerv4Reservation" as many times as reservations present in the scope, instead of the output given when directly executing the cmdlet.
Here's the code:
clear-host
$mac=read-host -prompt "Please type the MAC address for the host "
$freeip=Get-DhcpServerv4FreeIPAddress -scopeid 10.10.10.0
Add-DhcpServerv4Reservation -ScopeId 10.10.10.0 -ClientId $mac -IPAddress $freeip
$reservedips=Get-DhcpServerv4Reservation -ScopeId 10.10.10.0
if ($reservedips -match $freeip) {
write-host "The ip $freeip has been succesfully reserved for the host with the MAC address $mac"
}
else {write-host "I'm sorry but there are no free ip addresses to be reserved"}
# this is just to see what's inside $reservedips
write-host $reservedips
Why is this happening? Thanks
The result of Get-DhcpServerv4Reservation is a reservation object.
The -match operator is for matching a string against a regular expression.
You might be looking to something like:
if (($reservedips | Where-Object { $_.IPAddress -eq $freeip })) {
# success
}
I think you consider restructuring your code to look something like this:
$mac=read-host -prompt "Please type the MAC address for the host "
$freeip=Get-DhcpServerv4FreeIPAddress -scopeid 10.10.10.0
try {
Add-DhcpServerv4Reservation -ScopeId 10.10.10.0 -ClientId $mac -IPAddress $freeip -ErrorAction Stop
} catch {
Write-Host "An error has occurred while trying to add a reservation for '$mac' with IP '$freeip'."
}
Adding -ErrorAction Stop forces all exceptions to be caught by the try/catch block.
This is the alternative I have come up with, which works
clear-host
$mac=read-host -prompt "Please type the MAC address for the host "
$freeip=Get-DhcpServerv4FreeIPAddress -scopeid 10.10.10.0
Add-DhcpServerv4Reservation -ScopeId 10.10.10.0 -ClientId $mac -IPAddress $freeip
$reservedips=Get-DhcpServerv4Reservation -ScopeId 10.10.10.0 | Where-Object ipaddress -eq $freeip
if ($reservedips -eq "") {write-host "I'm sorry but there are no free ip addresses to be reserved"}
else {write-host "The ip $freeip has been succesfully reserved for the host with the MAC address $mac"}

Setting Static IP on NICs - Powershell

I am creating a script which will run through a lot of the basic tasks when commissioning a new server. Now most servers have multiple NICs these days and I need to question the user (using the script) what NIC they want to assign the IP to.
At the moment I have:
$NICs = Get-WMIObject Win32_NetworkAdapterConfiguration -ComputerName $env:COMPUTERNAME | where{$_.IPEnabled -eq $true -and $_.DHCPEnabled -eq $true}
Which will put the NICs into $NICs I believe. However from here I want to print them out to the user, and then somehow assign a value to each NIC, like an index, so the user can type in, "1" or "2" so tell the script what NIC to apply the Ip configuration to which will be done like:
If($ipQuestion -eq "Y") {
$ipAddr = Read-Host "Enter IP Address: "
$subnet = Read-Host "Enter Subnet: "
$dns = Read-Host "Enter DNS: "
Write-Host "Multiple DNS servers?" -ForegroundColor Green
$multipleDNSServersQuestion = Read-Host
If($multipleDNSServersQuestion -eq 'Y'){
$dns2 = Read-Host "Enter Secondary DNS: "
}
$dGateway = Read-Host "Enter Default Gateway: "
}
$NIC.EnableStatic($ipAddr, $subnet)
$NIC.SetGateways($dGateway)
$NIC.SetDNSServerSearchOrder($dns, $dns2)
$NIC.SetDynamicDNSRegistration("TRUE")
Any ideas?
If you ensure $NICS is always an array, you can use the array index to specify each NIC. To ensure it is always an array do this:
$NICs = #(Get-WMIObject Win32_NetworkAdapterConfiguration -ComputerName $env:COMPUTERNAME | where{$_.IPEnabled -eq $true -and $_.DHCPEnabled -eq $true})
Then print out the info like so:
PS> $NICS = #(Get-WMIObject Win32_NetworkAdapterConfiguration)
PS> $NICS | Foreach {$i=-1}{$i++;$_} | ft #{n='index';e={$i}},Description,ServiceName
index Description ServiceName
----- ----------- -----------
0 WAN Miniport (L2TP) Rasl2tp
1 WAN Miniport (SSTP) RasSstp
2 WAN Miniport (IKEv2) RasAgileVpn
3 WAN Miniport (PPTP) PptpMiniport
4 WAN Miniport (PPPOE) RasPppoe
5 WAN Miniport (IP) NdisWan
6 WAN Miniport (IPv6) NdisWan
7 WAN Miniport (Network Monitor) NdisWan
8 Microsoft Kernel Debug Network Adapter kdnic
9 RAS Async Adapter AsyncMac
10 Broadcom NetXtreme Gigabit Ethernet b57nd60a
11 Microsoft ISATAP Adapter tunnel
12 Microsoft Teredo Tunneling Adapter tunnel
13 Microsoft 6to4 Adapter tunnel
14 Microsoft ISATAP Adapter tunnel
Then access each NIC like so:
$NICS[$selectedIndex]
$NICs = #(Get-WMIObject Win32_NetworkAdapterConfiguration ...)
will make $NICs an array, which can be accessed by (zero-based) index:
$NICs[0] # <-- first interface
$NICs[1] # <-- second interface
...
The way I would do it. If you have a look to the network connexions panel in the internet connexions. You can see the string the user know for his devices :
So in a dialog with the user I would give this name retreiving it with win32_NetworkAdapter joinning Win32_NetworkAdapterConfiguration with Index.
$NICs = Get-WMIObject Win32_NetworkAdapterConfiguration -ComputerName $env:COMPUTERNAME | where{$_.IPEnabled -eq $true -and $_.DHCPEnabled -eq $true}
$NICs | % {$i = (Get-WmiObject win32_NetworkAdapter -Filter "index=$($_.index)").NetConnectionID; $_} | ft #
{n='index';e={$i}},Description,ServiceName
index Description ServiceName
----- ----------- -----------
NET1 Intel(R) 82567LM Gigabit Network Conne... e1yexpress

Display NIC Info

In the following code, the $ipAddress stores both the IPV4 and IPV6. I only want the IPV4 displayed, is there anyway this can be done? Maybe with a split?
Also, the subnet mask prints 255.255.255.0 64 - where is this rogue 64 coming from?
Code:
ForEach($NIC in $env:computername) {
$intIndex = 1
$NICInfo = Get-WmiObject -ComputerName $env:computername Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress -ne $null}
$caption = $NICInfo.Description
$ipAddress = $NICInfo.IPAddress
$ipSubnet = $NICInfo.IpSubnet
$ipGateWay = $NICInfo.DefaultIPGateway
$macAddress = $NICInfo.MACAddress
Write-Host "Interface Name: $caption"
Write-Host "IP Addresses: $ipAddress"
Write-Host "Subnet Mask: $ipSubnet"
Write-Host "Default Gateway: $ipGateway"
Write-Host "MAC: $macAddress"
$intIndex += 1
}
Subnets work differently for IPv6, so the rogue 64 you are seeing is the IPv6's subnet mask - not the IPv4's.
The prefix-length in IPv6 is the equivalent of the subnet mask in IPv4. However, rather than being expressed in 4 octets like it is in IPv4, it is expressed as an integer between 1-128. For example: 2001:db8:abcd:0012::0/64
See here: http://publib.boulder.ibm.com/infocenter/ts3500tl/v1r0/index.jsp?topic=%2Fcom.ibm.storage.ts3500.doc%2Fopg_3584_IPv4_IPv6_prefix_subnet_mask.html
In order to remove it you can try the following (massive assumption made that IPv4 always comes first, but in all my experimenting it hasn't come second yet ;))
ForEach($NIC in $env:computername) {
$intIndex = 1
$NICInfo = Get-WmiObject -ComputerName $env:computername Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress -ne $null}
$caption = $NICInfo.Description
#Only interested in the first IP Address - the IPv4 Address
$ipAddress = $NICInfo.IPAddress[0]
#Only interested in the first IP Subnet - the IPv4 Subnet
$ipSubnet = $NICInfo.IpSubnet[0]
$ipGateWay = $NICInfo.DefaultIPGateway
$macAddress = $NICInfo.MACAddress
Write-Host "Interface Name: $caption"
Write-Host "IP Addresses: $ipAddress"
Write-Host "Subnet Mask: $ipSubnet"
Write-Host "Default Gateway: $ipGateway"
Write-Host "MAC: $macAddress"
$intIndex += 1
}
Hope this helps!