Skip to main content
Question

Script to Add Computer to Static Group


Forum|alt.badge.img+14
  • Valued Contributor
  • 375 replies

Has anyone successfully deployed the following script to add a computer to a static group. Goal: Have buttons in Self Service to add a computer to a static group.

$4 is the group ID.

#!/bin/sh

#API login info
apiuser="apiaccount"
apipass='apiaccountpassword'
jamfProURL="https://myjamfinstance.jamfcloud.com"

ComputerName=$(hostname)

#Group to update
GroupID="$4"
apiURL="JSSResource/computergroups/id/${GroupID}"

#XML header stuff
xmlHeader="<?xml version="1.0" encoding="UTF-8" standalone="no"?>"

apiData="<computer_group><id>${GroupID}</id><name>Whatever the GroupName Is</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"

curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}" 
    -H "Content-Type: text/xml" 
    -d "${xmlHeader}${apiData}" 
    -X PUT  > /dev/null

18 replies

Forum|alt.badge.img+14
  • Valued Contributor
  • 342 replies
  • January 29, 2020

Just out of curiosity why wouldn't a Smart Group work for the scope of what you're trying to accomplish?


Forum|alt.badge.img+16
  • Valued Contributor
  • 182 replies
  • January 29, 2020

I have a goal of phasing this out in hopes of using a drop down extension attribute instead. But we do currently do this.

It has a few preset parameters:
$4 = Group ID#
$5 = 'additions' or 'deletions' It has to be just either of those strings with no quotes, or this won't function. This will control if it adds the computer or deletes the computer from the group.
$6 = APIUserName
$7 = APIPassword
if API username and Password are not given it will prompt the user for the JSS ID and Password.
$8 = Silent
anystring will make this run silent. If this is left blank then the user will get an alert of success or failure joining the group.

#! /bin/bash

jamfproURL="https://yoururlhere.jamfcloud.com"

default_group="856"
computer_name="$2"
current_user="$3"
silent="$8"



if [ -z $4 ]
    then
        groupid="$default_group"
    else
        groupid="$4"
fi

if [ -z $5 ]
    then
        action="additions"
    else
        action="$5"
fi

if [ -z $6 ]
    then
        APIUser=$(/usr/bin/osascript<<END
        tell application "System Events"
        activate
        set the answer to text returned of (display dialog "Please enter your Jamf Username:" default answer "" buttons {"Continue"} default button 1)
        end tell
        END)
    else
        APIUser="$6"
fi

