Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- update_client_hostnames - Check Meraki wireless clients for a GUID/UUID in the description, if found change the name to the hostname in DHCP.
- You will need to create a scheduled task to run this script that checks every x minutes / hours. We have it check hourly.
- Important Note:
- * This script does not handle devices that have been renamed after replacing the GUID/UUID with the hostname found in DHCP. You'll need to manually
- update these clients or write a script to do it ;)
- * This script will only grab a max of 1000 clients seen in the last 4 hours
- To 'secure' your Meraki API Key:
- The script below in 'CUT BELOW / ABOVE' can be used to generate a 'secure' password.
- It means you can store your meraki api key under an account not used for logons and
- create a task schedule with the credentials of that account. If anyone else
- tries to read the file they won't be able to unless they logon under the account
- that created the file. When prompted for a username you can leave it blank or put
- whatever in as only the password portion is used to store the meraki api key.
- ---- CUT BELOW ----
- # Instead of storing the plain text password to disk
- #
- # If anyone besides the user whom created the password tries to load the secure file, it won't work.
- # It'll give a "Key not valid for use in specified state." exception
- $cred = get-credential
- $username = $cred.GetNetworkCredential().UserName
- $password = $cred.GetNetworkCredential().Password
- $secureStringPwd = $password | ConvertTo-SecureString -AsPlainText -Force
- $creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd
- $secureStringText = $secureStringPwd | ConvertFrom-SecureString
- # You can either save this to $password and use read.ps1 to read it back in or save it to a file and read it back in and convert to a pscredential object
- $file = "$PSScriptRoot\secure.txt"
- Set-Content $file $secureStringText
- $username = $null
- $password = $null
- # ---- CUT ABOVE ----
- ^^ The above script is needed at the below part in this script:
- # retrieve apikey - to create the secure.txt file see above comments for the script
- $file = "$PSScriptRoot\secure.txt"
- $pass = Get-Content $file
- $securePwd = $pass | ConvertTo-SecureString
- $cred = New-Object System.Management.Automation.PSCredential("None", $securePwd)
- $apikey = $cred.GetNetworkCredential().Password
- $cred = $null
- #
- # Helpful links if you get stuck:
- #
- # The Cisco Meraki Dashboard API -> Need to turn your Meraki API on if it isn't already and generate a Meraki API key
- # https://documentation.meraki.com/zGeneral_Administration/Other_Topics/The_Cisco_Meraki_Dashboard_API
- #>
- <#
- # Logging information.
- #>
- function logger($msg, $show_to_screen=$true) {
- # log to file and optionally to screen by default
- $out = "$(Get-Date -UFormat "%Y-%b-%d %T") - $msg"
- if ($show_to_screen) {
- write-host $out
- }
- add-content -Path "$PSScriptRoot\status.log" -Value $out -Force
- }
- function ApiError($url=$null) {
- $err_url = ""
- if ($url -ne $null) {
- $err_url = " [$url]"
- }
- $msg = "Exception$err_url::Status Code: " + $_.Exception.Response.StatusCode.value__ + " - " + $_.Exception.Response.StatusDescription
- Write-Host -BackgroundColor:Black -ForegroundColor:Red $msg
- logger($msg, $false)
- }
- function api_get($key, $url) {
- $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
- $headers.Add("X-Cisco-Meraki-API-Key", "$apikey")
- #$headers.add("Content-Type", "application/json")
- try {
- $response = Invoke-RestMethod -Uri $url -Headers $headers -ContentType "application/json" -Method Get
- }
- catch {
- ApiError($url)
- }
- return $response
- }
- #
- # api_push - Pushes a change to the Meraki Cloud
- #
- function api_push($apikey, $url, $json, $method) {
- # Info on why this is necessary is at -> https://documentation.meraki.com/zGeneral_Administration/Other_Topics/The_Cisco_Meraki_Dashboard_API
- $headers = @{
- "X-Cisco-Meraki-API-Key" = "$apikey"
- }
- # Handle Redirection - Ugly, but it won't work without picking up the redirected url
- $response = Invoke-WebRequest -Uri $url -Headers $headers -ContentType "application/json" -Method $method -Body $json -MaximumRedirection 0
- $redirect = $response.Headers.Location
- try {
- $response = Invoke-WebRequest -Uri $redirect -Headers $headers -Method $method -Body $json -ContentType "application/json"
- }
- catch {
- ApiError($url)
- }
- return $response
- }
- #
- # api_post - friendly function as there is post or put, put removed as it isn't needed in this script
- #
- function api_post($apikey, $url, $json) {
- return api_push $apikey $url $json "Post"
- }
- # retrieve apikey - to create the secure.txt file see above comments for the script
- $file = "$PSScriptRoot\secure.txt"
- $pass = Get-Content $file
- $securePwd = $pass | ConvertTo-SecureString
- $cred = New-Object System.Management.Automation.PSCredential("None", $securePwd)
- $apikey = $cred.GetNetworkCredential().Password
- $cred = $null
- # Turn on TLS 1.2 for Invoke-RestMethod
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- # base url for api calls
- $base_url = "api.meraki.com/api/v0"
- # Name of your wireless network
- $wireless_network_name = "***NAME OF YOUR WIRELESS NETWORK NOT SSID***"
- # Fetch Organisation ID
- write-host "Fetch Organisation ID..." -NoNewline
- # API INFO - https://developer.cisco.com/meraki/api/#/rest/api-endpoints/organizations/get-organization
- $response = api_get $apikey "https://$base_url/organizations"
- $org_id = $response.id
- # Fetch Network IDs
- write-host "Fetch Network IDs..." -NoNewline
- # API INFO - https://developer.cisco.com/meraki/api/#/rest/api-endpoints/networks/get-organization-networks
- $value = api_get $apikey "https://$base_url/organizations/$org_id/networks"
- write-host "Done!`n" -NoNewline
- # Get the X Wireless network ID
- # Make sure to replace ***NAME OF YOUR WIRELESS NETWORK NOT SSID*** above with your wireless network name found in the Meraki Cloud dashboard
- $network_id = $null
- foreach ($v in $value) {
- if ($v.name.Contains($wireless_network_name)) {
- $network_id = $v.id
- break
- }
- }
- <#
- [
- [
- IPAddress : x.x.x.x
- ScopeId : x.x.x.x
- Description :
- ClientId : XX-XX-XX-XX-XX-XX
- HostName : XXXX.XXX.XXX
- ClientType : Dhcp
- AddressState : Active
- DnsRR : AandPTR
- DnsRegistration : Complete
- LeaseExpiryTime : 24/08/2019 11:58:03 AM
- NapCapable : x
- NapStatus : x
- ProbationEnds :
- PolicyName :
- ServerIP : X.X.X.X
- ],
- ...
- ]
- #>
- # DHCP Wifi Scope 1
- # computername - the server that issues the DHCP lease
- # scopeid - Replace X.X.X.X with the network address of the wifi network e.g. in DHCP it might look like 'Scope [192.168.0.0] ...'
- $dhcp_leases = get-dhcpserverv4lease -computername SERVER_NAME_HERE -scopeid X.X.X.X
- # DHCP Wifi Scope 2
- # computername - same as above
- # scopeid - same as above
- # this is just for additional wifi networks
- $dhcp_leases += get-dhcpserverv4lease -computername SERVER_NAME_HERE -scopeid X.X.X.X
- if ($network_id -ne $null) {
- <#
- [
- [
- id : kXXXXXX
- mac : XX:XX:XX:XX:XX:XX
- description : XXXXXXXXXXX
- ip : XX.XX.XX.XX
- ip6 : XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXX
- user : host/XXXXXXXXXXXXXXX
- firstSeen : 2019-01-09T02:27:26Z
- lastSeen : 2019-08-21T02:03:49Z
- manufacturer : Intel
- os : Windows 10
- recentDeviceSerial : XXXX-XXXX-XXXX
- recentDeviceName : XXXX
- recentDeviceMac : XX:XX:XX:XX:XX:XX
- ssid : XXXXXX
- vlan : XX
- switchport :
- usage : @{sent=11991; recv=75431}
- ],
- ...
- ]
- #>
- # 28800 = 8 hours
- # 14400 = 4 hours
- #
- # this will only grab clients seen in the last 4 hours, as it is in seconds you can change it
- # API INFO - https://developer.cisco.com/meraki/api/#/rest/api-endpoints/clients/get-network-clients
- $clients = api_get $apikey "https://$base_url/networks/$network_id/clients?perPage=1000×pan=14400"
- $msg = "Clients: $($clients.Length)"
- logger($msg)
- # Find the GUID/UUID pattern
- foreach ($client in $clients) {
- # match example: 16ff5ae6-48a8-4fbf-8486-1a6673ff0ee4
- if ($client.description -match ".{8}-.{4}-.{4}.{12}") {
- #$client | select description, lastSeen, user, ip
- $mac = $client.mac -replace ':', '-'
- # look for a match in dhcp leases
- $found = $false
- foreach ($lease in $dhcp_leases) {
- # match MAC and IP to update 'provision' the hostname in Meraki
- if ($lease.ClientId -eq $mac -and $lease.IPAddress -eq $client.ip) {
- $hostname = $lease.HostName
- # strip domain name # This is stripped from the DHCP lease info, it'll be different in your domain so update this
- if ($hostname -like "*.XXX.local") {
- $hostname = $hostname.split('.')[0]
- }
- $log = "Converted <desc: $($client.description) IP: $($client.ip) MAC: $($client.mac)> to DHCP IPv4 Hostname: $hostname"
- logger($log)
- # perform the update of the computer's name by provisioning the device
- # API INFO - https://developer.cisco.com/meraki/api/#/rest/api-endpoints/clients/provision-network-clients
- # You may need to adjust the devicePoliy and groupPolicyId if using something other than the default
- # for your devices.
- $url = "https://$base_url/networks/$network_id/clients/provision"
- $data = @{
- mac=$client.mac
- name=$hostname
- devicePolicy="Normal"
- groupPolicyId="101"
- }
- $json = $data | ConvertTo-Json
- $value = api_post $apikey $url $json
- $found = $true
- }
- }
- if ($found -eq $false) {
- $msg = "No DHCP match found for <desc: $($client.description) IP: $($client.ip) MAC: $($mac)>"
- logger($msg)
- }
- }
- }
- }
- else {
- logger("Unable to find the network id for XXX")
- }
- $apikey = $null
- $dhcp_leases = $null
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement