Dynamic targeting of actions or baselines via REST

We are looking to use REST to maintain and hopefully deploy certain baselines.

In a nutshell we are using PowerShell to access the REST APIs and have successfully managed to take a named baseline, remove all the patch fixlet components from the component group that contains the patches then add all current relevant fixlets, which is in the region of 100 fixlets, back into the baseline and import that back into Bigfix. Once the baseline has been updated, we then use REST to create an action that deploys the baseline to an automatic computer group.

This is successfully deploying the baseline but as its targeting is custom as we are using relevance to target a specific automatic computer group by ID, am I right in thinking that this will not be a dynamic target?

If it isn’t dynamic, is there any way to deploy a fixlet or baseline using REST that will target members of automatic groups that will be dynamic as new machines evaluate into of out of the automatic group?

Are you using a query to return a literal list of computer names or ids? That would be static targetting.

If you target by crafting your xml with a <CustomRelevance> field, that would be dynamically-targetted. Something like

<CustomRelevance> member of group 1234 of site "MyCustomSite" </CustomRelevance>

Thanks @JasonWalker. Yes, I have the CustomRelevance for the target

<Target>
	<CustomRelevance>exists true whose (if true then (member of group 1011277 of site "MyCustomSite") else false)"</CustomRelevance>
</Target>

The baseline and the action and all look correct but where I see 4 machines that evaluated into the group after the baseline was deployed and are relevant for the baseline, these have not been seen as by the action which I would have expected to see as they are online and actively reporting in. Might be something linked to the lock state, though the baselines and the action created are in a custom site that has lock override in place. Not sure I can safely unlock one of the endpoint but I’ll keep digging.

Did you ever solve this issue? I’m running the exact same scenario. My endpoint correctly shows as the baseline being relevant however it never reports in when the action is created. I logged onto the endpoint and tested the custom relevance in fixlet debugger to make sure it returns True (it does). This endpoint is not locked. I’m not sure what i’m missing. Any help would be appreciated. Thanks!

How long did you give for the endpoint to report? Is it responding to other actions?

If the UDP notifications from the relay to the client are blocked, the client would not be notified of the new action; it would only gather and report to the new action during the next relay select interval (6 hours, by default) unless you configured Command Polling at the client, or Persistent Connections at both the Relay and the client.

(The same issue could affect the Relay being notified of the new content, if downstream TCP/52311 is blocked from a Parent relay to a Child relay)

1 Like

It’s been more than 12 hours. UDP is not blocked. Yes, it responds to other actions. I tried with a different server this morning and get the same result. If i target via the console (rather than API) with the same baseline it picks it up within minutes and starts patching. I’ve tried this in 2 different bigfix environments i manage. I’m missing something, i’m just not sure what. I’ve tried targeting using 3 different ways (it’s an automatic group):

  • exists true whose (if true then (member of 1353 of site “CustomSite_Endpoints”) else false)
  • exists true whose (if true then (member of 1353 of sites) else false)
  • member of 1353 of site “CustomSite_Endpoints”

Alas I was never able to solve this one or narrow down possible causes. As even that act of automating the creation and management of baselines was, for us, a major time saver, we adopted a hybrid process where we use REST to automatically create/manage baselines then use the console to deploy them as dynamic actions to established automatic computre groups.

Patch Policies didn’t fit our requirement and I think it still has its limitations, ie you can’t include only “MSyy-MMM” security fixlets then create excludes, eg deploy all MS bulletins but not those for things like Exchange, SQL. If you include all security fixlets you get more than just MS bulletins

Just chiming in to say I’ve seen the same issue.

We create baselines & actions similar to how @SLB does except we use VBscript instead of PowerShell. On the baseline, the Relevance tag set exactly what he showed (except for the group ID, obviously). When the action is created, the CustomRelevance tag is used instead with the same data.

