Public/Import-LMMerakiCloud.ps1
<# .SYNOPSIS Imports a Meraki Cloud portal into LM. .DESCRIPTION Imports a Meraki Cloud portal into LM along with creating any required groups and device properties. .PARAMETER MerakiAPIToken Meraki Dashboard API Token .PARAMETER AllowedOrgIds Array of Org Ids that you would like to import, if omitted all Org Ids will be imported .PARAMETER AllowedNetworkIds Array of Network Ids that you would like to import, if omitted all NetworkIds Ids will be imported .PARAMETER MerakiRootFolderName The main folder name for the Meraki import, if omitted the default name is Meraki .PARAMETER MerakiFolderParentGroupId The parent group id that the root meraki device group should exist under, if omitted will default to root of resource tree .PARAMETER CollectorId The collector id number to assign to created devices, if omitted devices will be assigned the first collector returned from Get-LMCollector .PARAMETER ListOrgIds List out the available org ids for a given Meraki Portal. Useful if you want to use the AllowedOrgIds filter but dont know the id/names of the orgs .EXAMPLE Import-LMMerakiCloud -MerakiAPIToken "xxxxxxxxxxxxxxxxxxxxx" -MerakiRootFolderName "Meraki Devices" -CollectorId 1 -MerakiFolderParentGroupId 1 .EXAMPLE Import-LMMerakiCloud -MerakiAPIToken "xxxxxxxxxxxxxxxxxxxxx" -AllowedOrgIds @(1235,6234) .NOTES Currently a beta command, meraki cloud import is still under developement, please report any bugs you encounter while using this command. .INPUTS None. You cannot pipe objects to this command. .LINK Module repo: https://github.com/stevevillardi/Logic.Monitor .LINK PSGallery: https://www.powershellgallery.com/packages/Logic.Monitor #> Function Import-LMMerakiCloud { [CmdletBinding(DefaultParameterSetName="Import")] param ( [Parameter(Mandatory, ParameterSetName = 'Import')] [Parameter(Mandatory, ParameterSetName = 'List')] [String]$MerakiAPIToken, [Parameter(ParameterSetName = 'Import')] [String[]]$AllowedOrgIds = $null, [Parameter(ParameterSetName = 'Import')] [String[]]$AllowedNetworkIds = $null, [Parameter(ParameterSetName = 'Import')] [String]$MerakiRootFolderName = "Meraki", [Parameter(ParameterSetName = 'Import')] [Int]$MerakiFolderParentGroupId = 1, [Parameter(ParameterSetName = 'Import')] [String]$CollectorId, [Parameter(ParameterSetName = 'List')] [Switch]$ListOrgIds, [Parameter(ParameterSetName = 'List')] [Switch]$ListSNMPInfo, [Parameter(ParameterSetName = 'List')] [Switch]$ListNetworkIds ) #Check if we are logged in and have valid api creds Begin {} Process { If ($(Get-LMAccountStatus).Valid) { #List out org devices If($ListOrgIds -or $ListNetworkIds -or $ListSNMPInfo){ Try{ $Orgs = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} } Catch [Exception] { If($_.Exception.Response.StatusCode.value__ -eq "401"){ Write-Host "Unathorized request, check API token and try again." -ForegroundColor Red return } Else{ Write-Host "$($_.TargetObject.RequestUri.OriginalString): $(($_.ErrorDetails.Message | ConvertFrom-Json).errors)" -ForegroundColor Red } } $MerkaiInfo = @() Foreach($Org in $Orgs){ If($ListSNMPInfo){ If($Org.api.enabled){ Try{ $SNMPInfo = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations/$($Org.id)/snmp" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} } Catch{ If($_.Exception.Response.StatusCode.value__ -eq "401"){ Write-Host "Unathorized request, check API token and try again." -ForegroundColor Red return } Else{ Write-Host "$($_.TargetObject.RequestUri.OriginalString): $(($_.ErrorDetails.Message | ConvertFrom-Json).errors)" -ForegroundColor Red Continue } } $MerkaiInfo += [PSCustomObject]@{ orgId = $Org.id orgName = $Org.name v2cEnabled = $SNMPInfo.v2cEnabled v3Enabled = $SNMPInfo.v3Enabled v3AuthMode = $SNMPInfo.v3AuthMode v3PrivMode = $SNMPInfo.v3PrivMode peerIps = $SNMPInfo.peerIps v2CommunityString = $SNMPInfo.v2CommunityString hostname = $SNMPInfo.hostname port = $SNMPInfo.port } } Else{ Write-Host "Skipping SNMP Info check for ($($Org.name)) since dashboard api access is disabled for that org." -ForegroundColor Yellow Continue } } ElseIf($ListNetworkIds){ If($Org.api.enabled){ Try{ $Networks = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations/$($Org.id)/networks" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} } Catch [Exception] { If($_.Exception.Response.StatusCode.value__ -eq "401"){ Write-Host "Unathorized request, check API token and try again." -ForegroundColor Red return } Else{ Write-Host "$($_.TargetObject.RequestUri.OriginalString): $(($_.ErrorDetails.Message | ConvertFrom-Json).errors)" -ForegroundColor Red Continue } } Foreach($Net in $Networks){ $MerkaiInfo += [PSCustomObject]@{ org_id = $Org.id org_name = $Org.name network_id = $Net.id network_name = $Net.name api_dashboard_enabled = $Org.api.enabled } } } Else{ Write-Host "Skipping Network Info check for ($($Org.name)) since dashboard api access is disabled for that org." -ForegroundColor Yellow Continue } } Else{ $MerkaiInfo += [PSCustomObject]@{ org_id = $Org.id org_name = $Org.name network_id = "N/A" network_name = "N/A" api_dashboard_enabled = $Org.api.enabled } } } Return $MerkaiInfo } #Validate CollectorId If(!$CollectorId){ #If no collector id specified, choose first available collector $CollectorId = (Get-LMCollector | Select -First 1).id If(!$CollectorId){ Write-Host "Unable to find a collector, ensure a collector has been deployed and try again" -ForegroundColor Red Return } } Else{ $Collector = Get-LMCollector -Id $CollectorId If(!$Collector){ Write-Host "Unable to find collector with the specific id: $CollectorId, ensure the collector id is correct and try again" -ForegroundColor Red Return } } #Check if Meraki device group exists, if not create it $MerakiDeviceGroup = Get-LMDeviceGroupGroups -Id $MerakiFolderParentGroupId | Where-Object {$_.Name -eq $MerakiRootFolderName} If(!$MerakiDeviceGroup){ $GroupProps = @{ "meraki.api.key" = $MerakiAPIToken } Write-Host "[INFO]: Creating new Meraki device group : $MerakiRootFolderName" $MerakiDeviceGroup = New-LMDeviceGroup -Name $MerakiRootFolderName -ParentGroupId $MerakiFolderParentGroupId -Properties $GroupProps If(!$MerakiDeviceGroup){ Write-Host "Failed to create Meraki device group" -ForegroundColor Red Return } } Else{ Write-Host "[INFO]: Existing Meraki device group ($MerakiRootFolderName), already added to LogicMonitor, skipping creation" -ForegroundColor Gray } #Meraki API Endpoint $MerakiAPIEndpoint = "https://api.meraki.com/api/v1" Try{ $Orgs = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} } Catch [Exception] { If($_.Exception.Response.StatusCode.value__ -eq "401"){ Write-Host "Unathorized request, check API token and try again." -ForegroundColor Red Return } Else{ Write-Host $_.Exception.Response.StatusDescription -ForegroundColor Red } } Foreach($Org in $Orgs){ $OrgId = $Org.id $OrgName = $Org.name -replace "[/\\\*\<\>\,\`\(\)\|\']" , "" $Networks = @() $Devices = @() If ($AllowedOrgIds -ne $null) { If (!$AllowedOrgIds.Contains($OrgId)) { Write-Host "[INFO]: Skipping Meraki OrgId ($OrgId), not found in AllowedOrgIds list" -ForegroundColor Gray Continue } } If ($Org.api.enabled -eq $false) { Write-Host "[INFO]: Skipping Meraki OrgId ($OrgId), dashbaord API access not enabled" -ForegroundColor Gray Continue } Try { $Networks = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations/$OrgId/networks" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} $Devices = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations/$OrgId/devices" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} } Catch [Exception] { Write-Host $_.Exception.Response.StatusDescription -ForegroundColor Red Continue } #Only add orgs if they have networks. If (($Networks | Measure-Object).Count -gt 0) { #Create Dynamic Group for Meraki Org if it does not exists, adding in required SNMP info and props for proper collection $OrgGroup = Get-LMDeviceGroupGroups -Id $MerakiDeviceGroup.Id | Where-Object {$_.Name -eq "$OrgName"} If($OrgGroup){ Write-Host "[INFO]: Existing Meraki Org device group ($OrgName) already added to LogicMonitor, skipping creation" -ForegroundColor Gray } Else{ #Get SNMP Creds for group properties $SNMPInfo = Invoke-RestMethod -Uri "https://api.meraki.com/api/v1/organizations/$OrgId/snmp" -Headers @{"X-Cisco-Meraki-API-Key"=$MerakiAPIToken} If($SNMPInfo.v3Enabled){ $OrgGroupProps = @{ "snmp.auth" = $(If($SNMPInfo.v3AuthMode -like "SHA*"){"SHA"}Else{"MD5"}) "snmp.authToken" = "changeme" "snmp.priv" = $(If($SNMPInfo.v3PrivMode -like "AES*"){"AES"}Else{"DES"}) "snmp.privToken" = "changeme" "snmp.port" = $SNMPInfo.port "snmp.security" = $SNMPInfo.v3User "snmp.version" = "v3" "system.categories" = "NoHTTPS,NoPing" } $OrgGroup = New-LMDeviceGroup -Name $OrgName -Properties $OrgGroupProps -ParentGroupId $MerakiDeviceGroup.id -AppliesTo "meraki.org.id == `"$OrgId`"" If(!$OrgGroup){ Write-Host "Failed to create Meraki org device group ($OrgName)" -ForegroundColor Red Continue } Else{ Write-Host "[INFO]: Created Meraki Org device group ($OrgName). This Org is using SNMPv3 to poll network devices, you must update device group properties (snmp.authToken & snmp.privToken) with the correct values." -ForegroundColor Yellow } } ElseIf($SNMPInfo.v2cEnabled){ $OrgGroupProps = @{ "snmp.port" = $SNMPInfo.port "snmp.community" = $SNMPInfo.v2CommunityString "snmp.version" = "v2c" "system.categories" = "NoHTTPS,NoPing" } $OrgGroup = New-LMDeviceGroup -Name $OrgName -Properties $OrgGroupProps -ParentGroupId $MerakiDeviceGroup.id -AppliesTo "meraki.org.id == `"$OrgId`"" If(!$OrgGroup){ Write-Host "Failed to create Meraki org device group ($OrgName)" -ForegroundColor Red Continue } Else{ Write-Host "[INFO]: Created Meraki Org device group ($OrgName). This Org is using SNMPv2c to poll network devices, an appropriate snmp.community ($($SNMPInfo.v2CommunityString)) property has been set for this device group." } } } $OrgHostName = "$($OrgName.Replace(' ','')).invalid" $OrgDisplayName = "Meraki Org: $OrgName" $OrgProps = @{ "meraki.org.name" = $OrgName "meraki.org.id" = $OrgId } #Check if org device already exists $ExistingOrgDevice = Get-LMDevice -Name $OrgHostName If($ExistingOrgDevice){ Write-Host "[INFO]: Existing Meraki Org device ($OrgDisplayName) already added to LogicMonitor, skipping creation" -ForegroundColor Gray } ELse{ Write-Host "[INFO]: Creating new Meraki Org device: $OrgDisplayName" $OrgDevice = New-LMDevice -DisplayName $OrgDisplayName -Name $OrgHostName -Properties $OrgProps -PreferredCollectorId $CollectorId } } Foreach($Network in $Networks) { $NetworkId = $Network.id If ($AllowedNetworkIds -ne $null) { If (!$AllowedNetworkIds.Contains($NetworkId)) { Write-Host "[INFO]: Skipping Meraki NetworkId ($NetworkId), not found in AllowedNetworkIds list" -ForegroundColor Gray Continue } } #Check if this network has any devices and avoid reporting deviceless networks. $NetworkDevices = $Devices.networkId.Contains($Network.id) If (($NetworkDevices | Measure-Object).Count -eq 0) { Write-Host "[INFO]:$($Network.name) does not contain any devices, skipping processing" -ForegroundColor Gray Continue } $NetworkName = $Network.name -replace "[/\\\*\<\>\,\`\(\)\|\']" , "" $NetworkTags = $Network.tags $NetworkType = $Network.productTypes $NetworkHostName = "$($OrgName.Replace(' ','')).$($NetworkName.Replace(' ','')).invalid" $NetworkDisplayName = "Meraki Network: $NetworkName" $NetworkProps = @{ "meraki.org.name" = $OrgName "meraki.org.id" = $OrgId "meraki.network.id" = $NetworkId "meraki.network.name" = $NetworkName "meraki.network.tags" = $(If(!$NetworkTags){"[]"}Else{$NetworkTags -join ","}) "meraki.network.type" = $NetworkType -Join ", " } #Check if network device already exists $ExistingNetworkDevice = Get-LMDevice -Name $NetworkHostName If($ExistingNetworkDevice){ Write-Host "[INFO]: Existing Meraki Network device ($NetworkDisplayName) already added to LogicMonitor, skipping creation" -ForegroundColor Gray } ELse{ Write-Host "[INFO]: Creating new Meraki Network device: $NetworkDisplayName" $NetworkDevice = New-LMDevice -DisplayName $NetworkDisplayName -Name $NetworkHostName -Properties $NetworkProps -PreferredCollectorId $CollectorId } } } #Check if api device already exists $ExistingAPIDevice = Get-LMDevice -Name "api.meraki.com" If($ExistingAPIDevice){ Write-Host "[INFO]: Existing Meraki API device (api.meraki.com) already added to LogicMonitor, skipping creation" -ForegroundColor Gray } ELse{ Write-Host "[INFO]: Creating new Meraki API device: api.meraki.com" $APIDevice = New-LMDevice -DisplayName "api.meraki.com" -Name "api.meraki.com" -PreferredCollectorId $CollectorId -HostGroupIds @($($MerakiDeviceGroup.id)) } Return } Else { Write-Error "Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again." } } End {} } |