Scripting out a list of SyncroMSP duplicate assets

Syncro Logo RGB 2C 1

Issue / Fault definition

SyncroMSP has a flaw where if you re-image a device when the agent is installed, it will create a duplicate asset rather than merge into the old existing asset; over time, you end up with many hundreds of duplicated assets.

Here’s a step-by-step breakdown of the script:

  1. Variables are defined to store the assets, tenant, authorization details, and the base URL of the API.
  2. The script then tries to authenticate to the SyncroMSP API using the provided tenant and API key.
  3. If authentication is successful, it requests the API to get all the assets.
  4. The script then starts gathering all the assets from each page by sending a GET request for each page. The progress of this process is shown to the user.
  5. After gathering the assets, it “explodes” the JSON response into an array of assets, excluding the ones whose form factor is ‘Server’.
  6. Next, it identifies all duplicate assets based on their serial numbers.
  7. Then, for each duplicate, the script selects the asset that hasn’t checked in for the longest time, presumably to mark them for deletion.
  8. Lastly, the script sends a PUT request to the API for each selected asset, marking them for deletion by updating their properties to include “Old_Duplicate” = “Yes”.
  9. In case of any error during the execution of the script, it is caught and displayed to the user.

Known Fixes / Solutions

SyncroMSP currently provides no known solutions in-house, but I have been able to use the API to create a PowerShell script that will identify these for manual deletion. (Fingers crossed, providing SyncroMSP can confirm the API is able to delete the script can do this also)

$Asset_Array = @()
$Asset_Array_exploded = @()
$Asset_Duplicates = @()
$Data = @()
$tenant = "your tenant name"
$Authorization = "your API key"
$baseUri = 'https://' + $tenant + ''

    Write-Host "Authenticating to SyncroMSP, please wait... " -ForegroundColor Blue -NoNewline
    $headers = @{
        'method' = 'GET'
        'Accept' = 'Application/Json'
        'Authorization' = $Authorization
    $Json = Invoke-RestMethod -Uri $baseUri -Headers $headers -ErrorAction Stop
    $Max_Pages = $Json.meta.total_pages
    $Total_entries = $Json.meta.total_entries
    Write-Host "Done." -ForegroundColor Green

    Write-Host "Gathering $Total_entries assets from $Max_Pages pages, please wait... " -ForegroundColor Blue
    #Loop around each page and get the assets and ID's into an array
    for ($Page_Number = 1; $Page_Number -le $Max_Pages; $Page_Number++){
        $uri = $baseUri + '?page=' + $Page_Number
        $Json = Invoke-RestMethod -Uri $uri -Headers $headers -ErrorAction Stop
        foreach ($asset in $Json.assets){
            $Asset_Array += @([pscustomobject]@{Asset_Name = $; Asset_id = $; Asset_serial_number = $asset.asset_serial; Asset_updated_at = $asset.updated_at; Asset_form_factor = $})
    Write-Host "Done." -ForegroundColor Green

    Write-Host "Explode the JSON content into an array, please wait... " -ForegroundColor Blue -NoNewline
    #break the array down into an exploded array and add to a table
    $Asset_Array_exploded = $Asset_Array | Where-Object {$_.Asset_form_factor -notmatch "Server"}
    Write-Host "Done." -ForegroundColor Green

    Write-Host "Gathering all duplicates, please wait... " -ForegroundColor Blue -NoNewline
    #Get the duplicates and counts
    $Asset_Duplicates_list = $Asset_Array_exploded.Asset_serial_number | Group-Object | Where-Object {$_.Count -gt 1} | Select-Object Name, Count
    #loop around each duplicate and get the details
    $StartDate = Get-Date
    $Asset_Duplicates = foreach ($duplicate in $Asset_Duplicates_list) {
        $Asset_Array | Where-Object { $duplicate.Name -eq $_.Asset_serial_number } | ForEach-Object {
            [pscustomobject]@{AssetName = $_.Asset_Name; AssetID = $_.Asset_id; AssetSerial = $_.Asset_serial_number; LastCheckinDays = ($StartDate - [DateTime]$_.Asset_updated_at).Days; LastCheckinDate = [DateTime]$_.Asset_updated_at; Asset_form_factor = $_.Asset_form_factor}
    Write-Host "Done." -ForegroundColor Green

    Write-Host "Gathering duplicates to delete, please wait... " -ForegroundColor Blue -NoNewline

    Write-Host "Done." -ForegroundColor Green
    $deletes = $Asset_Duplicates | Sort-Object AssetSerial, LastCheckinDate | Group-Object AssetSerial | ForEach-Object { $ | Select-Object -First 1 }
    $deletes | Sort-Object -Property LastCheckinDate | Format-Table

    Write-Host "Updating SyncroMSP duplicates, please wait... " -ForegroundColor Blue
    foreach ($delete in $deletes) {
        $uri = $baseUri + '/' + $delete.AssetID
        Write-Host "Marking asset for deletion ID:" $delete.AssetID  -ForegroundColor Yellow
        $null = Invoke-RestMethod -Method Put -Uri $uri -Headers $headers -Body (ConvertTo-Json @{"asset" = @{"properties" = @{"Old_Duplicate" = "Yes"}}}) -ContentType "application/json" -ErrorAction Stop
    Write-Host "Done." -ForegroundColor Green
catch {
    Write-Host "There was an error in execution:" $_.Exception.Message -ForegroundColor Red

Found priceless insights in this blog? Support the author’s creativity – buy them a coffee!

Leave a Reply

Your email address will not be published. Required fields are marked *