cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
4495
Views
40
Helpful
0
Replies

AMP4E API - Sharing powershell script

Orlith
Level 1
Level 1

Hi

Looks like there's not much example of api scripts down there or on the net  for those who are using Powershell except this topic which was very helpful : https://community.cisco.com/t5/advanced-threats/some-handy-tips-for-amp4e-api-connections-with-powershell/td-p/3097485

So I decided to share mine, and I'm pretty sure it could be helpful for others.

I'm also sure that my scripts can be optimized , so feel free to share your thoughts about it 

 

Generating Header (thx @ChiefSec-SF)

# $clientid = "XXXXXXXXXXXXXXX"
# $apikey = "xxxx-xxxxx-xxxxx-xxxxx"
# $EncodedUsernamePassword = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($('{0}:{1}' -f $clientid, $apikey)))

$EncodedUsernamePassword='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
$Headers = @{'Authorization' = "Basic $($EncodedUsernamePassword)"; 'accept' = 'application/json'; 'Content-type' = 'application/json'; 'Accept-Encoding' = 'gzip, deflate'}

Some variables and my log function

$global:computerslist = $null
$global:computer = $null
$global:result = $null
$global:event=$null
$global:delete=$null
$global:duplicate=$null

$Date=Get-date -format "yyyyMMdd-HHmmss"
$logfile = "C:\Temp\"+$date+"_Amp.log"

#Region Log
Function Log($String) {
    "[$([DateTime]::Now)]: $string" | Out-File -FilePath $logfile -Append
}
#endregion Log

Retrieving the full connectors list

#region Get Computer list
    Function Computerlist {
        $list=$null
        $url="https://api.eu.amp.cisco.com/v1/computers"
        Log "Retrieving Computers list"
        $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers -ErrorVariable RestError -ErrorAction SilentlyContinue
        if ($RestError){
            $HttpStatusCode = $RestError.ErrorRecord.Exception.Response.StatusCode.value__
            $HttpStatusDescription = $RestError.ErrorRecord.Exception.Response.StatusDescription
            Log "   - Unable to retrieve the computer list"
            Log  "  - Http Status Code: $($HttpStatusCode) - Http Status Description: $($HttpStatusDescription)"
            Log "Exiting the script"
            Exit
        }
        $global:computerslist = $list.data
        Log "Number of computers retrieved : $($computerslist.Count)"
        do {
            $url=$list.metadata.links.next
            $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers -ErrorVariable RestError -ErrorAction SilentlyContinue
            if ($RestError){
                $HttpStatusCode = $RestError.ErrorRecord.Exception.Response.StatusCode.value__
                $HttpStatusDescription = $RestError.ErrorRecord.Exception.Response.StatusDescription
                Log "   - Unable to retrieve the computer list"
                Log  "  - Http Status Code: $($HttpStatusCode) - Http Status Description: $($HttpStatusDescription)"
                Log "Exiting the script"
                Exit
            }
            $global:computerslist += $list.data
            Log "Number of computers retrieved : $($computerslist.Count)"
        } while ($list.metadata.links.next -ne $null)
        Log "Total Retrieved: $($List.metadata.results.total)"
    }
#endregion list computers

Deleting connectors based on its guid, using global variable that was populate before calling the function

#region Delete computers
    Function Delete_Computer {
        foreach ($connector in $global:delete) {
            If ($connector.hostname -ne "keepthisconnector.tdomain.com"){ #if you want some to be excluded from the deletion
                $url = $url="https://api.eu.amp.cisco.com/v1/computers/"+$connector.connector_guid
                Log "Deleting $($connector.hostname) - $($connector.connector_guid)"
                $Response = Invoke-RestMethod -Method Delete -Uri $url -Headers $Headers -ErrorVariable RestError -ErrorAction SilentlyContinue
                if ($RestError){
                    $HttpStatusCode = $RestError.ErrorRecord.Exception.Response.StatusCode.value__
                    $HttpStatusDescription = $RestError.ErrorRecord.Exception.Response.StatusDescription
                    Log  "  - Http Status Code: $($HttpStatusCode) - Http Status Description: $($HttpStatusDescription)"
                }
                Else {Log "   - $($connector.hostname) deleted : $($response.data.deleted)"}
            }
        }
    }
#endregion Delete_Computer

Retrieving All the groups

#region get groups
    Function Groups {
        Log "Retrieving Group list"
        $url="https://api.eu.amp.cisco.com/v1/groups"
        $global:groups = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers
        $global:groups = $global:groups.data
        Log "$($groups.count) groups retrieved"
        # $global:groups |Format-Table
    }
#endregion groups

Moving a connector to a group (passing the connector guid and the group guid)

#region move computers
    Function Move_Computer {
        Param([string[]]$Connector_Guid,
        [string[]]$group_guid)
        $url="https://api.eu.amp.cisco.com/v1/computers/"+$Connector_Guid
        $body = @{"group_guid" = $group_guid}
        $body = $body | ConvertTo-json
        Log "Moving $($connector_guid)"
        $move = Invoke-RestMethod -Method Patch -Uri $url -Headers $Headers -Body $body #-ErrorVariable $RestError -ErrorAction SilentlyContinue
        if ($RestError){
            $HttpStatusCode = $RestError.ErrorRecord.Exception.Response.StatusCode.value__
            $HttpStatusDescription = $RestError.ErrorRecord.Exception.Response.StatusDescription
            Log "   - Unable to retrieve the computer list"
            Log  "  - Http Status Code: $($HttpStatusCode) - Http Status Description: $($HttpStatusDescription)"
            Log "Exiting the script"
            Exit
        }
    }