When the action is created, ONLY those computers that were in the target group when the action was created will ever execute that action. Even if computers that were added to the group afterwards are relevant for the baseline used to create the action, they will never execute it.

1 Like

Is that a literal copy/paste? All three are missing “group”, like member of *group* 1353

yup, my python script had a bug :slight_smile:

It was stripping ‘group’ out of the relevance. I fixed it and now it’s working as expected. Both my test endpoints see the action now! Thanks Jason

1 Like

@mikelbeck, I just tested the scenario you described and everything seemed to work as advertised. I used this relevance for targeting my endpoints.

exists true whose (if true then (member of group xxxx of site “CustomSite_Endpoints”) else false)

2 Likes

I just tested the scenario you described and everything seemed to work as advertised. I used this relevance for targeting my endpoints.

@LouC I tested it as well and it is indeed working properly now.

3 Likes

Would you be willing to share your posh code with company specific stuff removed?

https://developer.bigfix.com/rest-api/api/action.html
This link and many of the ones on the developer site offer very little when it comes to samples. <hint> we need a lot more samples.

I think I need to create an action to run a baseline but have zero examples to start with.

I’m not sure it’s obvious, but on each of those REST documentation pages you can click on the resource to expand it with example. Here I clicked on ‘POST /api/actions’ to expand it with the examples including XML -

The easiest option for this is to post a SourcedFixletAction, referencing the Baseline ID and source site. The example here using the SourcedFixletAction is valid, with the only difference that for a Baseline as a source you may optionally omit the <Action> node that is used to name which action from a Fixlet to use (in the example, “Action1”).

I could put together a longer example if you like - let me know whether you’re having trouble finding the source baseline, or with computer targeting, or if expanding the examples is enough to get you going.

The baseline could be new so it won’t be saved and there won’t be an ID unless you are saying that to push a baseline it has to be saved which would generate an ID?

My desire is to do a GET on an existing baseline, change the title, relevance and target list in the xml copy contained in the script/memory only, then submit that xml without saving the altered baseline. I only want to alter the xml from the saved baseline in memory and submit it as an action and when script ends, that altered xml is gone by design.

Hm. There aren’t any Targets on a baseline, only on the Action taken from the baseline.

How are you using baseline relevance where it would need to change upon taking action? Usually Baseline relevance is something simple - like “Windows of operating system”.

If this is an action that’s not taken from a baseline (the baseline that doesn’t exist), then it’s a special case we’d call a Multi-Action Group. In that case there’s not actually a baseline, just a collection of actions taken from multiple Fixlets (like selection multiple fixlets, and using the right-click menu for “Take Default Action”. This is also how Patch Policy issues actions). Is that your intent?

Just want to understand the use-case a bit better (esp. around changing the relevance), there are multiple ways to do this.

The saved baseline runs all the time against all computers with relevance that looks like this:

This relevance randomizes the day it runs a scan (this is for BF Inventory BTW) to every 7 days based on computer ID. This is all working and fine.

We get occasional requests to run a scan adhoc on 1 or more computers so I wanted to create a script that did this instead of using the slow console. I could try WebUI too but wanted to script this as well. I have the code that sets this to true but I am also struggling with setting this radio button:

I played around with <ApplicabilityRelevance>true</ApplicabilityRelevance> but no joy.

So, as stated earlier, I want to do a GET on this baseline, change the title, relevance and target list in the xml copy contained in the script/memory only, then submit that xml without saving the altered baseline. I only want to alter the xml in memory in the script and submit it as an action and when script ends, that altered xml is gone by design.

Ok, that makes a lot of sense, thanks for going in to such detail.

The impression I get is that you’re already comfortable with your script methods for manipulating the XML, and at this point you just need to know the correct XML to post, is that correct?

Here is some very basic and somewhat crude PowerShell code to pull a baseline, change its name and description and put the updated baselines back to the server then deploy it to a computer group. This uses ID and sites I have in my DEV server so baseline ID to update is 7014 in the custom site “IT Support”

