Dynamic targeting of actions or baselines via REST

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

@MB43, 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:

This example will update and existing baseline. Tio creat a new baselines you need to use the POST method to the “baselines/custom/IT%20Support” so a new baseline is created, then your need to get the baseline ID returned by the POST before you can deploy can action from it.

Any idea how to set that radio button?

Afraid not, but what I do is to create the actionfrom the baseline via the console then export the created action then review the XML to see what that setting will change in the action XML so it can then be replicated in the XML you’d need create using PowerShell code.

Tried that. I exported a stopped action for that baseline against 2 computers and in the XML, there was no obvious setting that detailed it.

So, it sounds like I cannot do a GET on an existing baseline, modify some things in memory only, submit the memory only changes as a new action without any changes occurring to the original baseline. Bummer

Looking in to the BES.XSD schema, the “SourceFixletAction” type does not allow for overriding the Relevance or ActionScript from the source fixlet/source baseline. I suspect this is to allow for enforcing the “Custom Content” operator right - as overriding the ActionScript or Relevance would likely count as “Custom Content”, I think an operator who is granted rights to Take Action without having Custom Content can probably only send SourcedFixletAction actions.

What I think needs to happen in this case is to build the full MultipleActionGroup XML. It will end up looking the same as an exported Action from the baseline, with the complication that exporting the Action strips out the Targeting and SourceFixletID nodes. You’ll need to add those back in, they appear after <SettingsLocks> per the schema for MultipleActionGroup. The Baseline’s source site can be defined by GatherURL, SiteID, or Site Name. Here’s an example (using SiteName):

		</SettingsLocks>
		<Target>
		  <ComputerName>endpoint-1</ComputerName>
		</Target>
		<SourceFixletID>
		  <!-- <GatherURL>http://BES-Dev-Root:52311/cgi-bin/bfgather.exe/CustomSite_Production</GatherURL> -->
		  <!-- <SiteID></SiteID> -->
		  <Sitename>Production</Sitename>
		  <FixletID>2272</FixletID>
		</SourceFixletID>
	</MultipleActionGroup>

So below is an example of the full XML for one of my lab setup baselines that I’m using to test.

I don’t think I’ll be able to put together the full script for this today, but the basic algorithm would be

  • Retrieve the Baseline XML via GET
  • Create a MultipleActionGroup XML. Fill in the Title and Relevance (the Relevance being ‘true’ or whatever custom relevance you want to apply on the new action)
  • Loop through the BaselineXML retrieving each /BaselineComponentCollection/BaselineComponentGroup/BaselineComponent node.
  • For each BaselineComponent found in the Baseline XML, create a new MemberAction node in the MultipleActionGroup XML. Title, Relevance, ActionScript, SuccessCriteria, and IncludeInGroupRelevance to apply in the MemberAction node should be retrieved from the BaselineComponent node in the source.
  • After appending all the MemberAction nodes, supply whatever Settings and Target to use for the action. Then append the <SourceFixletID> node & children to reference the source baseline.

