Forum Discussion

Mark_Hensler's avatar
4 years ago

PowerShell SDK

I am requesting a PowerShell SDK to compliment the current list of SDKs offered for Python and GO.

  • Here's a bit of PS that goes at the head of my scripts for RESTAPI work... uses Credential Manager 2.0 with the restAPI user/key stored in  the windows cred store:

    Import-Module     CredentialManager
    
    function          Send-Request               {
        param (
            $cred               ,
            $URL                ,
            $accessid    = $null,
            $accesskey   = $null,
            $data        = $null,
            $version     = '2'  ,
            $httpVerb    = "GET"
        )
        if ( $accessId -eq $null) {
            $accessId    = $cred.UserName
            $accessKey   = $cred.GetNetworkCredential().Password
        }
        # Use TLS 1.2
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    
        # 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' )
        # uses version 2 of the API
        $headers.Add(      "X-version"    , $version           )
        
    	# Make Request
        try {
            $response        = Invoke-RestMethod  `
                -Uri             $URL             `
                -Method          $httpVerb        `
                -Body            $data            `
                -Header          $headers         `
                -erroraction     stop `
                -warningaction   SilentlyContinue
        } catch {
            $response    = -1
        }
        Return $response
    }
    
    function          Get-LMRestAPIObjectListing {
        param (
            $URLBase          ,
            $resourcePathRoot , # "/device/devices"
            $size = 1000      ,
            $accessKey        ,
            $accessId         ,
            $version = '2'
        )
    
        write-host "Gathering $resourcePathRoot"
    
        $output  = @()
        $looping = $true
        $counter = 0
    
        # write-host "Gathering data from $resourcePathRoot"
        while ($looping) {
    
            # Re-calc offset based on iteration
            $offset = $counter * $size
            $resourcePath    = $resourcePathRoot
            $queryParam      = "?size=$size&offset=$offset"
            $url             = $URLBase + $resourcePath + $queryParam
    
            # Make Request
            $response        = Send-Request `
                -accesskey    $accessKey    `
                -accessid     $accessId     `
                -URL          $url          `
                -version      $version
            if ( $response.items.count -eq $size ) {
                # Return set is full, more items to retrieve
                $output     += $response.items
                $counter++
            } elseif ( $response.items.count -gt 0 ) {
                # Return set is not full, store date, end loop
                $output     += $response.items
                $looping     = $false
            } else {
                # Return set is empty, no data to store, end loop
                $looping     = $false
            }
        }
        write-output $output
        }
    
    $company        = "<CompanyName>"
    $URLBase        = "https://$company.logicmonitor.com/santaba/rest"
    
    # This will resolve to proper values if it's being run from inside LM
    $accessID       = "##Logicmonitor.AccessID.key##"
    $accessKey      = "##Logicmonitor.AccessKey.key##"
    
    if ( $accessID -like "##*" )       {
        # Not being run from inside LM - populate manually for testing
        Import-Module CredentialManager
        $Cred       = Get-StoredCredential -Target LogicMonitor
        $accessID   = $cred.UserName
        $accessKey  = $Cred.GetNetworkCredential().Password
    }
    
    # Get Devices
    $resourcePath         = "/device/devices"
    $Devices              = Get-LMRestAPIObjectListing `
        -resourcePathRoot $resourcePath                `
        -accessKey        $accessKey                   `
        -accessId         $accessID                    `
        -URLBase          $URLBase

    I wrote most of it using the standard "Send-Request" piece from LM's docs and the posts here... but added a bit to work around the request limit to allow me to fill a variable with all of the specific piece I'm looking for.  It also allows for storing creds for dev that are also in LM properties for deployment.  They're stored in a generic windows credential named "LogicMonitor" locally.

    To expand what it does, change or duplicate the "Get Devices" section to target a different $resourcePath from the swagger doc for the restAPI.

    DISCLAIMER: this code comes with no guarantees from myself or my employers past and present that it is safe in your environment.  Use it with caution as you always should.