$urlbase = "https://your.bes.server:52311/api/"
$url = $urlbase + "login"
$username = "youruser"
$password = "yourpassword"
$EncodedAuthorization = [System.Text.Encoding]::UTF8.GetBytes($username + ':' + $password)
$EncodedPassword = [System.Convert]::ToBase64String($EncodedAuthorization)
$headers = @{"Authorization"="Basic $($EncodedPassword)"}
$result = Invoke-WebRequest -Uri $url -Method GET -Headers $headers

if ($result.StatusCode -eq 200) {

    # GET the fixlet XML from the given site, type and ID
    $url = $urlbase + "baseline/custom/IT%20Support/7014"
    [xml]$BaselineXML = Invoke-RestMethod -Uri $url -Method GET -Headers $headers
    #Change the name and description    
    $BaselineXML.BES.Baseline.Title = "Test Baseline Renamed"
    $BaselineXML.BES.Baseline.Description = "Current time is $(Get-Date -UFormat "%R")"
    # Put the modified baseline back
    $Postresults = Invoke-RestMethod -Uri $url -Method "PUT" -Headers $headers -Body $BaselineXML.OuterXml.ToString()
    # Deploy the baseline to a computer group to start immediately and expire 7 days from now
    [xml]$ActionXML = New-Object system.Xml.XmlDocument
    $ActionXML.LoadXml("
    <BES xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`" xsi:noNamespaceSchemaLocation=`"BES.xsd`">
        <SourcedFixletAction>
            <SourceFixlet>
                <Sitename>IT Support</Sitename>
                <FixletID>7014</FixletID>
                <Action>Action1</Action>
            </SourceFixlet>
            <Target>
                <CustomRelevance>member of group 7015 of site `"CustomSite_IT_Support`"</CustomRelevance>
            </Target>
            <Settings>
                <PreActionShowUI>false</PreActionShowUI>
                <HasRunningMessage>false</HasRunningMessage>
                <HasTimeRange>false</HasTimeRange>
                <HasStartTime>false</HasStartTime>
                <HasEndTime>true</HasEndTime>
                <EndDateTimeLocalOffset>P7DT0H0M0S</EndDateTimeLocalOffset>
                <HasDayOfWeekConstraint>false</HasDayOfWeekConstraint>
                <UseUTCTime>true</UseUTCTime>
                <ActiveUserRequirement>NoRequirement</ActiveUserRequirement>
                <ActiveUserType>AllUsers</ActiveUserType>
                <HasWhose>false</HasWhose>
                <PreActionCacheDownload>false</PreActionCacheDownload>
                <Reapply>true</Reapply>
                <HasReapplyLimit>true</HasReapplyLimit>
                <ReapplyLimit>3</ReapplyLimit>
                <HasReapplyInterval>false</HasReapplyInterval>
                <HasRetry>true</HasRetry>
                <RetryCount>3</RetryCount>
                <RetryWait Behavior=`"WaitForReboot`">PT1H</RetryWait>
                <HasTemporalDistribution>false</HasTemporalDistribution>
                <ContinueOnErrors>true</ContinueOnErrors>
                <PostActionBehavior Behavior=`"Nothing`"></PostActionBehavior>
                <IsOffer>false</IsOffer>
            </Settings>
            <Title>My Baseline Deployment via TEST API</Title>
        </SourcedFixletAction>
    </BES>")
    $url = $urlbase + "actions"
    $NewActionID = Invoke-RestMethod -Uri $url -Method POST -Headers $headers -Body $ActionXML.OuterXml.ToString()
}

On my DEV ist results in an action being created, though can’t yet vouch if it actually is dynamic as machines appear in or out of the group.

2 Likes

This does not modify the saved baseline I have right? I am only interested in either creating a new baseline, running it, then deleting it OR GET the existing baseline, modify in memory only things about it and run it.

I have code working that sets this to true but can’t figure out how to set that radio button: