Link to home
Start Free TrialLog in
Avatar of Rich Rumble
Rich RumbleFlag for United States of America

asked on

Search for host details, as well as IP subnet CIDR information

Building off of https://www.experts-exchange.com/questions/29131838/Search-CIDR-subnet-ranges-with-powershell.html
I'd like to have a second file with known entries be searched first, then search the CIDR.csv failing a result on the main fields. I'd like to search on the main fields, IP, Host and User
Inventory.csv
IP_Address(s), Hostname, User, Notes
10.1.2.3, Workstation003, Jane Doe, HR Admin
10.10.0.3/1.2.3.4, Workstation001, John Doe, IT Analyst
10.1.2.30, Workstation007, James Bond, Janitor
10.69.69.23, WorkstationNiner, Tommy Boy, Sales
10.10.0.4, Workstation002, John Doe, IT Analyst

Open in new window


In the above, searching based on User "John Doe" should have two results (on two lines)
.\finddetails "John Doe" (maybe switches are needed? Like -i = ip, -h=host, -u=user?)
IP_Address(s), Hostname, User, Notes, Subnet
-------------- -------------- -------------- --------------
10.10.0.3/1.2.3.4, Workstation001, John Doe, IT Analyst (Production, unknown)
10.10.0.4, Workstation002, John Doe, IT Analyst

Open in new window

(Production)
[/code]
./finddetails 10.8.0.9
IP_Address(s), Hostname, User, Notes, Subnet
-------------- -------------- -------------- --------------
10.8.0.9, ???, ???, Telco, 10.8.0.0/24

Open in new window

Something to that effect if that makes sense? If the IP doesn't match anything, then some nice error :)
Let me know if you have questions on the details, thanks!
-rich
ASKER CERTIFIED SOLUTION
Avatar of oBdA
oBdA

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Rich Rumble

ASKER

As usual, way above and beyond! Thanks!
-rich
They changed the format on me! I've done a comlete copy paste, no spaces in the CSV and items that contain more than one are double quoted with a comma separating, not the slash anymore :(
And more changes, the domain is listed in some users, not on others, or they are local, and then on shared PC's they have more than one user and often also has the domain with them, so they are double quoted and csv'd
IP_Address(s),Hostname,User,Notes, on-line, offline
10.1.2.3,Workstation003,user1,HRAdmin,1/11/2019 20:58,
"10.10.0.3,1.2.3.4",Workstation001,"domain\user2,domain\user3",IT Analyst,,1/11/2019 10:58
10.1.2.30,Workstation007,localuser,Janitor,,1/11/2019 20:22
10.69.69.23,WorkstationNiner,domain\user5,Sales,,,
"10.10.0.4,1.2.3.6",Workstation002,"localuser,localuser2",IT Analyst,1/16/2019 07:58,,

Open in new window

I tried changing the IP delimiter in the script and that didn't seem to be enough.

Cannot process argument transformation on parameter 'IPAddress'. Cannot convert value "1.2.3.4 Workstation002" to type "System.Net.IPAddress". Error: "An invalid IP address was specified."
Thanks!
Avatar of oBdA
oBdA

This works for me with the sample data:
[CmdletBinding(DefaultParameterSetName='IPAddress')]
Param(
	[Parameter(Position=0, Mandatory=$true, ParameterSetName='IPAddress')]
	[Alias('I')]
	[IPAddress[]]$IPAddress,
	[Parameter(Position=0, Mandatory=$true, ParameterSetName='Hostname')]
	[Alias('H')]
	[String[]]$Hostname,
	[Parameter(Position=0, Mandatory=$true, ParameterSetName='User')]
	[Alias('U', 'Username')]
	[String[]]$User
)
$addressDelim = ','
Function ConvertTo-DecimalAddress([IPAddress]$IPAddress) {
	$bytes = $IPAddress.GetAddressBytes()
	[array]::Reverse($bytes)
	[BitConverter]::ToUInt32($bytes, 0)
}
Function Find-Subnet([String]$IPAddress) {
	$rows = $IPAddress.Split($addressDelim) | ForEach-Object {
		$address = ConvertTo-DecimalAddress -IPAddress $_.Trim()
		If ($row = $Script:cidr | Where-Object {($_.FirstAddress -le $address) -and ($address -le $_.LastAddress)}) {
			$row
		} Else {
			Select-Object -InputObject 'unknown' -Property @{n='CIDR'; e={$_}}, @{n='Subnet_Name'; e={$_}}
		}
	}
	$rows.CIDR -join $addressDelim
	$rows.Subnet_Name -join $addressDelim
}
$cidr = Import-Csv -Path '.\CIDR.csv' | ForEach-Object {
	$firstAddress = ConvertTo-DecimalAddress -IPAddress $_.CIDR.Split('/')[0]
	$hosts = [math]::Pow(2, (32 - $_.CIDR.Split('/')[1])) - 1
	Select-Object -InputObject $_ -Property *, @{n='FirstAddress'; e={$firstAddress}}, @{n='LastAddress'; e={$firstAddress + $hosts}}
}
$inventory = Import-Csv -Path '.\Inventory.csv'

Switch ($PSCmdlet.ParameterSetName) {
	'IPAddress'	{$source = $IPAddress;	$whereFilter = {$_.'IP_Address(s)' -match "\b$([regex]::Escape($pattern))\b"}}
	'Hostname'	{$source = $Hostname;	$whereFilter = {$_.Hostname -like $pattern}}
	'User'		{$source = $User;		$whereFilter = {$_.User -match "\b$([regex]::Escape($pattern).Replace('\*', '.*').Replace('\?', '.'))\b"}}
}
$source | ForEach-Object {
	$pattern = $_
	If ($rows = $inventory | Where-Object $whereFilter) {
		$rows | ForEach-Object {
			$subnetCidr, $subnetName = Find-Subnet -IPAddress $_.'IP_Address(s)'
			Select-Object -InputObject $_ -Property *, @{n='Subnet_Name'; e={$subnetName}}, @{n='Subnet_CIDR'; e={$subnetCidr}}
		}
	} Else {
		$subnetName = 'unknown'
		If ($PSCmdlet.ParameterSetName -eq 'IPAddress') {
			$subnetCidr, $subnetName = Find-Subnet -IPAddress $pattern
		}
		If ($subnetName -eq 'unknown') {
			Write-Warning "No record found for $($PSCmdlet.ParameterSetName) '$($_)'!"
		} Else {
			Select-Object -InputObject $pattern -Property `
				@{n='IP_Address(s)'; e={$_}},
				Hostname, User, Notes,
				@{n='Subnet_Name'; e={$subnetName}},
				@{n='Subnet_CIDR'; e={$subnetCidr}}
		}
	}
} 

Open in new window

That does work, maybe I messed something up in the previous one when I was working on it, thanks again!