📜 ⬆️ ⬇️

Through the ports on the equipment to the user machines

Good time of day, Habrazhiteli.

This post tells you how with the help of PowerShell we were again able to make our lives a little easier and automate the search for equipment and ports on which users' computers sit. This is necessary at the moment when it is necessary to forward vlans (well, or just for information).
"

Prehistory

It all started about a year ago. Once our senior administrator suggested that I try to write a script on this topic. Scratching a pumpkin, I agreed to try. Before that, I had never worked with network equipment (well, the home router does not count), so he threw off an approximate sequence of commands with which all this could be done.

Using Putty, I tried to do all this manually, everything worked out and I began to think how to automate all this. And not just to automate, but to do it with PowerShell. Why precisely PoSh? At that time I had a great crush on him (although I am still not getting off of him now), it was possible to do this in something else, but I really wanted to do it through PoSh.
')
Since it was required to connect to the equipment via Telnet and SSH (mainly via Telnet, since at that time SSH was not everywhere, but more on that later) I spent a lot of time on the Internet to find out how PowerShell can work with these protocols.
Then I turned to 2 connection mechanisms:
  1. using plink.exe (from Putty)
  2. Netcmdlets company / n software

Using mostly plink.exe, I got something that was difficult to call a work of art. It was a huge, cluttered script that absolutely no one wanted to show. And even more so to write about this article here.
And since it worked (periodically, I even used it), I postponed its optimization indefinitely and did other things.

The time has passed, a lot has changed during this time, but I did not forget about my brainchild, periodically trying to rewrite it again and get rid of a bunch of unnecessary things. Finally I managed it!

Vader, rise!

The most important thing that happened was that they updated the firmware on the switches, and now it became possible to connect to them via SSH. Well, that’s great, we’ve scored on telnet.
This was followed by another change: since telnet is no longer needed, we can stop using plink.exe (from Putty) and NetCmdlets gets all the glory.
Having talked quite a bit with the technical support of this company, I finally figured out the structure of these tools, and began to work.

What I needed:
  1. Check the correctness of the IP address of the computer
  2. Check whether the computer is online
  3. Connect to each equipment sequentially, starting with the most important, and find out on which ports our device hangs
  4. Show all this to the user, so that he (ie, I) would be satisfied

Netcmdlets

Since I want to say thank you to the people who made them, a small digression and a few words about these cmdlets:
You can read about them and download them here . You can download both the trial version (for 30 days) and the full version (for $ 100 per computer). I used the trial version because after the expiration date, you can simply reinstall it.
Recently, on the powershellmagazine.com resource, these cmdlets were heard for free, I managed to grab it. So be on the alert! But back to our sheep.
Choosing a set of these cmdlets, I began to study them. This set is quite large, so I will not describe everything that is there. I’ll stop at 2:

You can only do Invoke-SSh, but then you will not have a permanent session with the device (that is, say, you will not be able to execute commands in “conf t” on the device). Using this Connect-SSh cmdlet, we create a connection to the device, and the Invoke-SSh cmdlet executes commands. Everything is quite simple.
The important point is that these cmdlets can work together with the Get-Credential cmdlet, in which you can write credentials to connect to equipment (see examples in the script), i.e. the credentials are not stored in clear text in the script (as I had with plink.exe). I'm not paranoid, but love to be safe.

Parsing output and regular expressions

I was expecting a very romantic parsing of the output of the Cisco iOS shell, because the Invoke-SSH cmdlet shows the output in the Text column, i.e. passing the output to a variable, we get a large text.
This is where regular expressions come to the rescue. But who parsys great texts, knows that getting the right fragment from there is not easy enough, but thanks to PowerShell, we brilliantly got out of this situation.
For now, read PowerShell in Action 2-nd Edition. To anyone who studies PoSh, I highly recommend this book. And in it, I read about such a thing as a named regexp. The bottom line is that when PowerShell contains the $ Mathces variable, in which all matches are entered when using regular expressions:

PS [13] > $Matches PS [14] > $a="ass 123 saa" PS [15] > $a -match "\d+" True PS [16] > $Matches Name Value ---- ----- 0 123 

But that is not all! The whole point is that if we add
 ?   ,   : 
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)
? , :
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)
? , :
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)
? , :
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)
 ?   ,   : 
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)
? , :
PS [17] > $a -match "(?<Numbers>\d+)" True PS [18] > $Matches Name Value ---- ----- Numbers 123 0 123 PS [19] > $Matches.Numbers 123

( split!). , (, PowerShell ), .
, ?


, .
## Function LastSwitch { "IP : {0}, {1}" -f $IpSwitch,$Port If ($CiscoPhone) {" Cisco IP Phone"} Read-Host "Press Enter for continue..." break } ## For (;;) { $ip=Read-host "Enter ip" If ($ip -match "(\d{1,3}\.){3}\d{1,3}") {break} else {Write-Warning "Invalid IP address! Try again..."} } ## if ((test-connection $ip -quiet) -ne "True") { Write-Warning " !" Read-Host "Press Enter to continue..." break } $cred = get-credential Admin ## $IpSwitch = "10.138.30.1" ## $MAC = $null $CiscoPhone = $false For (;;) { $conn = Connect-ssh -Server $IpSwitch -Credential $cred -ShellPrompt "#" -Force Invoke-SSH -Connection $conn -Command "terminal length 0" | out-null Invoke-SSH -Connection $conn -Command "ping $ip" | out-null If (!$MAC) { ## ((Invoke-SSH -Connection $conn -Command "sh arp | i $ip ").text | Where-Object {$_ -match "\w"}) -match "(?<MAC>\w{4}\.\w{4}\.\w{4})" | out-null $MAC = $Matches.MAC } ## , (((Invoke-SSH -Connection $conn -Command "sh mac address-table address $MAC").Text | where-object {$_ -match $mac}) | Select-Object -First 1) -match "(?<port>((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})?)" | out-null $port = $Matches.Port ## $portInfo = (Invoke-SSH -Connection $conn -Command "show mac address-table interface $port").Text | where-object {$_ -match $port} If (($portInfo | measure).Count -eq 1) {LastSwitch} ## $DetailPortInfo = (Invoke-SSH -Connection $conn -Command "sh cdp neighbors $port detail" -Force).Text ## "Cisco IP phone", IP . If ($DetailPortInfo -match "Cisco IP phone") {$CiscoPhone = $true; LastSwitch} (($DetailPortInfo | where-object {$_ -match "IP address: (\d{1,3}\.){3}\d{1,3}"}) | Select-Object -First 1) -match "(?<ip>(\d{1,3}\.){3}\d{1,3})" | out-null "IP : {0}, {1}" -f $IpSwitch,$Port $IpSwitch = $Matches.IP Disconnect-SSH $conn }
:
Get-Credential. , , . 1 (.. ( PowerShell: get-help | more )). , .. Invoke-SSH , . , terminal length 0 ((\D{2}\d{1,3})/|Po)(\d{1,3})(/\d{1,3})? - , . : Fa5, Gi0/2, Te2/0/8, Po255 .. ( , , ) Cisco IP phone, , ( Invoke-SSH), (out-null)

Source: https://habr.com/ru/post/149191/


All Articles