if [ -z $7 ]
    then
        APIPass=$(/usr/bin/osascript<<END
        tell application "System Events"
        activate
        set the answer to text returned of (display dialog "Please enter your Jamf Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
        end tell
        END)
    else
        APIPass="$7"
fi

xml="<computer_group><computer_${action}><computer><name>$computer_name</name></computer></computer_${action}></computer_group>"

fullURL="${jamfproURL}/JSSResource/computergroups/id/${groupid}"

echo "Created XML"
echo $xml

echo "Jamf API URL"
echo $fullURL


result=$`curl "$fullURL" -u "$APIUser:$APIPass" -H "Content-Type: text/xml" -X PUT -d "$xml"`

echo "result"
echo "$result"

if [ -z $silent ] ; then
    if [[ "$result" == *"<p>The request requires user authentication</p>"* ]] ; then
        echo "Showing Fail message"
        /usr/bin/osascript -e 'tell app "System Events" to display dialog "Failed to update Static Group. Please check your network connection and try again."'
    else
        echo "Showing success message"
        dialog="${action} for the Static Group probably successful."
        cmd="Tell app "System Events" to display dialog "$dialog""
        /usr/bin/osascript -e "$cmd"
    fi
else
    echo "running silent No user notifications"
fi
exit 0

Forum|alt.badge.img+11
  • Contributor
  • 20 replies
  • January 29, 2020

This may be more than you bargained:

#!/bin/bash


#    While static groups within JAMF PRO are typically thought of as 
#    less-uesful than their more dynamic counterparts known as smart 
#    groups, I have found they still serve a critical role. This is 
#    especially so for those who extract the most from JAMF PRO via a
#    series of API scripts. Those API script often return a list of 
#    computer IDs or names. But those lists usually need to be acted 
#    upon in some way. Being able to easily create a static group within
#    JAMF PRO can make that happen. 

#    That is why I wrote this script. It allows for the quick creation
#    and/or re-population of a static group based on a string of computer 
#    IDs or names

#    Author:        Andrew Thomson
#    Date:          02-10-2017
#    GitHub:        https://github.com/thomsontown
#    Version:       1.02 (12-11-2019)


#    uncomment to override variables
# JSS_USER=""
# JSS_PASSWORD=""
# JSS_AUTH=""


function addGroupMembers() {

    local GROUP_ID="$1"
    local GROUP_NAME="$2"
    local COUNT=1

    #   create opening xml for replacing members of the static group
    XML_COMPUTER_TEMPLATE="<computer_group><id>$GROUP_ID</id><name>$GROUP_NAME</name><computers>"

    #   enumerate computers to re-populate static group
    for COMPUTER in ${COMPUTERS[@]}; do

        progressBar "${#COMPUTERS[@]}" "$((COUNT++))"

        #   derermine if computer id (integer) or name (alpha) was provided
        if isInteger "$COMPUTER"; then
            XML_COMPUTER=$(/usr/bin/curl -X GET -H "Content-Type: application/xml" -H "Authorization: Basic $JSS_AUTH" -s "${JSS_URL%/}/JSSResource/computers/id/$COMPUTER/subset/general" 2> /dev/null)

            COMPUTER_NAME=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/name/text()"          2> /dev/null)
            COMPUTER_SN=$(echo $XML_COMPUTER   | /usr/bin/xpath "/computer/general/serial_number/text()" 2> /dev/null)
            COMPUTER_ID="$COMPUTER"
        else
            XML_COMPUTER=$(/usr/bin/curl -X GET -H "Content-Type: application/xml" -H "Authorization: Basic $JSS_AUTH" -s "${JSS_URL%/}/JSSResource/computers/name/$COMPUTER/subset/general" 2> /dev/null)

            COMPUTER_ID=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/id/text()"            2> /dev/null)
            COMPUTER_SN=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/serial_number/text()" 2> /dev/null)
            COMPUTER_NAME="$COMPUTER"
            COMPUTER_NAME=$(encodeUrl "$COMPUTER_NAME")
        fi

        #   verify computer details were found      
        if [ -z "$COMPUTER_SN" ] || [ -z "$COMPUTER_ID" ] || [ -z "$COMPUTER_NAME" ]; then 
            echo -e  "
ERROR: Unable to retrieve info for computer [$COMPUTER]." >&2
            continue
        fi 

        #   insert xml requied for each computer be a member of the static group
        XML_COMPUTER_TEMPLATE+="<computer><id>$COMPUTER_ID</id><name>$COMPUTER_NAME</name><serial_number>$COMPUTER_SN</serial_number></computer>"
    done

    #   close out the xml for re-populating members of the static group
    XML_COMPUTER_TEMPLATE+="</computers></computer_group>"

    #   verify xml formatting before submitting
    if ! XML_COMPUTER_TEMPLATE=$(echo $XML_COMPUTER_TEMPLATE | /usr/bin/xmllint --format -); then 
        echo "ERROR: Imporperly formatted data structure found." >&2
        return $LINENO
    fi

    #   upload xml to re-populate the computers in the static group
    HTTP_CODE=$(/usr/bin/curl -X PUT -H "Content-Type: application/xml" -w "%{http_code}" -H "Authorization: Basic $JSS_AUTH" -d "$XML_COMPUTER_TEMPLATE" -o /dev/null -s "${JSS_URL%/}/JSSResource/computergroups/id/$GROUP_ID" 2> /dev/null)
    if [ "$HTTP_CODE" -ne "201" ]; then
        echo "ERROR: Unable to replace computers in static group." >&2
        return $LINENO
    fi
}


function createStaticGroup() {

    # $1 = Name of static group to create. (My Amazing Group)
    local GROUP_NAME="$1"

    #   query jss for existing group name to get id
    GROUP_ID=$(/usr/bin/curl -X GET -H "Accept: application/xml" -H "Authorization: Basic $JSS_AUTH" -s "${JSS_URL%/}/JSSResource/computergroups/name/$GROUP_NAME" | /usr/bin/xpath "//computer_group/id/text()" 2> /dev/null)

    #   create new group if no existing one can be found
    if [ -z "$GROUP_ID" ]; then

        #   minimal xml required to create static group
        XML_GROUP_TEMPLATE="<computer_group><id>0</id><name>$GROUP_NAME</name><is_smart>false</is_smart></computer_group>"

         #  upload xml to create static group
        GROUP_ID=$(/usr/bin/curl -X POST -H "Content-Type: application/xml" -H "Authorization: Basic $JSS_AUTH" -d "${XML_GROUP_TEMPLATE}" -s "${JSS_URL%/}/JSSResource/computergroups/id/0" | /usr/bin/xpath "//computer_group/id/text()" 2> /dev/null)

        #   display error or return group id
        if [ -z "$GROUP_ID" ]; then 
            echo "ERROR: Unable to create JSS computer group." >&2
            return $LINENO
        fi
    fi

    echo "$GROUP_ID"
    return 0
}


function encodeBasicAuthorization() {

    # $1 = User name for JSS query. (jsmith)
    # $2 = Password for JSS query.  (itisasecret)
    local USERNAME="$1"
    local PASSWORD="$2"

    if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ]; then
        writeLog "ERROR: Missing parameter(s)." >&2
        return $LINENO
    fi

    if ! AUTHORIZATION=$(/usr/bin/printf "$USERNAME:$PASSWORD" | /usr/bin/iconv -t ISO-8859-1 2> /dev/null | /usr/bin/base64 -i - 2> /dev/null); then
        writeLog "ERROR: Unable to encode authorization credentials [$?]." >&2
        return $LINENO
    else
        echo "$AUTHORIZATION"
        return 0
    fi
}