POST the new MultipleActionGroup to /api/actions

    <?xml version="1.0" encoding="UTF-8"?>
    <BES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BES.xsd">
    	<MultipleActionGroup>
    		<Title>Lab Network Configuration</Title>
    		<Relevance>true</Relevance>
    		<MemberAction>
    			<Title>Configure Windows Firewall: Allow Inbound ICMP Ping</Title>
    			<Relevance><![CDATA[((((windows of operating system) AND (if exists property "in proxy agent context" then not in proxy agent context else true)) AND (version of operating system >= "6" as version)) AND ((not exists key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall" of registry AND firewall enabled of current profile of local policy of firewall) OR (exists key ("HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\" & (if (current profile type of firewall = domain firewall profile type) then ("DomainProfile") else ("StandardProfile"))) whose (value "EnableFirewall" of it = 1) of registry))) AND (not allow inbound echo request of icmp settings of current profile of local policy of firewall)]]></Relevance>
    			<ActionScript MIMEType="application/x-Fixlet-Windows-Shell">
    action uses wow64 redirection false

    waithidden netsh.exe firewall set icmpsetting 8</ActionScript>
    			<SuccessCriteria Option="RunToCompletion"></SuccessCriteria>
    			<IncludeInGroupRelevance>false</IncludeInGroupRelevance>
    		</MemberAction>
    		
    		<MemberAction>
    			<Title>Configure Windows Firewall: Allow Remote Desktop Services</Title>
    			<Relevance><![CDATA[((((windows of operating system) AND (if exists property "in proxy agent context" then not in proxy agent context else true)) AND (version of operating system >= "6" as version)) AND ((not exists key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall" of registry AND firewall enabled of current profile of local policy of firewall) OR (exists key ("HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsFirewall\" & (if (current profile type of firewall = domain firewall profile type) then ("DomainProfile") else ("StandardProfile"))) whose (value "EnableFirewall" of it = 1) of registry))) AND (not rule group currently enabled "remote desktop" of firewall)]]></Relevance>
    			<ActionScript MIMEType="application/x-Fixlet-Windows-Shell">
    action uses wow64 redirection false

    waithidden cmd /c netsh.exe advfirewall firewall set rule group="remote desktop" new enable=Yes</ActionScript>
    			<SuccessCriteria Option="RunToCompletion"></SuccessCriteria>
    			<IncludeInGroupRelevance>false</IncludeInGroupRelevance>
    		</MemberAction>

		<Settings>
			<PreActionShowUI>false</PreActionShowUI>
			<HasRunningMessage>false</HasRunningMessage>
			<HasTimeRange>false</HasTimeRange>
			<HasStartTime>false</HasStartTime>
			<HasEndTime>true</HasEndTime>
			<EndDateTimeLocalOffset>P2D</EndDateTimeLocalOffset>
			<HasDayOfWeekConstraint>false</HasDayOfWeekConstraint>
			<UseUTCTime>false</UseUTCTime>
			<ActiveUserRequirement>NoRequirement</ActiveUserRequirement>
			<ActiveUserType>AllUsers</ActiveUserType>
			<HasWhose>false</HasWhose>
			<PreActionCacheDownload>false</PreActionCacheDownload>
			<Reapply>false</Reapply>
			<HasReapplyLimit>true</HasReapplyLimit>
			<ReapplyLimit>3</ReapplyLimit>
			<HasReapplyInterval>false</HasReapplyInterval>
			<HasRetry>false</HasRetry>
			<HasTemporalDistribution>false</HasTemporalDistribution>
			<ContinueOnErrors>true</ContinueOnErrors>
			<PostActionBehavior Behavior="Nothing"></PostActionBehavior>
			<IsOffer>false</IsOffer>
		</Settings>
		<SettingsLocks>
			<ActionUITitle>false</ActionUITitle>
			<PreActionShowUI>false</PreActionShowUI>
			<PreAction>
				<Text>false</Text>
				<AskToSaveWork>false</AskToSaveWork>
				<ShowActionButton>false</ShowActionButton>
				<ShowCancelButton>false</ShowCancelButton>
				<DeadlineBehavior>false</DeadlineBehavior>
				<ShowConfirmation>false</ShowConfirmation>
			</PreAction>
			<HasRunningMessage>false</HasRunningMessage>
			<RunningMessage>
				<Text>false</Text>
			</RunningMessage>
			<TimeRange>false</TimeRange>
			<StartDateTimeOffset>false</StartDateTimeOffset>
			<EndDateTimeOffset>false</EndDateTimeOffset>
			<DayOfWeekConstraint>false</DayOfWeekConstraint>
			<ActiveUserRequirement>false</ActiveUserRequirement>
			<ActiveUserType>false</ActiveUserType>
			<Whose>false</Whose>
			<PreActionCacheDownload>false</PreActionCacheDownload>
			<Reapply>false</Reapply>
			<ReapplyLimit>false</ReapplyLimit>
			<RetryCount>false</RetryCount>
			<RetryWait>false</RetryWait>
			<TemporalDistribution>false</TemporalDistribution>
			<ContinueOnErrors>false</ContinueOnErrors>
			<PostActionBehavior>
				<Behavior>false</Behavior>
				<AllowCancel>false</AllowCancel>
				<Deadline>false</Deadline>
				<Title>false</Title>
				<Text>false</Text>
			</PostActionBehavior>
			<IsOffer>false</IsOffer>
			<AnnounceOffer>false</AnnounceOffer>
			<OfferCategory>false</OfferCategory>
			<OfferDescriptionHTML>false</OfferDescriptionHTML>
		</SettingsLocks>
		<Target>
		  <ComputerName>endpoint-1</ComputerName>
		</Target>
		<SourceFixletID>
		  <!-- <GatherURL>http://BES-Dev-Root:52311/cgi-bin/bfgather.exe/CustomSite_Production</GatherURL> -->
		  <!-- <SiteID></SiteID> -->
		  <Sitename>Production</Sitename>
		  <FixletID>2272</FixletID>
		</SourceFixletID>
	</MultipleActionGroup>
</BES>
1 Like

Let me take a look at what you have provided thus far. Thanks to all for your inputs.