I use the attached script to identify and tag devices that haven't checked in for 30+ days via the API. You could add a step to export the data to a CSV or other data source. ### SET THESE VARIABLES ###
# Set the number of days old before the device is tagged.
$cutOffDays = 30
# You will need to set your Organization ID Here. It is probably a 5-digit number
$orgId = ""
# You can find this by logging in to Meraki with your account.
$tennantFQDN = "xxx.meraki.com"
# You will need to get an API key from Meraki and put it here
$apiKey = ""
# Sets verbose output of REST requests
$verbose = $true
# Time (MS) to wait after each REST request (If you get errors about too many/too fast API requests, increase this number until you don't)
$throttleMS = 100
### ###
# Setting some headers to be used with later requests
$contentType = "application/json"
$headers = @{ "X-Cisco-Meraki-API-KEY" = $apiKey }
# Since Meraki is using Unix Timestamps, This will be used to conver them to DATETIME values later
$start = Get-Date "1970-01-01T00:00:00Z"
# Set the cutoff Date
$cutOffDate = (Get-Date).AddDays(-1 * $cutOffDays)
# Set the tag to be used for devices over the threshold
$tag = "Over$cutOffDays`Days"
# This is needed for SSL REST Requests to work properly
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
function Get-SMNetworks{
# Build parameters to request the list of networks in your organization
$params = @{ContentType = $contentType
Headers = $headers
Method = "Get"
Uri = "https://$tennantFQDN/api/v0/organizations/$orgId/networks"
Body = $null
Verbose = $verbose
}
# Execute the REST request to return your organizations networks
$networks = Invoke-RestMethod @params
Start-Sleep -Milliseconds $throttleMS
if($networks){
# If networks were found, filter the list to SME networks and return the result
$networks = $networks | WHERE { $_.type -like "systems manager" }
return $networks
}
}
function Get-SMDevices{
param([string]$NetworkID,
[string]$Fields)
#Only proceed if a network ID was provided
if($NetworkID){
$firstPass = $true
$batchToken = $null
# This request can only return 1000 results. Results are paged so you can retrieve all records through multiple results
while($firstPass -or $response.batchToken -ne $null){
$firstPass = $false
# Build the URI request and append either the requested fields or the batch token for page 2+ of results
$uri = "https://$tennantFQDN/api/v0/networks/$NetworkID/sm/devices"
if($batchToken){ $uri += "?batchToken=$batchToken" }
elseif($fields){ $uri += "?fields=$fields" }
# Execute the request
$response = Invoke-RestMethod -ContentType $contentType -Headers $headers -Method Get -Uri $uri -Verbose
Start-Sleep -Milliseconds $throttleMS
# Update the Batch Token. Allows the next page of results to be retrieved
$batchToken = $response.batchToken
# Add the NetworkID to all devices returned (Used later as updates must be perfomred per network)
$response.devices | Add-Member -MemberType NoteProperty -Name "NetworkID" -Value $NetworkID
#Add the devices to the device collection
$devices += $response.devices
}
return $devices
}
}
# Load all your organization's SME Networks
$networks = Get-SMNetworks
# Load all devices from your SME networks
$allDevices = $networks | % { Get-SMDevices -NetworkID $_.id -Fields "lastConnected" }
# Get all devices that have and have not checked in in $cutOffDays days
$addTag = $allDevices | SELECT id,serialNumber,tags,@{LABEL="LastConnect";Expression={$start.AddSeconds($_.lastConnected)}},NetworkID | WHERE { $_.LastConnect -lt $cutOffDate -and $_.tags -notcontains $tag }
$remTag = $allDevices | SELECT id,serialNumber,tags,@{LABEL="LastConnect";Expression={$start.AddSeconds($_.lastConnected)}},NetworkID | WHERE { $_.LastConnect -ge $cutOffDate -and $_.tags -contains $tag }
# These hashtables will be used to build the JSON requests and parameters for the REST Request
$body = @{ "ids" = ""; "updateAction" = ""; "tags" = $tag }
$params = @{ ContentType = $contentType; Headers = $headers; Method = "Put"; Uri = $null; Body = ""; Verbose = $verbose; }
### Tag Devices that have not checked in in $cutOffDays days ###
foreach($network in $networks){
# This url will be used to send the tagging requests
$netId = $network.id
$params.uri = "https://$tennantFQDN/api/v0/networks/$netId/sm/devices/tags"
# Get the devices for this network that need tags added
$addTagNet = $addTag | WHERE NetworkID -eq $netId
# Only execute the add tag operation if there are devices needing the tag
if($addTagNet){
# Set the updateAction to add as wer are adding tags
$body.updateAction = "add"
# Add the device IDs to the body
$body.ids = $addTagNet.id -join ", "
# Convert the body to JSON
$json = ConvertTo-Json $body
# Add the json body to the request parameters
$params.Body = $json
# Execute the request to tag devices
Invoke-RestMethod @params
Start-Sleep -Milliseconds $throttleMS
}
# Get the devices for this network that need tags removed
$remTagNet = $remTag | WHERE NetworkID -eq $netId
# Only execute the add tag operation if there are devices needing the tag
if($remTagNet){
pause
# Set the updateAction to delete as wer are removing tags
$body.updateAction = "delete"
# Add the device IDs to the body
$body.ids = $remTagNet.id -join ", "
# Convert the body to JSON
$json = ConvertTo-Json $body
# Add the json body to the request parameters
$params.Body = $json
# Execute the request to tag devices
Invoke-RestMethod @params
Start-Sleep -Milliseconds $throttleMS
}
}
### ###
... View more