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.

1#!/bin/sh
2
3#API login info
4apiuser="apiaccount"
5apipass='apiaccountpassword'
6jamfProURL="https://myjamfinstance.jamfcloud.com"
7
8ComputerName=$(hostname)
9
10#Group to update
11GroupID="$4"
12apiURL="JSSResource/computergroups/id/${GroupID}"
13
14#XML header stuff
15xmlHeader="<?xml version="1.0" encoding="UTF-8" standalone="no"?>"
16
17apiData="<computer_group><id>${GroupID}</id><name>Whatever the GroupName Is</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"
18
19curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}"
20 -H "Content-Type: text/xml"
21 -d "${xmlHeader}${apiData}"
22 -X PUT > /dev/null

18 replies

Forum|alt.badge.img+14
  • Valued Contributor
  • 345 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.

1#! /bin/bash
2
3jamfproURL="https://yoururlhere.jamfcloud.com"
4
5default_group="856"
6computer_name="$2"
7current_user="$3"
8silent="$8"
9
10
11
12if [ -z $4 ]
13 then
14 groupid="$default_group"
15 else
16 groupid="$4"
17fi
18
19if [ -z $5 ]
20 then
21 action="additions"
22 else
23 action="$5"
24fi
25
26if [ -z $6 ]
27 then
28 APIUser=$(/usr/bin/osascript<<END
29 tell application "System Events"
30 activate
31 set the answer to text returned of (display dialog "Please enter your Jamf Username:" default answer "" buttons {"Continue"} default button 1)
32 end tell
33 END)
34 else
35 APIUser="$6"
36fi
37
38if [ -z $7 ]
39 then
40 APIPass=$(/usr/bin/osascript<<END
41 tell application "System Events"
42 activate
43 set the answer to text returned of (display dialog "Please enter your Jamf Password:" default answer "" with hidden answer buttons {"Continue"} default button 1)
44 end tell
45 END)
46 else
47 APIPass="$7"
48fi
49
50xml="<computer_group><computer_${action}><computer><name>$computer_name</name></computer></computer_${action}></computer_group>"
51
52fullURL="${jamfproURL}/JSSResource/computergroups/id/${groupid}"
53
54echo "Created XML"
55echo $xml
56
57echo "Jamf API URL"
58echo $fullURL
59
60
61result=$`curl "$fullURL" -u "$APIUser:$APIPass" -H "Content-Type: text/xml" -X PUT -d "$xml"`
62
63echo "result"
64echo "$result"
65
66if [ -z $silent ] ; then
67 if [[ "$result" == *"<p>The request requires user authentication</p>"* ]] ; then
68 echo "Showing Fail message"
69 /usr/bin/osascript -e 'tell app "System Events" to display dialog "Failed to update Static Group. Please check your network connection and try again."'
70 else
71 echo "Showing success message"
72 dialog="${action} for the Static Group probably successful."
73 cmd="Tell app "System Events" to display dialog "$dialog""
74 /usr/bin/osascript -e "$cmd"
75 fi
76else
77 echo "running silent No user notifications"
78fi
79exit 0

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

This may be more than you bargained:

