Targeting a GROUP with API to schedule SourcedFixletAction

I cannot seem to get this to work. I am targeting a group using the in XML, but it keeps failing. I have a feeling my XML is ok but my PowerShell is the issue. Any help is appreciated:

<?xml version="1.0" encoding="UTF-8"?>
<BES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BES.xsd">
    <SourcedFixletAction>
        <SourceFixlet>
            <Sitename />
            <FixletID />
            <Action>Action1</Action>
        </SourceFixlet>
        <Target>
          <CustomRelevance>exists true whose ( if true then ( member of group 1075264 of site "Data Center (WIN)" ) else false )</CustomRelevance>
        </Target>
        <Settings>
            <HasStartTime>true</HasStartTime>
            <StartDateTimeLocal />
            <HasEndTime>true</HasEndTime>
            <EndDateTimeLocal />
            <UseUTCTime>false</UseUTCTime>
            <ActiveUserRequirement>NoRequirement</ActiveUserRequirement>
            <ActiveUserType>UsersOfGroups</ActiveUserType>
            <UIGroupConstraints>
                <LocalGroup Name="Administrators"/>
            </UIGroupConstraints>
            <HasWhose>false</HasWhose>
            <PreActionCacheDownload>true</PreActionCacheDownload>
            <Reapply>true</Reapply>
            <HasReapplyLimit>false</HasReapplyLimit>
            <HasReapplyInterval>false</HasReapplyInterval>
            <HasRetry>true</HasRetry>
            <RetryCount>99</RetryCount>
            <RetryWait Behavior="WaitForInterval">PT10M</RetryWait>
            <HasTemporalDistribution>false</HasTemporalDistribution>
            <ContinueOnErrors>true</ContinueOnErrors>
            <PostActionBehavior Behavior="Nothing">
                <AllowCancel>false</AllowCancel>                
            </PostActionBehavior>
        </Settings>
        <Title />
    </SourcedFixletAction>
</BES>

And my powershell function looks like this:

Function ScheduleActionFromFixlet {
    param (
        [Parameter(Mandatory=$true,
            HelpMessage="Expecting input of the form: https://<bigfix_server>:52311")]
            [string]$APIBaseUrl,
        [Parameter(Mandatory=$true,
            HelpMessage="Path to directory containing XML templates files")]
            [string]$TemplateDirectory,
        [Parameter(Mandatory=$true,
            HelpMessage="The desired display name of the new action to be created")]
            [string]$ActionTitle,
        [Parameter(Mandatory=$true)]$SiteName,
        [Parameter(Mandatory=$true)]$FixletID,
        [Parameter(Mandatory=$true)][int[]]$TargetComputerID,
        [Parameter(Mandatory=$true)][System.DateTimeOffset]$StartDateTime,
        [Parameter(Mandatory=$true)][System.DateTimeOffset]$EndDateTime,
        [Parameter(Mandatory=$true)]$HasEndTime,
        [bool]$ActionRestartComputer=$false,
        [Parameter(Mandatory=$true)][Microsoft.PowerShell.Commands.WebRequestSession]$WebSession
    )
    $xmlTemplate = $($TemplateDirectory + $TemplateFile)
    if (!(Test-Path -Path $xmlTemplate)) {
        return @("TEMPLATE_NOT_FOUND",$null)
    }
    # Get XML template and update it with input parameter data
    $actionXML = [xml](Get-Content -Path $xmlTemplate)
    $actionXML.BES.SourcedFixletAction.SourceFixlet.Sitename = $SiteName
    $actionXML.BES.SourcedFixletAction.SourceFixlet.FixletID = [string]$FixletID
    # PowerShell treats null-valued elements as String instead of XmlElement, so need to cast
    [System.Xml.XmlElement]$xmlTarget = $actionXML.SelectSingleNode('./BES/SourcedFixletAction/Target')
    foreach ($computerID in $TargetComputerID) {
        $computerIDElement = $actionXML.CreateElement("ComputerID")
        $computerIDText = $actionXML.CreateTextNode([string]$computerID)
        $customRelevanceElement = $actionXML.CreateElement("CustomRelevance")
        $customRelevanceText = $actionXML.CreateTextNode([string]$customRelevance)
        [void]($computerIDElement.AppendChild($ComputerIDText))
        [void]($xmlTarget.AppendChild($computerIDElement))
        [void]($customRelevanceElement.AppendChild($customRelevanceText))
        [void]($xmlTarget.AppendChild($customRelevanceElement))
    }

    $actionXML.BES.SourcedFixletAction.Settings.StartDateTimeLocal = $StartDateTime.ToString('yyyy-MM-dd HH:mm:ss')
    $actionXML.BES.SourcedFixletAction.Settings.HasEndTime = $HasEndTime
    $actionXML.BES.SourcedFixletAction.Settings.EndDateTimeLocal = $EndDateTime.ToString('yyyy-MM-dd HH:mm:ss')

    if ($ActionRestartComputer) {
        $actionXML.BES.SourcedFixletAction.Settings.PostActionBehavior.Behavior = 'Restart'
    }
    $actionXML.BES.SourcedFixletAction.Title = $ActionTitle
    $uri = $($APIBaseUrl + "/api/actions")
    $body = $actionXML.OuterXml

    Try {
        $response = Invoke-WebRequest -UseBasicParsing -SkipCertificateCheck -Uri $uri -Method Post -ContentType "application/xml" -Body $body -WebSession $WebSession -ErrorAction Stop | Out-Null
    } Catch {
            return @("REQUEST_FAILED",$null)
    }
    $returnVal = New-Object -TypeName System.Collections.ArrayList
    foreach ($action in ([xml]($response.Content)).BESAPI.Action) {
        [void]($returnVal.Add(
            [pscustomobject]@{
                ID = $action.ID;
                Name = $action.Name
            }
        ))
    }
    return @($null,$returnVal)
}

