Forum Discussion

thedietz's avatar
thedietz
Icon for Neophyte rankNeophyte
3 years ago

Remove multiple devices from a static group

I want to delete multiple devices from a static group in bulk.  i DO NOT want to delete the device itself. 

I am new to LogicMonitor but have figured out how to get all members of a group using the API.  I just haven't figured out how to then remove all of those devices from that group.  Has anyone been successful in doing this?

  • Also to bring this back full circle.  This all started because in my folder structure I had a Static Group which contained dynamic Groups under it and there were also resources in that upper level static Group.  I only wanted the dynamic folders to remain, and I did not want the 30 resources in the Static Group any longer.  Using the UI my options were to either "Manage" each device and choose delete, or click each device then on INFO tab click the "X" on the group I wanted to remove it from (this option however refreshes my screen and takes me away from that group, so then you need to navigate back to the folder you were just at...I hate this feature of the UI).  So with this script below you put in the Group ID # that has the resources you want to remove.  It gets all the resources and then loops through to PATCH the hostGroupIds property.  This is obviously use at your own risk however it does work for me.  Running this took about 10-15 seconds to remove all 30 resources from my static group.

     

     

    ## Enter the group you would like to have resources removed from
    ## This script will take all resources in that group (folders excluded) and remove the resources from that group
    $group = "437"

    <# Use TLS 1.2 #>
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    <# account info #>
    $accessId = ''
    $accessKey = ''
    $company = ''

    <# request details #>
    $httpVerb = 'GET'

    #use this for a specific Device
    $resourcePath = "/device/groups/$group/devices"

    <# Construct URL #>
    $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryparams

    <# Get current time in milliseconds #>
    $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)

    <# Concatenate Request Details #>
    $requestVars = $httpVerb + $epoch + $resourcePath  

    <# Construct Signature #>
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
    $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
    $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
    $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))

    <# Construct Headers #>
    $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization",$auth)
    $headers.Add("Content-Type",'application/json')
    $headers.Add("X-Version", "2")

    <# Make Request #>
    $response = Invoke-RestMethod -Uri $url -Method $httpVerb  -Header $headers
    <# Print status and body of response #>
    $status = $response.status
    $body = $response.data| ConvertTo-Json -Depth 5

    $devicePayload = $response.items


    ##loop through each device and remove group from its hostGroupIds property
    Foreach ($d in $devicePayload)
    {
        #find where the group is and remove it from the string along with comma depending on placement
        if ($d.hostGroupIds -like "*,$group*")
        {
        $remove = "," + $group
        $groups = $d.hostGroupIds.Replace("$remove","")
        }
        Else
        {
        $remove = $group + ","
        $groups = $d.hostGroupIds.Replace("$remove","")
        }


        $httpVerb = 'PATCH'


        $id = $d.id
        $resourcePath = "/device/devices/$id"
        $queryparams = '?patchFields=hostGroupIds'
        $data = "{" + '"hostGroupIds":"' + $groups + '"}'

        # Construct URL 
        $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryparams

        # Get current time in milliseconds #
        $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)

        # Concatenate Request Details #
        $requestVars = $httpVerb + $epoch + $data + $resourcePath  

        # Construct Signature #
        $hmac = New-Object System.Security.Cryptography.HMACSHA256
        $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
        $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
        $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
        $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))

        # Construct Headers #
        $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
        $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $headers.Add("Authorization",$auth)
        $headers.Add("Content-Type",'application/json')
        $headers.Add("X-Version", "2")

        # Make Request #
        $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers -Body $data
      
    }

  • Figured out my issue.  For anyone who reviewed this and looks at this in the future Mike was right the group Ids are a string and need in quotes....and i was missing the "-Body $data" parameter/value in Invoke-RestMethod.  

  • Also to bring this back full circle.  This all started because in my folder structure I had a Static Group which contained dynamic Groups under it and there were also resources in that upper level static Group.  I only wanted the dynamic folders to remain, and I did not want the 30 resources in the Static Group any longer.  Using the UI my options were to either "Manage" each device and choose delete, or click each device then on INFO tab click the "X" on the group I wanted to remove it from (this option however refreshes my screen and takes me away from that group, so then you need to navigate back to the folder you were just at...I hate this feature of the UI).  So with this script below you put in the Group ID # that has the resources you want to remove.  It gets all the resources and then loops through to PATCH the hostGroupIds property.  This is obviously use at your own risk however it does work for me.  Running this took about 10-15 seconds to remove all 30 resources from my static group.

     

     

    ## Enter the group you would like to have resources removed from
    ## This script will take all resources in that group (folders excluded) and remove the resources from that group
    $group = "437"

    <# Use TLS 1.2 #>
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    <# account info #>
    $accessId = ''
    $accessKey = ''
    $company = ''

    <# request details #>
    $httpVerb = 'GET'

    #use this for a specific Device
    $resourcePath = "/device/groups/$group/devices"

    <# Construct URL #>
    $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryparams

    <# Get current time in milliseconds #>
    $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)

    <# Concatenate Request Details #>
    $requestVars = $httpVerb + $epoch + $resourcePath  

    <# Construct Signature #>
    $hmac = New-Object System.Security.Cryptography.HMACSHA256
    $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
    $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
    $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
    $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))

    <# Construct Headers #>
    $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization",$auth)
    $headers.Add("Content-Type",'application/json')
    $headers.Add("X-Version", "2")

    <# Make Request #>
    $response = Invoke-RestMethod -Uri $url -Method $httpVerb  -Header $headers
    <# Print status and body of response #>
    $status = $response.status
    $body = $response.data| ConvertTo-Json -Depth 5

    $devicePayload = $response.items


    ##loop through each device and remove group from its hostGroupIds property
    Foreach ($d in $devicePayload)
    {
        #find where the group is and remove it from the string along with comma depending on placement
        if ($d.hostGroupIds -like "*,$group*")
        {
        $remove = "," + $group
        $groups = $d.hostGroupIds.Replace("$remove","")
        }
        Else
        {
        $remove = $group + ","
        $groups = $d.hostGroupIds.Replace("$remove","")
        }


        $httpVerb = 'PATCH'


        $id = $d.id
        $resourcePath = "/device/devices/$id"
        $queryparams = '?patchFields=hostGroupIds'
        $data = "{" + '"hostGroupIds":"' + $groups + '"}'

        # Construct URL 
        $url = 'https://' + $company + '.logicmonitor.com/santaba/rest' + $resourcePath + $queryparams

        # Get current time in milliseconds #
        $epoch = [Math]::Round((New-TimeSpan -start (Get-Date -Date "1/1/1970") -end (Get-Date).ToUniversalTime()).TotalMilliseconds)

        # Concatenate Request Details #
        $requestVars = $httpVerb + $epoch + $data + $resourcePath  

        # Construct Signature #
        $hmac = New-Object System.Security.Cryptography.HMACSHA256
        $hmac.Key = [Text.Encoding]::UTF8.GetBytes($accessKey)
        $signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
        $signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
        $signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))

        # Construct Headers #
        $auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
        $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
        $headers.Add("Authorization",$auth)
        $headers.Add("Content-Type",'application/json')
        $headers.Add("X-Version", "2")

        # Make Request #
        $response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers -Body $data
      
    }