function encodeUrl() {

    # $1 = Universal Resource Locator to be encoded. (https://www.company.com/some/path/index.htm)
    local URL="$1"
    local PREFIX=$(echo $URL | /usr/bin/grep -Eoi "^(afp|file|ftp|http|https|smb)://" 2> /dev/null)   
    local LENGTH=${#PREFIX}
    local SUFFIX=${URL:$LENGTH} 
    local ENCODED="" 

    if [ -z "$SUFFIX" ]; then
        echo "ERROR: Specified URL is incomplete."
        return $LINENO
    fi

    while [ -n "$SUFFIX" ]; do
        TAIL=${SUFFIX#?}
        HEAD=${SUFFIX%$TAIL}
        case $HEAD in
          [-._~0-9A-Za-z/:]) ENCODED+=$(/usr/bin/printf  %c "$HEAD");; #  encoding not required   
          *) ENCODED+=$(/usr/bin/printf  %%%02x "'$HEAD")              #  encoding required
        esac
        SUFFIX=$TAIL
    done
    echo "${PREFIX}$ENCODED"
}


function initJamf() {

    #   verify encoded authorization
    if [ -z "$JSS_AUTH" ]; then     

        # verify username and password for jss
        if [ -n "$JSS_USER" ] || [ -z "$JSS_PASSWORD" ]; then 
            echo "ERROR: A username or password to access to the JSS was not specified." >&2
            return $LINENO
        fi

        if declare -f encodeBasicAuthorization &> /dev/null; then
            if ! JSS_AUTH=$(encodeBasicAuthorization "$JSS_USER" "$JSS_PASSWORD"); then 
                return $LINENO
            fi
        else
            echo "ERROR: Unable to encode username and password to access the JSS." >&2
            return $LINENO
        fi
    fi

    #   get jss url
    JSS_URL=$(/usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url 2> /dev/null)
    if [ -z "JSS_URL" ]; then
        echo "ERROR: A a valid URL to the JSS was not specified [JSS_URL]." >&2
        return $LINENO
    fi

    #   verify jss is available
    JSS_CONNECTION=$(/usr/bin/curl --connect-timeout 10 -H "Authorization: Basic $JSS_AUTH" -sw "%{http_code}" ${JSS_URL%/}/JSSCheckConnection -o /dev/null)
    if [ $JSS_CONNECTION -ne 200 ] && [ $JSS_CONNECTION -ne 403 ] ; then
        echo "ERROR: Unable to connect to JSS [$JSS_URL]." >&2
        return $LINENO
    fi
}