1#!/bin/bash
2
3
4# While static groups within JAMF PRO are typically thought of as
5# less-uesful than their more dynamic counterparts known as smart
6# groups, I have found they still serve a critical role. This is
7# especially so for those who extract the most from JAMF PRO via a
8# series of API scripts. Those API script often return a list of
9# computer IDs or names. But those lists usually need to be acted
10# upon in some way. Being able to easily create a static group within
11# JAMF PRO can make that happen.
12
13# That is why I wrote this script. It allows for the quick creation
14# and/or re-population of a static group based on a string of computer
15# IDs or names
16
17# Author: Andrew Thomson
18# Date: 02-10-2017
19# GitHub: https://github.com/thomsontown
20# Version: 1.02 (12-11-2019)
21
22
23# uncomment to override variables
24# JSS_USER=""
25# JSS_PASSWORD=""
26# JSS_AUTH=""
27
28
29function addGroupMembers() {
30
31 local GROUP_ID="$1"
32 local GROUP_NAME="$2"
33 local COUNT=1
34
35 # create opening xml for replacing members of the static group
36 XML_COMPUTER_TEMPLATE="<computer_group><id>$GROUP_ID</id><name>$GROUP_NAME</name><computers>"
37
38 # enumerate computers to re-populate static group
39 for COMPUTER in ${COMPUTERS[@]}; do
40
41 progressBar "${#COMPUTERS[@]}" "$((COUNT++))"
42
43 # derermine if computer id (integer) or name (alpha) was provided
44 if isInteger "$COMPUTER"; then
45 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)
46
47 COMPUTER_NAME=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/name/text()" 2> /dev/null)
48 COMPUTER_SN=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/serial_number/text()" 2> /dev/null)
49 COMPUTER_ID="$COMPUTER"
50 else
51 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)
52
53 COMPUTER_ID=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/id/text()" 2> /dev/null)
54 COMPUTER_SN=$(echo $XML_COMPUTER | /usr/bin/xpath "/computer/general/serial_number/text()" 2> /dev/null)
55 COMPUTER_NAME="$COMPUTER"
56 COMPUTER_NAME=$(encodeUrl "$COMPUTER_NAME")
57 fi
58
59 # verify computer details were found
60 if [ -z "$COMPUTER_SN" ] || [ -z "$COMPUTER_ID" ] || [ -z "$COMPUTER_NAME" ]; then
61 echo -e "
62ERROR: Unable to retrieve info for computer [$COMPUTER]." >&2
63 continue
64 fi
65
66 # insert xml requied for each computer be a member of the static group
67 XML_COMPUTER_TEMPLATE+="<computer><id>$COMPUTER_ID</id><name>$COMPUTER_NAME</name><serial_number>$COMPUTER_SN</serial_number></computer>"
68 done
69
70 # close out the xml for re-populating members of the static group
71 XML_COMPUTER_TEMPLATE+="</computers></computer_group>"
72
73 # verify xml formatting before submitting
74 if ! XML_COMPUTER_TEMPLATE=$(echo $XML_COMPUTER_TEMPLATE | /usr/bin/xmllint --format -); then
75 echo "ERROR: Imporperly formatted data structure found." >&2
76 return $LINENO
77 fi
78
79 # upload xml to re-populate the computers in the static group
80 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)
81 if [ "$HTTP_CODE" -ne "201" ]; then
82 echo "ERROR: Unable to replace computers in static group." >&2
83 return $LINENO
84 fi
85}
86
87
88function createStaticGroup() {
89
90 # $1 = Name of static group to create. (My Amazing Group)
91 local GROUP_NAME="$1"
92
93 # query jss for existing group name to get id
94 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)
95
96 # create new group if no existing one can be found
97 if [ -z "$GROUP_ID" ]; then
98
99 # minimal xml required to create static group
100 XML_GROUP_TEMPLATE="<computer_group><id>0</id><name>$GROUP_NAME</name><is_smart>false</is_smart></computer_group>"
101
102 # upload xml to create static group
103 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)
104
105 # display error or return group id
106 if [ -z "$GROUP_ID" ]; then
107 echo "ERROR: Unable to create JSS computer group." >&2
108 return $LINENO
109 fi
110 fi
111
112 echo "$GROUP_ID"
113 return 0
114}
115
116
117function encodeBasicAuthorization() {
118
119 # $1 = User name for JSS query. (jsmith)
120 # $2 = Password for JSS query. (itisasecret)
121 local USERNAME="$1"
122 local PASSWORD="$2"
123
124 if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ]; then
125 writeLog "ERROR: Missing parameter(s)." >&2
126 return $LINENO
127 fi
128
129 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
130 writeLog "ERROR: Unable to encode authorization credentials [$?]." >&2
131 return $LINENO
132 else
133 echo "$AUTHORIZATION"
134 return 0
135 fi
136}
137
138
139function encodeUrl() {
140
141 # $1 = Universal Resource Locator to be encoded. (https://www.company.com/some/path/index.htm)
142 local URL="$1"
143 local PREFIX=$(echo $URL | /usr/bin/grep -Eoi "^(afp|file|ftp|http|https|smb)://" 2> /dev/null)
144 local LENGTH=${#PREFIX}
145 local SUFFIX=${URL:$LENGTH}
146 local ENCODED=""
147
148 if [ -z "$SUFFIX" ]; then
149 echo "ERROR: Specified URL is incomplete."
150 return $LINENO
151 fi
152
153 while [ -n "$SUFFIX" ]; do
154 TAIL=${SUFFIX#?}
155 HEAD=${SUFFIX%$TAIL}
156 case $HEAD in
157 [-._~0-9A-Za-z/:]) ENCODED+=$(/usr/bin/printf %c "$HEAD");; # encoding not required
158 *) ENCODED+=$(/usr/bin/printf %%%02x "'$HEAD") # encoding required
159 esac
160 SUFFIX=$TAIL
161 done
162 echo "${PREFIX}$ENCODED"
163}
164
165
166function initJamf() {
167
168 # verify encoded authorization
169 if [ -z "$JSS_AUTH" ]; then
170
171 # verify username and password for jss
172 if [ -n "$JSS_USER" ] || [ -z "$JSS_PASSWORD" ]; then
173 echo "ERROR: A username or password to access to the JSS was not specified." >&2
174 return $LINENO
175 fi
176
177 if declare -f encodeBasicAuthorization &> /dev/null; then
178 if ! JSS_AUTH=$(encodeBasicAuthorization "$JSS_USER" "$JSS_PASSWORD"); then
179 return $LINENO
180 fi
181 else
182 echo "ERROR: Unable to encode username and password to access the JSS." >&2
183 return $LINENO
184 fi
185 fi
186
187 # get jss url
188 JSS_URL=$(/usr/bin/defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url 2> /dev/null)
189 if [ -z "JSS_URL" ]; then
190 echo "ERROR: A a valid URL to the JSS was not specified [JSS_URL]." >&2
191 return $LINENO
192 fi
193
194 # verify jss is available
195 JSS_CONNECTION=$(/usr/bin/curl --connect-timeout 10 -H "Authorization: Basic $JSS_AUTH" -sw "%{http_code}" ${JSS_URL%/}/JSSCheckConnection -o /dev/null)
196 if [ $JSS_CONNECTION -ne 200 ] && [ $JSS_CONNECTION -ne 403 ] ; then
197 echo "ERROR: Unable to connect to JSS [$JSS_URL]." >&2
198 return $LINENO
199 fi
200}
201
202
203function isInteger() {
204
205 return $([ "$@" -eq "$@" ] 2> /dev/null)
206}
207
208
209function main() {
210
211 while [ -n "$1" ]; do
212 case $1 in
213 -n | --name ) shift;GROUP_NAME="$1" ;;
214 -f | --file ) shift;FILE_PATH="$1" ;;
215 -u | --user ) shift;JSS_USER="$1" ;;
216 -p | --pass ) shift;JSS_PASSWORD="$1" ;;
217 -a | --auth ) shift;JSS_AUTH="$1" ;;
218 -h | --help ) shift;usage ;;
219 * ) COMPUTERS+=( "$1" )
220 esac
221 shift
222 done
223
224 # load common source variables
225 if [ -f ~/.bash_source ]; then
226 source ~/.bash_source
227 fi
228
229 # prompt for password if missing
230 if [ -z "$JSS_AUTH" ] && [ -n "$JSS_USER" ] && [ -z "$JSS_PASSWORD" ]; then
231 echo "Please enter JSS password for account [$JSS_USER]: "
232 read -s JSS_PASSWORD
233 fi
234
235 # verify user and password or encoded authorization
236 if [ -z "$JSS_USER" ] || [ -z "$JSS_PASSWORD" ] && [ -z "$JSS_AUTH" ]; then
237 echo "ERROR: A JSS user name and password are required if no encoded authorization is provided." >&2
238 usage
239 exit $LINENO
240 fi
241
242 # verify group name was specified
243 if [ -z "$GROUP_NAME" ]; then
244 echo "Please enter a name for the group you wish to create/populate: "
245 read GROUP_NAME
246 if [ -z "$GROUP_NAME" ]; then
247 echo "ERROR: No group name was specified." >&2
248 exit $LINENO
249 fi
250 fi
251
252 # verify member source
253 if [ ! -r "$FILE_PATH" ] && [ "${#COMPUTERS[@]}" -eq "0" ]; then
254 echo "Please drag-n-drop or enter the path to a line-seperated file containing computer names or IDs: "
255 read FILE_PATH
256 if [ ! -r "$FILE_PATH" ]; then
257 echo "ERROR: The path to the specified readable file cound not be found [$FILE_PATH]." >&2
258 exit $LINENO
259 fi
260 fi
261
262 # populate array with computer names from file
263 if [ -r "$FILE_PATH" ]; then
264 while IFS= read -r COMPUTER; do
265 COMPUTERS+=($COMPUTER)
266 done < "$FILE_PATH"
267 fi
268
269 # obsure password for debug
270 for ((i=1; i<${#JSS_PASSWORD}; i++)); do
271 JSS_OBSURED+="◦"
272 done
273
274 # display parameters for debug
275 if $DEBUG; then
276 echo -e "NAME: $GROUP_NAME
277FILE: $FILE_PATH
278USER: $JSS_USER
279PASS: $JSS_OBSURED
280AUTH: $JSS_AUTH
281COMPUTERS: ${COMPUTERS[@]}"
282 fi
283
284 # initialize and verify jamf connection
285 if ! initJamf; then exit $LINENO; fi
286
287 # create/get computer group id
288 if ! GROUP_ID=$(createStaticGroup "$GROUP_NAME"); then exit $LINENO; fi
289
290 # add each computer to group
291 addGroupMembers "$GROUP_ID" "$GROUP_NAME"
292
293 # play sound to signal completion
294 playSound
295}
296
297
298function playSound() {
299
300 # $1 = Path to sound file. (/System/Library/Sounds/Glass.aiff)
301 local SOUND_FILE_PATH="$1"
302
303 if [ -z "$SOUND_FILE_PATH" ] && [ -f "/System/Library/Sounds/Glass.aiff" ]; then
304 local SOUND_FILE_PATH="/System/Library/Sounds/Glass.aiff"
305 fi
306
307 if [ -f "$SOUND_FILE_PATH" ]; then
308 /usr/bin/afplay "$SOUND_FILE_PATH" &> /dev/null
309 fi
310}
311
312
313function progressBar() {
314
315 # $1 = Maximum count of progress. (75)
316 # $2 = Current count of progress. (10)
317 local MAX="$1"
318 local COUNT="$2"
319
320 # verify required parameters
321 if [ -z "$MAX" ] || [ -z "$COUNT" ]; then
322 echo "ERROR: Missing parameter."
323 return $LINENO
324 fi
325
326 # verify parameters are integers
327 if [ "$MAX" -ne "$MAX" ] 2> /dev/null || [ "$COUNT" -ne "$COUNT" ] 2> /dev/null; then
328 echo "ERROR: Integer expression expected." >&2
329 return $LINENO
330 fi
331
332 if [ "$COUNT" -lt "$MAX" ]; then
333 # display progress
334 PERCENT_COMPLETE=$(echo "(100/$MAX)*$COUNT" | /usr/bin/bc -l | /usr/bin/awk '{print int($1+0.5)}')
335 PROGRESS_DONE=$(echo "$PERCENT_COMPLETE/2" | /usr/bin/bc -l | /usr/bin/awk '{print int($1+0.5)}')
336 PROGRESS_LEFT=$(( 50 - $PROGRESS_DONE ))
337 DONE_PATTERN=$(/usr/bin/printf "%${PROGRESS_DONE}s") # % number "done" of blanks
338 LEFT_PATTERN=$(/usr/bin/printf "%${PROGRESS_LEFT}s") # % number "left" of blanks
339
340 /usr/bin/printf "
341Processing: [${DONE_PATTERN// /#}${LEFT_PATTERN// /-}] ${PERCENT_COMPLETE}%%" # replace blanks with patterns
342 else
343 /usr/bin/printf "
344Processing: [##################################################] 100%%
345"
346 fi
347}
348
349
350function usage() {
351
352 echo
353 echo "Usage: ./${0##*/} -n "NAME" -f "FILE" -u "USER" -p "PASSWORD" -a "AUTHENTICATION" -h <computer_name> <computer_name>... OR <computer_id> <computer_id>..."
354 echo
355 echo -e " -n | --name Specify a static group name to create (required)"
356 echo -e " -f | --file Specify a line-seperated file containing computer names or ids (optional)"
357 echo -e " -u | --user Specify a JSS user name with access to create computer groups (required)"
358 echo -e " -p | --pass Specify a JSS password for the user name specified above (optional)"
359 echo -e " -a | --auth Specify encoded JSS authorization credentials (optional)"
360 echo -e " If --auth is spcified then user and password are optional."
361 echo -e " <computer_name> Computer names can be included as parameters on the command line (optional)"
362 echo -e " <computer_id> Computer ids can be included as parameters on the command line (optional)"
363 echo -e " -h | --help Display help"
364}
365
366
367# run main if called directly
368if [[ "$BASH_SOURCE" == "$0" ]]; then
369 main $@
370fi

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.

1#! /bin/sh
2######################################################################
3############## Define Variable Block #################################
4######################################################################
5groupID="$4"
6utilityName="$5"
7jamfAuthKey="$6" //Basic Base64 encoded
8
9jamfBaseURL="https://your.jamf.pro:8443"
10allComputersFile="/path/to/localfile.txt"
11filePath="/file/path/root"
12loop="Continue"
13oops1Dialog="SORRY! Either the Asset Tag entered: "
14oops2Dialog=" was incorrect or that device is not currently being managed by Jamf Pro. Please check the device and try again."
15addAnotherDialog="Would you like to add another device?"
16mainDialog="Please Enter the Asset Tag of the Mac to add to the "$utilityName" Group (format: XX123456)"
17appTitle="Company Name "$utilityName" Utility"
18xmlContentType="Content-Type: application/xml"
19computersAPI="/JSSResource/computers"
20computerIDAPI="/JSSResource/computergroups/id/"
21######################################################################
22################# Define Functions Block #############################
23######################################################################
24
25file_Check() {
26mkdir -p "$filePath"
27if [ -f "$allComputersFile" ]
28then
29rm -rf "$allComputersFile"
30fi
31}
32
33get_List() {
34curl -X GET "$jamfBaseURL""$computersAPI" -H "$xmlContentType" -H "${jamfAuthKey}" > "$allComputersFile"
35}
36
37add_Devices() {
38assetTag=$(osascript <<EOT
39tell app "System Events"
40text returned of (display dialog "${mainDialog}" buttons {"Cancel", "Continue"} default button "Continue" default answer "" with title "${appTitle}")
41end tell
42EOT
43)
44
45if ! grep -i ${assetTag} "$allComputersFile"
46then
47osascript <<EOT
48tell app "System Events"
49display dialog "${oops1Dialog} ${assetTag} ${oops2Dialog}" buttons {"Done"} default button "Done" with title "${appTitle}"
50end tell
51EOT
52else
53echo "<computer_group><computer_additions><computer><name>$assetTag</name></computer></computer_additions></computer_group>" | curl -X PUT -d @- "$jamfBaseURL""$computerIDAPI""$groupID" -H "$xmlContentType" -H "$jamfAuthKey"
54fi
55}
56
57device_Loop() {
58loop=$(osascript <<EOT
59tell app "System Events"
60button returned of (display dialog "${addAnotherDialog}" buttons {"Cancel", "Continue", "Done" } default button "Done" with title "${appTitle}")
61end tell
62EOT
63)
64}
65######################################################################
66################# Script Run Block ###################################
67######################################################################
68while [ "${loop}" = "Continue" ]
69do
70file_Check
71get_List
72add_Devices
73device_Loop
74file_Check
75done

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
  • 3566 replies
  • January 30, 2020

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

1#!/bin/sh
2
3#API login info
4apiuser="USERNAME"
5apipass='PASSWORD'
6jamfProURL="https://jamfproserver:8443"
7
8ComputerName=$(/usr/sbin/scutil --get ComputerName)
9
10GroupID="1234"
11GroupName="Whatever the Group Name is"
12
13apiURL="JSSResource/computergroups/id/${GroupID}"
14
15#XML header stuff
16xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"
17
18apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"
19
20curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}"
21 -H "Content-Type: text/xml"
22 -d "${xmlHeader}${apiData}"
23 -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:

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

sdagley
Forum|alt.badge.img+25
  • Jamf Heroes
  • 3566 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:

1#!/bin/sh
2
3#API login info
4apiuser="USERNAME"
5apipass='PASSWORD'
6jamfProURL="https://jamfproserver:8443"
7
8ComputerName=$(/usr/sbin/scutil --get ComputerName)
9
10GroupID="1234"
11GroupName="Whatever the Group Name is"
12
13apiURL="JSSResource/computergroups/id/${GroupID}"
14
15#XML header stuff
16xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"
17
18apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"
19
20curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}"
21 -H "Content-Type: text/xml"
22 -d "${xmlHeader}${apiData}"
23 -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
  • 3566 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:

1#!/bin/sh
2
3#API login info
4apiuser="USERNAME"
5apipass='PASSWORD'
6jamfProURL="https://jamfproserver:8443"
7
8ComputerName=$(/usr/sbin/scutil --get ComputerName)
9
10GroupID="1234"
11GroupName="Whatever the Group Name is"
12
13apiURL="JSSResource/computergroups/id/${GroupID}"
14
15#XML header stuff
16xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"
17
18apiData="<computer_group><id>${GroupID}</id><name>${GroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"
19
20curl -sSkiu ${apiuser}:${apipass} "${jamfProURL}/${apiURL}"
21 -H "Content-Type: text/xml"
22 -d "${xmlHeader}${apiData}"
23 -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
  • 3566 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...


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