I call it with this:

ScheduleActionFromFixlet -APIBaseUrl $APIBaseUrl -TemplateDirectory $TemplateDirectory -ActionTitle $ActionTitle -SiteName $SiteName -FixletID $FixletID -TargetComputerID $TargetComputerID -StartDateTime $StartDateTime  -HasEndTime $HasEndTime -EndDateTime $EndDateTime -WebSession $Session[1]

Do you get a failure code back on the REST POST/PUT call, or does it create an action that never runs, or something else?

Doesnt create anything. All I get is “Request failed”

That helps though, it implies something’s wrong with the schema of the XML you’re posting.

Can you have it print a preview of the XML it attempted to post?

<?xml version="1.0" encoding="UTF-8"?>
<BES
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BES.xsd">
	<SourcedFixletAction>
		<SourceFixlet>
			<Sitename>Data Center (WIN)</Sitename>
			<FixletID>39096</FixletID>
			<Action>Action1</Action>
		</SourceFixlet>
		<Target>
			<CustomRelevance>exists true whose ( if true then ( member of group 1075264 of site "Data Center (WIN)" ) else false )</CustomRelevance>
			<ComputerID>1075264</ComputerID>
			<CustomRelevance></CustomRelevance>
		</Target>
		<Settings>
			<HasStartTime>true</HasStartTime>
			<StartDateTimeLocal>2024-04-12 16:00:00</StartDateTimeLocal>
			<HasEndTime>true</HasEndTime>
			<EndDateTimeLocal>2024-04-12 20:00:00</EndDateTimeLocal>
			<UseUTCTime>false</UseUTCTime>
			<ActiveUserRequirement>NoRequirement</ActiveUserRequirement>
			<ActiveUserType>UsersOfGroups</ActiveUserType>
			<UIGroupConstraints>
				<LocalGroup Name="Administrators" />
			</UIGroupConstraints>
			<HasWhose>false</HasWhose>
			<PreActionCacheDownload>true</PreActionCacheDownload>
			<Reapply>true</Reapply>
			<HasReapplyLimit>false</HasReapplyLimit>
			<HasReapplyInterval>false</HasReapplyInterval>
			<HasRetry>true</HasRetry>
			<RetryCount>99</RetryCount>
			<RetryWait Behavior="WaitForInterval">PT10M</RetryWait>
			<HasTemporalDistribution>false</HasTemporalDistribution>
			<ContinueOnErrors>true</ContinueOnErrors>
			<PostActionBehavior Behavior="Nothing">
				<AllowCancel>false</AllowCancel>
			</PostActionBehavior>
		</Settings>
		<Title>KRO - Fri 8:00 PM Test Schedule Reboot - SQL Servers - Security Updates</Title>
	</SourcedFixletAction>
</BES>

OK so after I noticed it is passing ComputerID as well as using a customrelevance, I pulled out the computerID stuff, and it seems to create the job now. The next issue is my relevance is not working. The jop that is created shows Relevance of TRUE, but under the computers tab, it shows nothing. Furthermore, when I run the relevance through the fixlet debugger, it comes up as false. There is one computer in this particular group.

What I have is:

exists true whose ( if true then ( member of group 1075264 of site "Data Center (WIN)" ) else false )

image

What if you use something like this:

(member of group 1075264 of sites)

Where 1075264 is the id of the specific computer group.

I get the same result.

Try this

(exists true whose (if true then (member of group 1075264 of sites whose (name of it = "Data Center (WIN)")) else false))

This is the syntax I use that successfully creates an action via the API targeting an automatic group

2 Likes