This blog has moved to http://ThePowerShellGuy.com
Greetings /\/\o\/\/
In this post an example function/script (get-Site) that will find the AD site from a given IPAddress or Hostname.
In this script two nice new features in PowerShell are shown :
byRef Parameters and Switch Parameters.
also you could see I started using new aliases a couple of weeks ago.
I waited a long time using the common % and ? aliases as I keep forgetting them (see new on my blog) but now the fist one its still mine but the others are standard !
so these line are not necessary anymore :
# check needed aliases
if (!(get-command -ea SilentlyContinue new)) {set-alias new New-Object}
if (!(get-command -ea SilentlyContinue %)) {set-alias % ForEach-Object}
if (!(get-command -ea SilentlyContinue ?)) {set-alias ? Where-Object}
if (!(get-command -ea SilentlyContinue gwmi)) {set-alias gwmi get-WMIObject}
and you will see them a lot more ;-)
an other thing to note is that I did split up the function in 2 parts
the function Find-site and the function Get-site.
I do this becouse I like to paste code into the PowerShell Console.
b.t.w. this is also why I always put the { at the end of the line (oposed to on the next line) and why I never use tabs in the examples this is to keep it parsable from the interactive prompt , so that I can paste it. in a script this is not needed, but this keeps the samples easy to try.
if you want to build it in a script, this would be a more common form :
# get-Site.ps1
param ($Computer,[switch]$Verbose)
# Main function
Function Main {}
# helper functions
function FindSiteByIp {}
# Start Main Function
. Main
but to test by pasting them into the commandline when needed, I wil use 2 functions
The first function is the WorkHorse :
it will take a net.ipAddress Object as input, calculate possible Subnets of the IP number and try to find the subnet in AD till it does find one, then it does list the subnet and Site info from AD.
*Note* again for the example I did declare the AD stuff in one place, in a production script you would declare it only once and just set the filter in the loop.
but now with no AD handy its easy to remark the AD part and more readable I think for an example.
the first function does look like this :
# find the AD site from a given IP Number
# Helper Function for Get-Site Function / Script
# /\/\o\/\/ 2006
# http:/mow001.blogspot.com
Function find-Site {
param ([net.ipAddress]$ip)
# Resolve possible NetworkNumbers
for ($bit = 30 ; $bit -ge 1; $bit--){
[int]$octet = [math]::Truncate(($bit - 1 ) / 8)
$net = [byte[]]@()
for($o=0;$o -le 3;$o++) {
$ba = $ip.GetAddressBytes()
if ($o -lt $Octet) {
$Net += $ba[$o]
}ELSEIF ($o -eq $octet) {
$factor = 8 + $Octet * 8 - $bit
$Divider = [math]::pow(2,$factor)
$value = $divider * [math]::Truncate($ba[$o] / $divider)
$Net += $value
}ELSE {
$Net += 0
}
}
$NetWork = [string]::join('.',$net) + "/$bit"
# try to find Subnet in AD
if ($verbose.IsPresent) {write-host -fore 'yellow' "Trying : $network"}
$de = new directoryservices.directoryentry('LDAP://rootDSE')
$Root = new directoryservices.directoryentry("LDAP://$($de.configurationNamingContext)")
$ds = new directoryservices.directorySearcher($root)
$ds.filter = "(CN=$NetWork)"
$r = $ds.findone()
# If subnet found, write info and exit script.
if ($r) {
write-host -fore 'yellow' "AD Site found for $IP :"
$r.properties.name
$r.properties.description
$r.GetDirectoryEntry().siteObject
break
}
}
}
You will see some math to calculate the different network ID's possible.
then it will connect to the RootDSE to get the configurationNamingContext, connects to that with a Directory Searcher to find the subnet.
note also the :
$r.GetDirectoryEntry().siteObjectto get from the searchresult to the directoryentry and then to the Site Object.
I will not go into that in this post but search for
AD on my blog (top or botom of page) to find more info about PowerShell and AD and for
Byte for more info about the Math .
this Math was from an Old VB.NET "script" I made, working from former byte examples, this would be a way also : (I made this to refresh my IP math, from other byte examples) ;-)
# List possible networks for IP number
# /\/\o\/\/ 2006
# http://mow001.blogspot.com
function Parse-IP {
param ($sIp)
$ip = 0
if([net.IPAddress]::TryParse($sIP,[ref]$ip)){
$Bytes = $ip.GetAddressBytes()
for ($bits = 30;$bits -gt 0; $bits--) {
Switch ([system.Math]::Truncate($bits / 8)){
3 {
$script:sum = 0 ; for ($i= (8 - ($bits - 24));$i -le 7;$i++){if ($bytes[3] -band [math]::pow(2,$i)) {$script:sum += ([math]::pow(2,$i))}}
"$($bytes[0]).$($bytes[1]).$($bytes[2]).$script:sum/$bits"
}
2 {
$script:sum = 0 ; for ($i= (8 - ($bits - 16));$i -le 7;$i++){if ($bytes[2] -band [math]::pow(2,$i)) {$script:sum += ([math]::pow(2,$i))}}
"$($bytes[0]).$($bytes[1]).$script:sum.0/$bits"}
1 {
$script:sum = 0 ; for ($i= (8 - ($bits - 8));$i -le 7;$i++){if ($bytes[1] -band [math]::pow(2,$i)) {$script:sum += ([math]::pow(2,$i))}}
"$($bytes[0]).$script:sum.0.0/$bits"
}
0 {
$script:sum = 0 ; for ($i= (8 - ($bits));$i -le 7;$i++){if ($bytes[0] -band [math]::pow(2,$i)) {$script:sum += ([math]::pow(2,$i))}}
"$script:sum.0.0.0/$bits"
}
}
}
}
}
# test Code
parse-ip 130.144.215.100
this script also shows the usage of the [ref] variable in tryParse()
But on to the Second (not counting parse-IP sample), Script.
this will do 2 things, first it checks if the $computer parameter is an IP Address
by doing a tryParse() , (this method is much nicer to work with as the Parse function, as you canuse it in an IF statement as in the Example.
Before in Monad/MSH this was not yet possible as the [ref] type was not supported yet.) if its not an IP number it will assume it is a hostname and will try to ping it to get the IP adress. (if ICMP is disabled, but you are admin on the remote, you can also consider adding a WMI try also to get the IP address (for more WMI info search for WMI on my blog)
the Second thing you will see is the use of the [switch] parameter, as the boolean behavour is changed (see also release notes)
so the second script is a wrapper to make it more easy to use the find-ip function.
this script looks like this :
# find the AD site from a given IP Number
# Will Find an AD site from an IP Number or a Hostname
# /\/\o\/\/ 2006
# http://mow001.blogspot.com
Function Get-site {
param ($Computer,[switch]$Verbose)
$ip = 0
if ([net.ipaddress]::tryparse($computer,[ref]$ip)) {
find-site $ip
}ELSE{
if ($verbose.IsPresent) {write-host -fore 'yellow' "$Computer is No IP Address, trying Ping"}
$ping = new Net.NetworkInformation.Ping
&{TRAP{$ip = $null;continue}
if ($verbose.IsPresent) {write-host -fore 'yellow' "Pinging : $computer"}
$ip = $ping.send("$Computer").address
if ($ip) {
write-host -fore 'yellow' "$computer resolved to $ip";find-site $ip
}ELSE {
write-host -fore 'yellow' "$computer Not found"
}
}
}
}
and the 2 together can be used like this :
Get-site 10.10.215.249
Get-site mowPC44
Get-site mowPC44 -verbose
You see in the examples below Used the [switch] to togle verbose mode to output more info (shortened to -V), and in the scripts I use :
if ($verbose.IsPresent) {write-host -fore 'yellow' "text"}
constructions to output the extra info (only to console not to pipeline !).
Usage Examples :
# Get-Site using IP number
MowPS>Get-site 10.10.215.249
AD Site found for 10.10.215.249 :
10.10.208.0/20
MOW The Netherlands
CN=Mow-01,CN=Sites,CN=Configuration,DC=Mow,DC=com
# get site using HostName
MowPS>Get-site MowPC44
MowPC44 resolved to 10.10.215.249
AD Site found for 10.10.215.249 :
10.10.208.0/20
MOW The Netherlands
CN=Mow-01,CN=Sites,CN=Configuration,DC=Mow,DC=com
# Using Verbose Mode :
MowPS>Get-site mowPC44 -v
MowPC44 is No IP Address, trying Ping
Pinging : MowPC44
MowPC44 resolved to 10.10.215.249
Trying : 10.10.215.248/30
Trying : 10.10.215.248/29
Trying : 10.10.215.240/28
Trying : 10.10.215.224/27
Trying : 10.10.215.192/26
Trying : 10.10.215.128/25
Trying : 10.10.215.0/24
Trying : 10.10.214.0/23
Trying : 10.10.212.0/22
Trying : 10.10.208.0/21
Trying : 10.10.208.0/20
AD Site found for 10.10.215.249 :
10.10.208.0/20
MOW The Netherlands
CN=Mow-01,CN=Sites,CN=Configuration,DC=Mow,DC=com
You see that the Wrapper makes a a lot easier, by checking the IP number and the option to use a hostname using ping, I use the Ping version to locate SMS roaming clients, to check DPs.
Enjoy,
Greetings /\/\o\/\/
Tags : Monad msh PowerShell