#endregion move computers

Deleting duplicate (retrieved the connector list, then filter the duplicate the finally delete every duplicate and keep the latest last_seen)

#region Find_duplicate
    function Delete_Duplicate {
        $temp=@()
        $list=$null
        $global:duplicate=@()
        Computerlist
        $list = $global:computerslist.hostname |Sort
        $ht = @{}
        $list | foreach {$ht["$_"] += 1}
        $ht.keys | where {$ht["$_"] -gt 1} | foreach {$global:duplicate+= $_ }
        $global:duplicate = $global:duplicate|sort
        Log "Found $($global:duplicate.count) duplicate "
        foreach ($connector in $global:duplicate) {
            $temp = $global:computerslist.where({$_.hostname -like $connector})
            $count = $temp.count -1
            $global:delete = $temp | Sort-Object { $_.last_seen -as [datetime] } -Descending  | Select -Last $count
            Delete_Computer
        }
    }
#endregion

Retrieve the full scan event where scan path > 4 for a connector :

#region Get_events_Full_scan_Computer
    function Get_events_Full_scan {
        Param([string[]]$Connector_Guid)
        $global:event = $null
        $list=$null
        $url="https://api.eu.amp.cisco.com/v1/events?connector_guid[]="+$connector_guid
        $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers
        $global:event = $list.data.where({$_.scan.description -like 'Full*' -and $_.scan.scanned_paths -gt 4}) |Sort-Object { $_.date -as [datetime] } -Descending  | Select -first 1
    }
#endregion

Retrieve the list of connector having run a full scan for a specific group

function Get_events_Full_scan_Group {
    Param([string[]]$Group_Guid)
    $list=$null
    $global:event = $null
    $url="https://api.eu.amp.cisco.com/v1/events?group_guid[]="+$Group_Guid #Cp_Deployment
    $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers
    $list.data |Format-List
    $global:event = $list.data.where({$_.scan.description -like 'Full*' -and $_.scan.scanned_paths -gt 4}) | Sort-Object { $_.date -as [datetime] } -Descending
    $global:event |Format-Table -Property connector_guid,Computer, date
}
#endregion

Retrive connector list for a specific group

Function Computerlist_Per_Group {
    Param([string[]]$Group_Guid)
    $list=$null
    Log "Retrieving connectors in the group: $($group_guid)"
    $url="https://api.eu.amp.cisco.com/v1/computers?group_guid[]="+$Group_Guid
    $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers
    $global:computerslist = $list.data
    If ($list.metadata.links.next) {
        do {
            $url=$list.metadata.links.next
            $list = Invoke-RestMethod -Method Get -Uri $url -Headers $Headers
            $global:computerslist += $list.data
        } while ($list.metadata.links.next -ne $null)
    }
    Log "$($global:computerslist.count) connector retrieved"
    $global:computerslist = $global:computerslist | Sort-Object $_.hostname
}
#endregion list computers

Move a connector to another group (and optionally "only if a full scan has run on it")

#region Move_Computer_list
Function Move_Computer_list {
    Param([string[]]$Group_Guid,
    [bool[]]$Full_Scan)
    $global:computerslist = $null
    Groups #retrieve the list of group
    Computerlist_Per_Group $Group_Guid # retrieve the list of connector belonging to a group
    foreach ($connector in $global:computerslist) {
        $Move=$false
        If ($Full_Scan) {
            Log "Retrieving Full scan Events for $($connector.hostname)"
            Get_events_full_scan $connector.connector_guid
            If ($global:event) {
                Log "   Full scan events found"
                $Move=$True
            } Else {Log "   No Full scan events found"}
        } Else {$Move=$True}
        If ($Move -and ($connector.hostname -like 'DT*'-or $connector.hostname -like 'LT*')) {
            $groupname=$connector.hostname.substring(2,$connector.hostname.length -18)
            $group= $global:groups.where({$_.name -match $groupname})
            If ($group) {
                Write-Host "Moving $($connector.hostname) to $($groupname) Group"
                Move_Computer $connector.connector_guid $group.guid
            }
        } Else {Log "   Skipping $($connector.hostname)"}
    }
}
#endregion

 

So here is how I use it :

 

#################### Delete connector not seen the past 10 days ###################
    # $Date_Last_seen = Get-Date -date $(Get-Date).AddDays(-10) -Format u
    # Computerlist
    # $global:delete = $global:computerslist.where({$_.last_seen -lt $Date_Last_seen -and $_.hostname -ne "keepthisconnecotr.domain.com"})
    # If ($global:delete) {
    #     Log "Starting deletion of $($global:delete.count) connectors"
    #     Delete_Computer
    # } Else {Log "No computer found with this 10 days filter"}
###################################################################################

################################ Delete duplicate #################################
    #  Delete_Duplicate
###################################################################################

############## Move connector in "TEST" group if fullscan ok ###############
    # Move_Computer_list -group_guid 'xxxxx-xxxxx-xxxxx-xxxxxxx' -Full_Scan $true 
###################################################################################

######################## Move connector in "temp" group ############################
    # Move_Computer_list -group_guid '3xxxxxxx-xxxxx-xxxxx-xxxxxx' -Full_Scan $false 
###################################################################################

Once again everything can be improved (like using a variable for the common part of $url, it's on my to do list :) ),  I'm not a powershell expert, but those scripts saved me a lot , but a lot of time, and fill a lot of gaps in the portal.

0 Replies 0