none
Getting MAC Addresses from DHCP for Printers RRS feed

  • Question

  • Hello everyone! I want to premise this by letting you all know that I've only been dabbling with PowerShell for about a month now so don't judge me too harshly. I'd also like to apologize for the naming of my variables up front. I realize they may be hard to follow. :S

    I have been trying to devise a way to get MAC addresses for printers. I can't seem to find anything that really helps my case without running commands from the server itself which I don't have access to (highest rights in my org, but the server is controlled by a higher entity). However, I do have access to the console and can do most things to alter DHCP, I just can't log into the server itself.

    That being said, I came up with a script that will query DHCP for a specific IP address in order to display its information. It was originally intended for printers, but I thought it might be a nice thing for my user to be able to query for any IP they desire. Here is what I came up with:

    #Gather Admin Credentials to Open an Elevated PS Window
    $MyWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $MyWindowsPrinipal=new-object System.Security.Principal.WindowsPrincipal($MyWindowsID)
    
    $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
    
    if ($MyWindowsPrinipal.IsInRole($adminRole))
        {
        $host.UI.RawUI.WindowTitle=$MyInvocation.MyCommand.Definition + "(Elevated)"
        $host.UI.RawUI.BackgroundColor= "DarkBlue"
        clear-host
        }
    Else
        {
        $newProcess = New-Object System.Diagnostics.ProcessStartInfo "Powershell";
        $newProcess.Arguments = "& '" + $MyInvocation.MyCommand.Path + "'"
        $newProcess.Verb = "runas";
        [System.Diagnostics.Process]::Start($newProcess);
        exit
        }
    
    Write-Host -NoNewLine "Press any Space Bar to continue..."
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    
    #Getting IP Through an Input Box
    Add-Type -AssemblyName Microsoft.VisualBasic
    $IP = [Microsoft.VisualBasic.Interaction]::InputBox('Enter the IP Address you are looking for','DHCP','')
    $1oct = ($IP).split('.')[0]
    $2oct = ($IP).split('.')[1]
    $3oct = ($IP).split('.')[2]
    
    #Sets 3rd Octet variable to equal the correct IP scope for the IP given.
    If ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    ElseIf ($3oct -match "###")
        {
        $3oct = "###"
        }
    Else
        {
        $3oct = $3oct
        }
    
    #Gathers DHCP info for the IP that was given across all DHCP Servers.
    $Server1 = netsh dhcp server \\SERVER scope "$1oct.$2oct.$3oct.0" show clients | findstr "$IP"
    $Server2 = netsh dhcp server \\SERVER scope "$1oct.$2oct.$3oct.0" show clients | findstr "$IP"
    
    #Displays a message box if neither server can find the given IP.
    If ($Server1 -eq $null -and $Server2 -eq $null)
        {
        $VB = new-object -comobject wscript.shell
        $VB.popup("The IP address could not be found in DHCP.", 0, "DHCP Info", 0) | Out-Null
        }
    #If The 1st server can't find the IP, Use the 2nd to find pull the information
    ElseIf ($Server1 -eq $null)
        {
        $Subnet2 = ($Server2).Split('-')[1]
        $MAC12 = (($Server2).Split('-')[2]).ToUpper()
        $MAC22 = (($Server2).Split('-')[3]).ToUpper()
        $MAC32 = (($Server2).Split('-')[4]).ToUpper()
        $MAC42 = (($Server2).Split('-')[5]).ToUpper()
        $MAC52 = (($Server2).Split('-')[6]).ToUpper()
        $MAC62 = (($Server2).Split('-')[7]).ToUpper()
        $Lease2 = ($Server2).Split('-')[8]
    
        #Export to a Popup Box
        $VB = new-object -comobject wscript.shell
        $VB.popup("IP: $IP
    
    Subnet: $Subnet2
    
    MAC Address: $MAC12-$MAC22-$MAC32-$MAC42-$MAC52-$MAC62 
    
    Lease Expiration: $Lease2", 0, "DHCP Info", 0) | Out-Null
        }
    #Script will use info from 1st server if it was able to be found
    Else 
        {
        $Subnet1 = ($Server1).Split('-')[1]
        $MAC11 = (($Server1).Split('-')[2]).ToUpper()
        $MAC21 = (($Server1).Split('-')[3]).ToUpper()
        $MAC31 = (($Server1).Split('-')[4]).ToUpper()
        $MAC41 = (($Server1).Split('-')[5]).ToUpper()
        $MAC51 = (($Server1).Split('-')[6]).ToUpper()
        $MAC61 = (($Server1).Split('-')[7]).ToUpper()
        $Lease1 = ($Server1).Split('-')[8]
    
        #Export to a Popup Box
        $VB = new-object -comobject wscript.shell
        $VB.popup("IP: $IP
    
    Subnet: $Subnet1
    
    MAC Address: $MAC11-$MAC21-$MAC31-$MAC41-$MAC51-$MAC61 
    
    Lease Expiration: $Lease1", 0, "DHCP Info", 0) | Out-Null
        }


    I've obviously had to change some things for security reasons, but that is pretty much it. The only question I seem to be unable to answer is that I would like to display the name associated with the IP address. I've been attempting to do a .split() with the results of a:

    netsh dhcp server \\SERVER scope $1oct.$2oct.$3oct.0 show clients 1 | findstr "$IP"

    but that doesn't seem to help as there's not anything for me to split to at that point. As in my previous method within my script is no longer good enough.

    My other question is how do I make my script loop back to the input box if they would want to search for another IP? I intend on having another popup box at the end prompting them with this question and if the response is "Yes" then I'd like it to loop back to input box. However, I am at a loss as to how to accomplish this as well. Any help would be greatly appreciated!



    • Edited by McCoid1017 Thursday, April 23, 2015 1:50 PM
    Thursday, April 23, 2015 1:14 PM

Answers

  • This will get everything:

    $p='192.168.1.1'
    $scope='192.168.1.0'
    
    $IP,$MAC,$expires,$type,$name=(netsh dhcp server \\sbs01 scope $scope show clients 1 |findstr $p).Split(' ',[system.stringsplitoptions]::RemoveEmptyEntries
    
    


    \_(ツ)_/


    • Edited by jrv Thursday, April 23, 2015 3:29 PM
    • Marked as answer by McCoid1017 Thursday, April 23, 2015 3:36 PM
    Thursday, April 23, 2015 3:27 PM

All replies

  • Why work so hard when you can just ask the printer.

    $p=[System.Net.DNS]::GetHostByName('Myprinter').AddressList[0].IPAddressToString
    ping $p
    $IP,$MAC,$type=(arp -a|findstr $p).Split(' ',[System.StringSplitOptions]::RemoveEmptyEntries)

    You now have the IP, Name and MAC. 


    \_(ツ)_/

    Thursday, April 23, 2015 1:54 PM
  • if your DHCP server is WS2012 you can also use WMI to get all of this info in one simple line.


    \_(ツ)_/

    Thursday, April 23, 2015 1:58 PM
  • All of my printers are on a printer VLAN so I can't arp -a in order to obtain the entry. We're implementing a print server now which is why we're gathering MAC Addresses. The only way this can work is if they're not on 802.1x yet (We're implementing the standard now). I wrote it this way so that if they need to get a printer's MAC and it's not on 802.1x, it should show up in DHCP under a different scope.

    As well our DHCP server is not 2012 nor would I have access to it even if it was. Like I said, I have access to the console but have no access to the server.

    I work in the Network Control Center on base and am pretty much left with minimal options based on my permissions. I have the highest here on base but all core servers are managed at another point. So I can look at a lot of stuff... just don't always have actual access to a lot of stuff.

    Thursday, April 23, 2015 2:12 PM
  • How can you have access to the console and not to the server?

    "netsh dhcp server" is access to the server. It requires that you have permissions on the server. You may not have change permission but you have read permission.

    To loop place the script in a file then call the scrip inside of a simple loop. You can also make a function out of the script and call the function in a loop.

    Use Test-Connection to retrieve the name.


    \_(ツ)_/

    Thursday, April 23, 2015 2:19 PM
  • That's exactly right. I have permissions to change what's on the server as far as DHCP goes but I can't gwmi anything on it or log into it. I basically just house the server. The way that the network is broken into subnets and the "limited" access or rights I have to important things is why I've had to resort to doing things the way I'm doing things. This script is purely for my own advancement in understanding and being able to utilize PS as a tool. The script itself I've tried to make dummy proof for the new guys I've got coming in. But thanks for the advice! I'll give that a shot and see how that goes! Any idea how I would be able to pull the "name" field from the "Netsh" cmd?

    Thursday, April 23, 2015 2:31 PM
  • DHCP does not support name. It is IP, scope and MAC only.  THe name can be many all pointing to the same IP.  DNS has that info.  Test-Connection will resolve the name(s).


    \_(ツ)_/

    Thursday, April 23, 2015 2:35 PM
  • netsh dhcp server \\SERVER scope "$1oct.$2oct.$3oct.0" show clients 1

    This will return all information pertaining to the entry, to include the name. But Test-Connection should work much better. Thanks for the help!
    Thursday, April 23, 2015 3:16 PM
  • How can you be sure that the scope is a full class C subnet?

    Yes the 1 arg does add the names


    \_(ツ)_/


    • Edited by jrv Thursday, April 23, 2015 3:21 PM
    Thursday, April 23, 2015 3:19 PM
  • are you referring to my variables? Namely the $3oct variable?

    Thursday, April 23, 2015 3:22 PM
  • This will get everything:

    $p='192.168.1.1'
    $scope='192.168.1.0'
    
    $IP,$MAC,$expires,$type,$name=(netsh dhcp server \\sbs01 scope $scope show clients 1 |findstr $p).Split(' ',[system.stringsplitoptions]::RemoveEmptyEntries
    
    


    \_(ツ)_/


    • Edited by jrv Thursday, April 23, 2015 3:29 PM
    • Marked as answer by McCoid1017 Thursday, April 23, 2015 3:36 PM
    Thursday, April 23, 2015 3:27 PM
  • are you referring to my variables? Namely the $3oct variable?

    "$1oct.$2oct.$3oct.0"

    That defines a full C subnet.  How do you know you are sub-netted and scoped that way? subnets can be of any size and boundary and a scope is usually al or part of a subnet.


     

    \_(ツ)_/

    Thursday, April 23, 2015 3:31 PM
  • thanks a lot! That did the trick!
    Thursday, April 23, 2015 3:36 PM
  • correct. I have access to view the entries via the console and also the means to talk to the people who set up these subnets. I actually hardcoded the scopes into the script by saying:

    #Sets 3rd Octet variable to equal the correct IP scope for the IP given.
    If ($3oct -match "44")
        {
        $3oct = "43"
        }
    Else
        {
        $3oct = $3oct
        }
    
    I took the real numbers out so that I could post the script here :P

    Thursday, April 23, 2015 3:47 PM