This blog should be used in together with my previous blog about Unifi documentation. This script syncs all devices to IT-Glue and makes sure the configurations are in sync with eachother.
It will overwrite any changes you’ve made to the configurations, so treat with care.
############### $ITGkey = "ITGlueKey" $ITGbaseURI = "https://api.eu.itglue.com" $UnifiBaseUri = "https://Controller.yourdomain.com:8443/api" $UnifiUser = "APIUSER" $UnifiPassword = "APIPASSWORD" ############## #Settings IT-Glue logon information If (Get-Module -ListAvailable -Name "ITGlueAPI") { Import-module ITGlueAPI } Else { Install-Module ITGlueAPI -Force Import-Module ITGlueAPI } Add-ITGlueBaseURI -base_uri $ITGbaseURI Add-ITGlueAPIKey $ITGkey write-host "Checking if products exist in IT-Glue, and if not creating them." $unifiAllModels = @" [{"c":"BZ2","t":"uap","n":"UniFi AP"},{"c":"BZ2LR","t":"uap","n":"UniFi AP-LR"},{"c":"U2HSR","t":"uap","n":"UniFi AP-Outdoor+"}, {"c":"U2IW","t":"uap","n":"UniFi AP-In Wall"},{"c":"U2L48","t":"uap","n":"UniFi AP-LR"},{"c":"U2Lv2","t":"uap","n":"UniFi AP-LR v2"}, {"c":"U2M","t":"uap","n":"UniFi AP-Mini"},{"c":"U2O","t":"uap","n":"UniFi AP-Outdoor"},{"c":"U2S48","t":"uap","n":"UniFi AP"}, {"c":"U2Sv2","t":"uap","n":"UniFi AP v2"},{"c":"U5O","t":"uap","n":"UniFi AP-Outdoor 5G"},{"c":"U7E","t":"uap","n":"UniFi AP-AC"}, {"c":"U7EDU","t":"uap","n":"UniFi AP-AC-EDU"},{"c":"U7Ev2","t":"uap","n":"UniFi AP-AC v2"},{"c":"U7HD","t":"uap","n":"UniFi AP-HD"}, {"c":"U7SHD","t":"uap","n":"UniFi AP-SHD"},{"c":"U7NHD","t":"uap","n":"UniFi AP-nanoHD"},{"c":"UCXG","t":"uap","n":"UniFi AP-XG"}, {"c":"UXSDM","t":"uap","n":"UniFi AP-BaseStationXG"},{"c":"UCMSH","t":"uap","n":"UniFi AP-MeshXG"},{"c":"U7IW","t":"uap","n":"UniFi AP-AC-In Wall"}, {"c":"U7IWP","t":"uap","n":"UniFi AP-AC-In Wall Pro"},{"c":"U7MP","t":"uap","n":"UniFi AP-AC-Mesh-Pro"},{"c":"U7LR","t":"uap","n":"UniFi AP-AC-LR"}, {"c":"U7LT","t":"uap","n":"UniFi AP-AC-Lite"},{"c":"U7O","t":"uap","n":"UniFi AP-AC Outdoor"},{"c":"U7P","t":"uap","n":"UniFi AP-Pro"}, {"c":"U7MSH","t":"uap","n":"UniFi AP-AC-Mesh"},{"c":"U7PG2","t":"uap","n":"UniFi AP-AC-Pro"},{"c":"p2N","t":"uap","n":"PicoStation M2"}, {"c":"US8","t":"usw","n":"UniFi Switch 8"},{"c":"US8P60","t":"usw","n":"UniFi Switch 8 POE-60W"},{"c":"US8P150","t":"usw","n":"UniFi Switch 8 POE-150W"}, {"c":"S28150","t":"usw","n":"UniFi Switch 8 AT-150W"},{"c":"USC8","t":"usw","n":"UniFi Switch 8"},{"c":"US16P150","t":"usw","n":"UniFi Switch 16 POE-150W"}, {"c":"S216150","t":"usw","n":"UniFi Switch 16 AT-150W"},{"c":"US24","t":"usw","n":"UniFi Switch 24"},{"c":"US24P250","t":"usw","n":"UniFi Switch 24 POE-250W"}, {"c":"US24PL2","t":"usw","n":"UniFi Switch 24 L2 POE"},{"c":"US24P500","t":"usw","n":"UniFi Switch 24 POE-500W"},{"c":"S224250","t":"usw","n":"UniFi Switch 24 AT-250W"}, {"c":"S224500","t":"usw","n":"UniFi Switch 24 AT-500W"},{"c":"US48","t":"usw","n":"UniFi Switch 48"},{"c":"US48P500","t":"usw","n":"UniFi Switch 48 POE-500W"}, {"c":"US48PL2","t":"usw","n":"UniFi Switch 48 L2 POE"},{"c":"US48P750","t":"usw","n":"UniFi Switch 48 POE-750W"},{"c":"S248500","t":"usw","n":"UniFi Switch 48 AT-500W"}, {"c":"S248750","t":"usw","n":"UniFi Switch 48 AT-750W"},{"c":"US6XG150","t":"usw","n":"UniFi Switch 6XG POE-150W"},{"c":"USXG","t":"usw","n":"UniFi Switch 16XG"}, {"c":"UGW3","t":"ugw","n":"UniFi Security Gateway 3P"},{"c":"UGW4","t":"ugw","n":"UniFi Security Gateway 4P"},{"c":"UGWHD4","t":"ugw","n":"UniFi Security Gateway HD"}, {"c":"UGWXG","t":"ugw","n":"UniFi Security Gateway XG-8"},{"c":"UP4","t":"uph","n":"UniFi Phone-X"},{"c":"UP5","t":"uph","n":"UniFi Phone"}, {"c":"UP5t","t":"uph","n":"UniFi Phone-Pro"},{"c":"UP7","t":"uph","n":"UniFi Phone-Executive"},{"c":"UP5c","t":"uph","n":"UniFi Phone"}, {"c":"UP5tc","t":"uph","n":"UniFi Phone-Pro"},{"c":"UP7c","t":"uph","n":"UniFi Phone-Executive"}] "@ $configTypes = @" [{"t":"uap","n":"Unifi AP"},{"t":"usw","n":"Unifi Switch"},{"t":"ugw","n":"Unifi Gateway"},{"t":"uph","n":"Unifi VOIP"}] "@ | ConvertFrom-Json $unifiAllModels = $unifiAllModels | ConvertFrom-Json $unifiModels = $unifiAllModels | Sort-Object n -Unique $ITGConfigTypes = (Get-ITGlueConfigurationTypes).data write-host "Check Config Types and creating if required" -ForegroundColor Green foreach ($ConfType in $configTypes) { if ($ConfType.n -notin $ITGConfigTypes.attributes.name) { write-host "Creating $($Model.n)" -ForegroundColor Green New-ITGlueConfigurationTypes -data @{ type = 'configuration-types' attributes = @{ name = $ConfType.n } } } } $ExistingModels = (Get-ITGlueModels -page_size 1000).data write-host "Checkings manufacture and creating if required" -ForegroundColor Green $Manafacture = (Get-ITGlueManufacturers -filter_name "UniFi").data if (!$Manafacture) { New-ITGlueManufacturers -data @{ type = 'manufacturers' attributes = @{ name = 'uniFi-2' } } $Manafacture = (Get-ITGlueManufacturers -filter_name "UniFi").data } write-host "Grabbing active status" $ConfigurationStatusId = (Get-ITGlueConfigurationStatuses -filter_name 'Active').data.ID | Select-Object -Last 1 write-host "Checkings models and creating if required" -ForegroundColor Green foreach ($Model in $unifiAllModels) { if ($model.n -notin $ExistingModels.attributes.name) { write-host "Creating $($Model.n)" -ForegroundColor Green New-ITGlueModels -data @{ type = 'models' attributes = @{ 'manufacturer-id' = $Manafacture.id name = $model.n } } } } write-host "Start configuration syncing process." -foregroundColor green $UniFiCredentials = @{ username = $UnifiUser password = $UnifiPassword remember = $true } | ConvertTo-Json write-host "Logging in to Unifi API." -ForegroundColor Green try { Invoke-RestMethod -Uri "$UnifiBaseUri/login" -Method POST -Body $uniFiCredentials -SessionVariable websession } catch { write-host "Failed to log in on the Unifi API. Error was: $($_.Exception.Message)" -ForegroundColor Red } write-host "Collecting sites from Unifi API." -ForegroundColor Green try { $sites = (Invoke-RestMethod -Uri "$UnifiBaseUri/self/sites" -WebSession $websession).data } catch { write-host "Failed to collect the sites. Error was: $($_.Exception.Message)" -ForegroundColor Red } foreach ($site in $sites) { $ITGlueOrgID = $site.desc.split('()')[1] if (!$ITGlueOrgID) { write-host "Could not get IT-Glue OrgID for site $($site.desc). Moving on to next site." -ForegroundColor Yellow continue } else { write-host "Documenting $($site.desc), using ITGlue ID: $ITGlueOrgID" -ForegroundColor Green } $unifiDevices = Invoke-RestMethod -Uri "$UnifiBaseUri/s/$($site.name)/stat/device" -WebSession $websession foreach ($device in $unifiDevices.data) { ($ExistingConfiguration = Get-ITGlueConfigurations -organization_id $ITGlueOrgID -filter_serial_number $device.serial).data.id | select-object -last 1 $DeviceName = if (!$device.name) { "Unifi Device $($device.serial)" } else { $device.name } $ModelName = ($unifiAllModels | Where-Object { $_.c -eq $device.model }).n $modelid = $ExistingModels | Where-Object { $_.attributes.name -eq $ModelName } | Select-Object -last 1 $ConfigName = ($configtypes | Where-Object { $_.t -eq $device.type }).n $Configurationtypeid = ($ITGConfigTypes | Where-Object { $_.attributes.name -eq $Configname }).id $ConfigurationBody = @{ type = "configurations" attributes = @{ "organization-id" = $ITGlueOrgID "name" = $DeviceName "configuration-type-id" = $Configurationtypeid "configuration-status-id" = $ConfigurationStatusId "manufacturer-id" = $Manafacture.id "model-id" = $ModelID.id "primary-ip" = $device.ip "serial-number" = $device.serial "mac-address" = $device.mac } } if (!$ExistingConfiguration) { write-host "Creating new device" -ForegroundColor Green New-ITGlueConfigurations -organization_id $ITGlueOrgID -data $ConfigurationBody } else { write-host "Editing previous existing device" -ForegroundColor Green Set-ITGlueConfigurations -id ($ExistingConfiguration.data.id | Select-Object -last 1) -data $ConfigurationBody } } }
And that’s it! this blog will be followed up by another documentation blog pretty quick, so its shorter than normal. As always, Happy PowerShelling.
Hi Kelvin,
Love your blog posts, they’ve been very informative.
Having a bit of an issue with this one though, I’m getting this error for sites that are linked back to IT Glue from your previous post.
Editing previous existing device
Set-ITGlueConfigurations : {“errors”:[{“status”:404,”title”:”Not found”,”detail”:”Record not found”,”source”:{“pointer”:”id”}}]}
At C:\Users\%user%\Work\Scripts\unificonfigsync.ps1:152 char:13
+ Set-ITGlueConfigurations -id ($ExistingConfiguration.data …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Set-ITGlueConfigurations
I’ve confirmed the manufacturer and model entries have been added properly.
Thanks for any help you can provide!
You might have duplicate devices, or the same name of the device in multiple locations. I’ve edited the script to accomdate this 🙂
Hello, I’ve found great use in a lot of your scripts and you run a great blog! I’m running into the below error.. Any suggestions on what may be happening?
Creating UniFi AP
New-ITGlueModels : {“errors”:[{“status”:422,”title”:”Valid manufacturer_id is required”,”source”:{“pointer”:”data/attributes/manufacturer_id”}}]}
At line:82 char:9
+ New-ITGlueModels -data @{
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,New-ITGlueModels
Create a manufacture called “Unifi” in your IT-Glue system. I think its failing to create it via the API 🙂
Though the Models are getting created properly, I am still getting this error:
Set-ITGlueConfigurations : {“errors”:[{“status”:404,”title”:”Not
found”,”detail”:”Record not found”,”source”:{“pointer”:”id”}}]}
At line:156 char:13
+ Set-ITGlueConfigurations -id ($ExistingConfiguration.data …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Set
-ITGlueConfigurations
Any thoughts?
Thanks again for your scripts!
Seems like you also have some duplicate devices, the oneliner I added should take care of that though. If they are getting created correctly it might just be a bug.
I am running into a strange issue where existing devices that were originally created by Eliot Munro’s scripts are being updated by your script just fine, but all devices added since we last ran his script are not being created in ITG, regardless if it is a new UniFi site or an existing one with new devices added. These are all brand new devices so they do not already existing elsewhere in our ITG. What’s stranger is the PS output is showing as if it’s trying to update an existing configuration and erroring when it does not exist:
Documenting , using ITGlue ID:
Editing previous existing device
Set-ITGlueConfigurations : {“errors”:[{“status”:404,”title”:”Not found”,”detail”:”Record not found”,”source”:{“pointer”:”id”}}]}
At line:155 char:13
+ Set-ITGlueConfigurations -id ($ExistingConfiguration.data …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Set-ITGlueConfigurations
I am assuming it’s an issue at line 129 where it determines if it is an existing config or not, but I don’t know how to fix it from there on my own.
I’m thinking there are some duplicate devices which are causing this. Can you confirm that? if so, I can check how to resolve 🙂
I checked and confirmed there are no duplicate devices at all, and anything that is existing it is updating just fine. As a test I deleted one of the existing devices and the script would not re-add it and that device also started throwing an error now where it wasn’t before I deleted it.
Based on the PS window scrollback I think the test logic to see if a device is new or existing is not processing it right and thinks everything is existing, then when it tries to update an ‘existing’ device that isn’t really in ITG it throws that error. I just have no idea how to troubleshoot or fix the logic since at the surface checking for the existing serial should be good. I even looked at the ITG device IDs the script says are existing but they do no exist in our ITG instance.
And these are all brand new UBNT devices that were purchased through Ingram so they should be truly new. It really does not make any sense but this is what it is.
Any chance you have had some time to look at the logic for new vs existing and find a solution? Just checking in.