function isInteger() { 

    return $([ "$@" -eq "$@" ] 2> /dev/null) 
}


function main() {

    while [ -n "$1" ]; do
        case $1 in
            -n | --name )       shift;GROUP_NAME="$1"   ;;
            -f | --file )       shift;FILE_PATH="$1"    ;;
            -u | --user )       shift;JSS_USER="$1"     ;;
            -p | --pass )       shift;JSS_PASSWORD="$1" ;;
            -a | --auth )       shift;JSS_AUTH="$1"     ;;
            -h | --help )       shift;usage             ;;
            * )                 COMPUTERS+=( "$1" ) 
        esac
        shift
    done

    #   load common source variables
    if [ -f ~/.bash_source ]; then
        source ~/.bash_source
    fi

    #   prompt for password if missing
    if [ -z "$JSS_AUTH" ] && [ -n "$JSS_USER" ] && [ -z "$JSS_PASSWORD" ]; then 
        echo "Please enter JSS password for account [$JSS_USER]: "
        read -s JSS_PASSWORD
    fi

    #   verify user and password or encoded authorization
    if [ -z "$JSS_USER" ] || [ -z "$JSS_PASSWORD" ] && [ -z "$JSS_AUTH" ]; then 
        echo "ERROR: A JSS user name and password are required if no encoded authorization is provided." >&2
        usage
        exit $LINENO
    fi 

    #   verify group name was specified
    if [ -z "$GROUP_NAME" ]; then 
        echo "Please enter a name for the group you wish to create/populate: "
        read GROUP_NAME
        if [ -z "$GROUP_NAME" ]; then 
            echo "ERROR: No group name was specified." >&2
            exit $LINENO
        fi
    fi

    #   verify member source
    if [ ! -r "$FILE_PATH" ] && [ "${#COMPUTERS[@]}" -eq "0" ]; then 
        echo "Please drag-n-drop or enter the path to a line-seperated file containing computer names or IDs: "
        read FILE_PATH
        if [ ! -r "$FILE_PATH" ]; then
            echo "ERROR: The path to the specified readable file cound not be found [$FILE_PATH]." >&2
            exit $LINENO
        fi
    fi

    #   populate array with computer names from file
    if [ -r "$FILE_PATH" ]; then
        while IFS= read -r COMPUTER; do
          COMPUTERS+=($COMPUTER)
        done < "$FILE_PATH"
    fi

    #   obsure password for debug
    for ((i=1; i<${#JSS_PASSWORD}; i++)); do
        JSS_OBSURED+="◦"
    done

    #   display parameters for debug
    if $DEBUG; then 
        echo -e  "NAME: $GROUP_NAME
FILE: $FILE_PATH
USER: $JSS_USER
PASS: $JSS_OBSURED
AUTH: $JSS_AUTH
COMPUTERS: ${COMPUTERS[@]}"
    fi

    #   initialize and verify jamf connection
    if ! initJamf; then exit $LINENO; fi

    #   create/get computer group id
    if ! GROUP_ID=$(createStaticGroup "$GROUP_NAME"); then exit $LINENO; fi

    #   add each computer to group
    addGroupMembers "$GROUP_ID" "$GROUP_NAME" 

    #   play sound to signal completion
    playSound
}


function playSound() {

    # $1 = Path to sound file. (/System/Library/Sounds/Glass.aiff)
    local SOUND_FILE_PATH="$1"

    if [ -z "$SOUND_FILE_PATH" ] && [ -f "/System/Library/Sounds/Glass.aiff" ]; then
        local SOUND_FILE_PATH="/System/Library/Sounds/Glass.aiff" 
    fi

    if [ -f "$SOUND_FILE_PATH" ]; then
        /usr/bin/afplay "$SOUND_FILE_PATH" &> /dev/null
    fi
}


function progressBar() {

    # $1 = Maximum count of progress. (75)
    # $2 = Current count of progress. (10)
    local MAX="$1"
    local COUNT="$2"

    #   verify required parameters
    if [ -z "$MAX" ] || [ -z "$COUNT" ]; then
        echo "ERROR: Missing parameter."
        return $LINENO
    fi

    #   verify parameters are integers
    if [ "$MAX" -ne "$MAX" ] 2> /dev/null || [ "$COUNT" -ne "$COUNT" ] 2> /dev/null; then
        echo "ERROR: Integer expression expected." >&2
        return $LINENO
    fi

    if [ "$COUNT" -lt "$MAX" ]; then 
        #   display progress
        PERCENT_COMPLETE=$(echo "(100/$MAX)*$COUNT" | /usr/bin/bc -l | /usr/bin/awk '{print int($1+0.5)}')
        PROGRESS_DONE=$(echo "$PERCENT_COMPLETE/2" | /usr/bin/bc -l | /usr/bin/awk '{print int($1+0.5)}')
        PROGRESS_LEFT=$(( 50 - $PROGRESS_DONE ))
        DONE_PATTERN=$(/usr/bin/printf "%${PROGRESS_DONE}s") #  % number "done" of blanks
        LEFT_PATTERN=$(/usr/bin/printf "%${PROGRESS_LEFT}s") #  % number "left" of blanks

        /usr/bin/printf "
Processing: [${DONE_PATTERN// /#}${LEFT_PATTERN// /-}] ${PERCENT_COMPLETE}%%"  #  replace blanks with patterns
    else
        /usr/bin/printf "
Processing: [##################################################] 100%%
"
    fi        
}


function usage() {

    echo
    echo "Usage: ./${0##*/} -n "NAME" -f "FILE" -u "USER" -p "PASSWORD" -a "AUTHENTICATION" -h <computer_name> <computer_name>... OR <computer_id> <computer_id>..."
    echo
    echo -e "  -n | --name 		 Specify a static group name to create (required)"
    echo -e "  -f | --file 		 Specify a line-seperated file containing computer names or ids     (optional)"
    echo -e "  -u | --user 		 Specify a JSS user name with access to create computer groups      (required)"
    echo -e "  -p | --pass 		 Specify a JSS password for the user name specified above           (optional)"
    echo -e "  -a | --auth 		 Specify encoded JSS authorization credentials                      (optional)"
    echo -e " 			 If --auth is spcified then user and password are optional."                       
    echo -e "  <computer_name> 	 Computer names can be included as parameters on the command line (optional)"
    echo -e "  <computer_id> 	 Computer ids can be included as parameters on the command line     (optional)" 
    echo -e "  -h | --help 		 Display help"
}


# run main if called directly
if [[ "$BASH_SOURCE" == "$0" ]]; then
    main $@
fi

Forum|alt.badge.img+10
  • Contributor
  • 29 replies
  • January 29, 2020

Not super fancy nor the best code but this is what we use to add devices to a particular static group. It's not pretty but it gets the job done.

#! /bin/sh
######################################################################
############## Define Variable Block #################################
######################################################################
groupID="$4"
utilityName="$5"
jamfAuthKey="$6" //Basic Base64 encoded

jamfBaseURL="https://your.jamf.pro:8443"
allComputersFile="/path/to/localfile.txt"
filePath="/file/path/root"
loop="Continue"
oops1Dialog="SORRY! Either the Asset Tag entered: "
oops2Dialog=" was incorrect or that device is not currently being managed by Jamf Pro. Please check the device and try again."
addAnotherDialog="Would you like to add another device?"
mainDialog="Please Enter the Asset Tag of the Mac to add to the "$utilityName" Group (format: XX123456)"
appTitle="Company Name "$utilityName" Utility"
xmlContentType="Content-Type: application/xml"
computersAPI="/JSSResource/computers"
computerIDAPI="/JSSResource/computergroups/id/"
######################################################################
################# Define Functions Block #############################
######################################################################

file_Check() {
mkdir -p "$filePath"
if [ -f "$allComputersFile" ]
then
rm -rf "$allComputersFile"
fi
}

get_List() {
curl -X GET "$jamfBaseURL""$computersAPI" -H "$xmlContentType" -H "${jamfAuthKey}"  > "$allComputersFile"
}

add_Devices() {
assetTag=$(osascript <<EOT
tell app "System Events"
text returned of (display dialog "${mainDialog}" buttons {"Cancel", "Continue"} default button "Continue" default answer "" with title "${appTitle}")
end tell
EOT
)

if ! grep -i ${assetTag} "$allComputersFile"
then
osascript <<EOT
tell app "System Events"
display dialog "${oops1Dialog} ${assetTag} ${oops2Dialog}" buttons {"Done"} default button "Done" with title "${appTitle}"
end tell
EOT
else
echo "<computer_group><computer_additions><computer><name>$assetTag</name></computer></computer_additions></computer_group>" | curl -X PUT -d @- "$jamfBaseURL""$computerIDAPI""$groupID" -H "$xmlContentType" -H "$jamfAuthKey"
fi
}

device_Loop() {
loop=$(osascript <<EOT
tell app "System Events"
button returned of (display dialog "${addAnotherDialog}" buttons {"Cancel", "Continue", "Done" } default button "Done" with title "${appTitle}")
end tell
EOT
)
}
######################################################################
################# Script Run Block ###################################
######################################################################
while [ "${loop}" = "Continue" ]
do
file_Check
get_List
add_Devices
device_Loop
file_Check
done

Forum|alt.badge.img+14
  • Author
  • Valued Contributor
  • 375 replies
  • January 30, 2020

@jhuls The majority of our scopes are based on PreStage and auto-assigned or moved at purchasing. We have static groups that emulate those PreStages and I want buttons for our techs to add machines to these groups.

We try to leverage a Smart Groups 97% of the time but these static groups pick up their slack.


Forum|alt.badge.img+14
  • Author
  • Valued Contributor
  • 375 replies
  • January 30, 2020

@strayer Your script looks perfect for us. I have the URL defined on the actual script for Jamf Cloud, and the following attributes defined. That being said, the computer is not porting to a static group.

I am getting ": No such file or directory" when it is looking for the group id, which I grabbed from the JSS URL when I am in the static group. I believe that is the correct method?

Thanks for your help!
Jared


Forum|alt.badge.img+16
  • Valued Contributor
  • 182 replies
  • January 30, 2020

@jared_f Could be this. I put it in as a quote instead of as a script so the backtics areound result=$`curl "$fullURL" -u "$APIUser:$APIPass" -H "Content-Type: text/xml" -X PUT -d "$xml" didn't translate correctly
i've edited my comment above. let me know if that does it.


Forum|alt.badge.img+14
  • Author
  • Valued Contributor
  • 375 replies
  • January 30, 2020

@strayer That did the trick. Thanks for the script, it is perfect for our needs


sdagley
Forum|alt.badge.img+25
  • Jamf Heroes
  • 3532 replies
  • January 30, 2020

If you're trying to add a single computer to a Static Group, the <computer_additions> mechanism is much simpler:

#!/bin/sh

#API login info
apiuser="USERNAME"
apipass='PASSWORD'
jamfProURL="https://jamfproserver:8443"

ComputerName=$(/usr/sbin/scutil --get ComputerName)

GroupID="1234"
GroupName="Whatever the Group Name is"

apiURL="JSSResource/computergroups/id/${GroupID}"

#XML header stuff
xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"

apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"

curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}" 
    -H "Content-Type: text/xml" 
    -d "${xmlHeader}${apiData}" 
    -X PUT  > /dev/null

Forum|alt.badge.img+4
  • Contributor
  • 14 replies
  • March 18, 2020

After much testing, I found we can simplify the command. You don't need to include the xmlHeader, GroupID, or GroupName in the XML data you send.

This command works to PUT the computers with ID 777 and 888 into the $GroupID Group:

curl -u "$apiUsername":"$apiPassword" 
https://jss.url.com:8443/JSSResource/computergroups/id/$GroupID 
-H "Content-Type: text/xml" 
-X PUT -s 
-d "<computer_group><computer_additions>
<computer><id>777</id></computer>
<computer><id>888</id></computer>
</computer_additions></computer_group>"

sdagley
Forum|alt.badge.img+25
  • Jamf Heroes
  • 3532 replies
  • March 19, 2020

@tim.c.arnold Thanks for doing the research on trimming that command, but you might want to correct your statement

You don't need to include the xmlHeader, GroupID, or GroupName

as you do need the GroupID.


Forum|alt.badge.img+4
  • Contributor
  • 14 replies
  • March 19, 2020

Ah, yes... I meant - You don't need to supply the GroupID in the XML Data.

You do still need the GroupID in the URL. edited initial post to add clarity.


Forum|alt.badge.img+21
  • Honored Contributor
  • 970 replies
  • September 4, 2020

@mrheathjones whats the jamfAuthKey? You not using an username and password?


GGInquisitor
Forum|alt.badge.img+5
  • New Contributor
  • 10 replies
  • March 24, 2022
sdagley wrote:

If you're trying to add a single computer to a Static Group, the <computer_additions> mechanism is much simpler:

#!/bin/sh

#API login info
apiuser="USERNAME"
apipass='PASSWORD'
jamfProURL="https://jamfproserver:8443"

ComputerName=$(/usr/sbin/scutil --get ComputerName)

GroupID="1234"
GroupName="Whatever the Group Name is"

apiURL="JSSResource/computergroups/id/${GroupID}"

#XML header stuff
xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"

apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"

curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}" 
    -H "Content-Type: text/xml" 
    -d "${xmlHeader}${apiData}" 
    -X PUT  > /dev/null

I'm trying to use this and the command completes but I get bad request in the return when removing the > /dev/null and the computer doesn't post to the group.  Could you take a look and see what I'm doing wrong?  I have both the serial and computer group in my script but currently have it running off the serial number to post.  I get the same return either way.  Here is the return when running from terminal. 

+ apiuser=api_user + apipass='XXXX' + jamfProURL=https://mdm.company.org:8443 ++ hostname + ComputerName=localcomputername ++ ioreg -rd1 -c IOPlatformExpertDevice ++ awk '-F"' '/IOPlatformSerialNumber/{print $4 tail}' + ComputerSerial=localcomputerserial + GroupID=1234 + GroupName=APITest + apiURL=JSSResource/computergroups/id/1234 + xmlHeader='<?xml version=1.0 encoding=UTF-8?>' + apiData=' <computer_group> <id>1234</id> <name>APITest</name> <computer_additions> <computer> <serial_number>localcomputerserial</serial_number> </computer> </computer_additions> </computer_group>' + curl -sSkiu 'api_user:XXXX' https://mdm.company.org:8443/JSSResource/computergroups/id/1234 -H 'Content-Type: text/xml' -d '<?xml version=1.0 encoding=UTF-8?> <computer_group> <id>1234</id> <name>APITest</name> <computer_additions> <computer> <serial_number>localcomputerserial</serial_number> </computer> </computer_additions> </computer_group>' -X PUT HTTP/2 400 date: Thu, 24 Mar 2022 15:56:29 GMT content-type: text/html;charset=UTF-8 content-length: 400 set-cookie: LongStringOfCharacters; Expires=Thu, 31 Mar 2022 15:56:28 GMT; Path=/ set-cookie: LongStringOfCharacters; Expires=Thu, 31 Mar 2022 15:56:28 GMT; Path=/; SameSite=None; Secure x-frame-options: DENY cache-control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0 strict-transport-security: max-age=31536000;includeSubDomains x-xss-protection: 1; mode=block accept-ranges: bytes server: Jamf Cloud Node vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept <html> <head> <title>Status page</title> </head> <body style="font-family: sans-serif;"> <p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Bad Request</p> <p>Error in XML file</p> <p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">here</a>.<br> Please continue your visit at our <a href="/">home page</a>. </p> </body> </html>

Thanks!


GGInquisitor
Forum|alt.badge.img+5
  • New Contributor
  • 10 replies
  • March 24, 2022
GGInquisitor wrote:

I'm trying to use this and the command completes but I get bad request in the return when removing the > /dev/null and the computer doesn't post to the group.  Could you take a look and see what I'm doing wrong?  I have both the serial and computer group in my script but currently have it running off the serial number to post.  I get the same return either way.  Here is the return when running from terminal. 

+ apiuser=api_user + apipass='XXXX' + jamfProURL=https://mdm.company.org:8443 ++ hostname + ComputerName=localcomputername ++ ioreg -rd1 -c IOPlatformExpertDevice ++ awk '-F"' '/IOPlatformSerialNumber/{print $4 tail}' + ComputerSerial=localcomputerserial + GroupID=1234 + GroupName=APITest + apiURL=JSSResource/computergroups/id/1234 + xmlHeader='<?xml version=1.0 encoding=UTF-8?>' + apiData=' <computer_group> <id>1234</id> <name>APITest</name> <computer_additions> <computer> <serial_number>localcomputerserial</serial_number> </computer> </computer_additions> </computer_group>' + curl -sSkiu 'api_user:XXXX' https://mdm.company.org:8443/JSSResource/computergroups/id/1234 -H 'Content-Type: text/xml' -d '<?xml version=1.0 encoding=UTF-8?> <computer_group> <id>1234</id> <name>APITest</name> <computer_additions> <computer> <serial_number>localcomputerserial</serial_number> </computer> </computer_additions> </computer_group>' -X PUT HTTP/2 400 date: Thu, 24 Mar 2022 15:56:29 GMT content-type: text/html;charset=UTF-8 content-length: 400 set-cookie: LongStringOfCharacters; Expires=Thu, 31 Mar 2022 15:56:28 GMT; Path=/ set-cookie: LongStringOfCharacters; Expires=Thu, 31 Mar 2022 15:56:28 GMT; Path=/; SameSite=None; Secure x-frame-options: DENY cache-control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0 strict-transport-security: max-age=31536000;includeSubDomains x-xss-protection: 1; mode=block accept-ranges: bytes server: Jamf Cloud Node vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept <html> <head> <title>Status page</title> </head> <body style="font-family: sans-serif;"> <p style="font-size: 1.2em;font-weight: bold;margin: 1em 0px;">Bad Request</p> <p>Error in XML file</p> <p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1">here</a>.<br> Please continue your visit at our <a href="/">home page</a>. </p> </body> </html>

Thanks!


Disregard.  After reading this thread a little more thoroughly and comparing some other scripts, it seems that removing the {xmlHeader} from -d "${xmlHeader}{apiData}" solved the issue.


sdagley
Forum|alt.badge.img+25
  • Jamf Heroes
  • 3532 replies
  • March 24, 2022
GGInquisitor wrote:

Disregard.  After reading this thread a little more thoroughly and comparing some other scripts, it seems that removing the {xmlHeader} from -d "${xmlHeader}{apiData}" solved the issue.


@GGInquisitor I would strongly advise you to look at @dlondon 's updated script which uses Bearer Token Auth which will be required for API calls later this year: https://community.jamf.com/t5/jamf-pro/bearer-token-api-and-adding-computer-to-static-group/m-p/261400/highlight/true#M240985


Forum|alt.badge.img+3
  • New Contributor
  • 6 replies
  • July 5, 2023
sdagley wrote:

If you're trying to add a single computer to a Static Group, the <computer_additions> mechanism is much simpler:

#!/bin/sh

#API login info
apiuser="USERNAME"
apipass='PASSWORD'
jamfProURL="https://jamfproserver:8443"

ComputerName=$(/usr/sbin/scutil --get ComputerName)

GroupID="1234"
GroupName="Whatever the Group Name is"

apiURL="JSSResource/computergroups/id/${GroupID}"

#XML header stuff
xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"

apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"

curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}" 
    -H "Content-Type: text/xml" 
    -d "${xmlHeader}${apiData}" 
    -X PUT  > /dev/null

Hello , 

I try to use this commands but every time I have error like 

 -X: command not found

 -d: command not found

Do you have any idea ? 


sdagley
Forum|alt.badge.img+25
  • Jamf Heroes
  • 3532 replies
  • July 5, 2023
kdpk wrote:

Hello , 

I try to use this commands but every time I have error like 

 -X: command not found

 -d: command not found

Do you have any idea ? 


@kdpk Do not use the scripts in this thread. You should refer to @dlondon 's updated version which uses Bearer Token Auth (and corrects the formatting of the curl command to include the line continuation characters missing in the script you tried): https://community.jamf.com/t5/jamf-pro/bearer-token-api-and-adding-computer-to-static-group/m-p/2614...


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings