Automated way to change a site

stevevalle
Contributor III

Hi all

I’m not sure if this is at all possible, but I am looking for an automated solution to move computers from one site to another.

What I am hoping to achieve is to assign all new computers to “Site 1”, then once initial setup policies have run, the computer is automatically moved to “Site 2”.

Any help is much appreciated!

1 ACCEPTED SOLUTION

davidacland
Honored Contributor II

It would certainly be possible. The REST API will let you upload xml that would change the values.

The xml you would upload will look like this:

<computer>
  <general>
    <site>
      <id>1</id>
      <name>Example Site</name>
    </site>
  </general>
</computer>

and the script to do the upload would look like:

#!/bin/sh

apiURL="https://your.jss.url"
apiUser="apiuser"
apiPass="apipassword"

# Get serial number of Mac so it can be identified in the JSS
#serial=$(system_profiler SPHardwareDataType | grep 'Serial Number (system)' | awk '{print $NF}')
serial="MacSerialNumber"

# Upload the xml file
curl -sfku $apiUser:$apiPass $apiURL/JSSResource/computers/serialnumber/$serial/subset/general -T /private/tmp/path.to.xml -X PUT

exit 0

Add the script to a policy and it will change the site value.

NOTE: I've used variations of this script but in this case these are just examples and should be tested and adapted for your own use :)

Hope this helps.

View solution in original post

18 REPLIES 18

davidacland
Honored Contributor II

It would certainly be possible. The REST API will let you upload xml that would change the values.

The xml you would upload will look like this:

<computer>
  <general>
    <site>
      <id>1</id>
      <name>Example Site</name>
    </site>
  </general>
</computer>

and the script to do the upload would look like:

#!/bin/sh

apiURL="https://your.jss.url"
apiUser="apiuser"
apiPass="apipassword"

# Get serial number of Mac so it can be identified in the JSS
#serial=$(system_profiler SPHardwareDataType | grep 'Serial Number (system)' | awk '{print $NF}')
serial="MacSerialNumber"

# Upload the xml file
curl -sfku $apiUser:$apiPass $apiURL/JSSResource/computers/serialnumber/$serial/subset/general -T /private/tmp/path.to.xml -X PUT

exit 0

Add the script to a policy and it will change the site value.

NOTE: I've used variations of this script but in this case these are just examples and should be tested and adapted for your own use :)

Hope this helps.

stevevalle
Contributor III

Thanks for the info @davidacland. I haven't used the API before, so I look forward to testing this out!

szultzie
Contributor II

So i have been trying to get this to work this morning, but for some reason it is not workin.

I have a scrip.sh and an site.xml file created, i put in my full admin rights username and password and nothing happens.

Should the curl command be giving any typ of output once completed? I also ran a recon after it to see if thats is needed.

I am doing this via terminal, haven't even tried to bring it into Self Service Policy.
Any help would be appreciated

Here is the script i am running

#!/bin/sh

set -x

apiURL=https://myURL.jamfcloud.com
apiUser=myadminaccount
apiPass=mypassword

# Get serial number of Mac so it can be identified in the JSS
serial=$(system_profiler SPHardwareDataType | grep 'Serial Number (system)' | awk '{print $NF}')
#serial="MacSerialNumber"

# Upload the xml file
curl -sfku $apiUser:$apiPass $apiURL/JSSResource/computers/serialnumber/$serial/subset/general -T /mypathto/XML/file.xml -X PUT


exit 0

below is my XML file

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<computer>
  <general>
    <site>
    <id>4</id>
    <name>Departments</name>
  </site>
  </general>
</computer>

-Peter

mm2270
Legendary Contributor III

@szultzie Does your XML actually have the backslashes in front of the " marks like shown, or was that just a copy/paste issue? Because with those backslashes in there, the XML would not be valid.

Here's a way you can check your XML file's validity. There's a few different tools that will do this, but xmllint is the one I use

xmllint --valid /path/to/file.xml

It will show you where the errors in the xml are. Using your example, all the backslashes are flagged as problems. They should not be there.

szultzie
Contributor II

Here is a screenshot of the actualy XML file
66cf31d5acb64f838554a22eec5c7858

szultzie
Contributor II

ok so its working now, i recreated the xml file using TextWrangler and the scrip file. And confirmed my username and password and it works with my . full admin, now trying to figure out what minimal access i would need to create a user with rights just to do this

Thanks for your help.

szultzie
Contributor II

ok so in case somebody else needs the info, i worked it out with some fancy guess and check =)

so the User will need:
Access Level = Full Access
Privilege set = Custom

Under the Privileges Tab - Jamf Pro Server Objects

Computers = Read and Update
GSX Connection Keystores = Read and Update
Push Certificates = Read and Update
Users = Read and Update

Everything else is NOT needed.

This works for me, some of them got checked automatically and unchecking them just put them back on, so they are tied to each other somehow. But that is minimal access as far as I can tell.

-Peter

mhasman
Valued Contributor

Script not working for me, I suppose the issue is with my .xml file. Checking the xml validity, I get an error:

3: validity error : Validation failed: no DTD found !

<computer>

^

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<computer>

<general>

<site>

<id>##</id>

<name>*</name>

</site>

</general>

</computer>

BBEdit shows no error in the file...

Any advice and suggestions will be greatly appreciated!

mm2270
Legendary Contributor III

@mhasman I've often found when creating xml files from scratch that it's best to not include the actual xml header in the file. As long as you name your file with a .xml extension and the structure of the file is in valid xml format, it should work. So for example, I took what you posted above, removed blank lines, changed the ## and * to something valid just as part of the test and it looks like this when open in TextWrangler

<computer>
<general>
<site>
<id>1</id>
<name>Site 1</name>
</site>
</general>
</computer>

If I run xmllint --format against that, it validates just fine. I would try something like that. Leave out the header and see if it works.

Note that if you really want the xml header in the file and also want it formatted to show tree indenting, you can do something this, changing the appropriate paths. The resulting file will have the indenting and header included in it.

xmllint --format /path/to/file.xml > /path/to/formatted.xml

mhasman
Valued Contributor

@mm2270 Thank you!

I just did what you recommended - deleted xml header, created another xml file via "xmllint --format" - no luck.

Both files shows an error

"Validation failed: no DTD found !

<computer>

^

mm2270
Legendary Contributor III

Does your actual xml file have an asterisk in it like you posted before, or was that just that you removed relevant data? Because certain characters can't be included in xml files without being encoded first. I believe an asterisk, and maybe things like the pound/hash sign # might mess up an xml.

Edit: Ok, never mind. I just ran a quick test and both an * and # were included in strings and neither caused invalidation of the file. It would of course fail to update the computer record via the API, but I'm not sure if the error you're seeing is when trying to do the update back to the server or just validating the xml file locally.

mhasman
Valued Contributor

No, I just replaced actual site id with #, site name with *

mhasman
Valued Contributor

Seems to be working! :) All my fault...

The issue was that I put apiURL=""https://your.jss.url/" - with "/" on the end.

So, "curl -sfku ..." was running with doble "//" affront of "...JSSResource/".

That "set -x" part help a lot!

Mike, thank you very much!

szultzie
Contributor II

Hi All,

We just upgraded to Jamf Pro 10.9 and this piece seemed to break. I can run the curl command manual ont he client machine and it sets the site fine, but using it thru a policy (self service or otherwise) doesn't set it, and no errors.

It was working great until the upgrade.
Wonder if anybody is seeing this. I put in a ticket to Jamf as well, to see what they can do.

-Peter

leoos
New Contributor

Did you get a solution to this @szultzie ? I have just run into the same problem and was hitting my head off a brick wall until I came across your post and now feel like I was not going mad

szultzie
Contributor II

its working for us. Cant remember what i had to do to get it to work anymore. It may have been just a bad password. Let me know if you need my code.

craigo
New Contributor III

Hi All,

I was mucking around with this and came up with another way to do it without the need for the xml file if anyone else is interested. I use a plist for the URL and API token for authentication (which I picked up from someone else on this forum whom I can't remember; sorry to them and thanks for the awesome idea) or the script will prompt for them if they are not present, or you can hard code them if you need to fully automate the process in JSS, just be aware of the risks of hardcoding credentials in your scripts.
I only have a hand full of computers to move so I run this manually as required and that's how it's currently configured. You can modify the script by commenting out and uncommenting lines to suite, or you could tweak it to take a list of computers if you wanted.
WARNING: I'm no scripting or API guru, I'm just learning this as I go along like most of us here so please double check the code before you use it, and run it at your own risk ;)

#!/bin/bash

# To obtain the API token, run the following in terminal, replacing JamfUsername and JamfPassword with your Jamf username and password
# printf "JamfUsername:JamfPassword" | iconv -t ISO-8859-1 | base64 -i -


siteID=SiteNumberGoesHere
siteName="SiteNameGoesHere"
plistFile="jamfpro-info"


/bin/echo "Moving Mac to site $siteName"
# Was the machine serial number fed in?
if [ ! "$1" ]; then
    read -p "Enter Mac Serial Number: " deviceSN
    # Or get the serial number of the machine it's running on
    #deviceSN=$(system_profiler SPHardwareDataType | grep 'Serial Number (system)' | awk '{print $NF}')
else
    deviceSN="$1"
fi

# If the $plistFile.plist file is available read in the relevant information.
if [[ -f "$HOME/Library/Preferences/$plistFile.plist" ]]; then
    /bin/echo
    if [[ -z "$jamfProURL" ]]; then
        jamfProURL=$(defaults read $HOME/Library/Preferences/$plistFile.plist jamfpro_url)
    fi

    if [[ -z "$apiToken" ]];then
        apiToken=$(defaults read $HOME/Library/Preferences/$plistFile.plist apiToken)
    fi
    /bin/echo
fi

# If the Jamf Pro URL or apiToken aren't available prompted the user or hardcode it.
if [[ -z "$jamfProURL" ]]; then
    read -p "Please enter your Jamf Pro server URL: " jamfProURL
    #jamfProURL="https://your.site.here:PORTNUMBER"
fi

if [[ -z "$apiToken" ]]; then
    read -p "Please enter your Jamf Pro apiToken: " apiToken
    #apiToken="YourAPItokenHere"
fi


# Let's do this
/usr/bin/curl --header "authorization: Basic $apiToken" -H "Content-Type: text/xml" $jamfProURL/JSSResource/computers/serialnumber/$deviceSN/subset/general -X PUT -d "<?xml version="1.0" encoding="ISO-8859-1"?><computer><general><site><id>$siteID</id><name>$siteName</name></site></general></computer>"

/bin/echo "Finished"

exit 0

mhasman
Valued Contributor

Another step...
Would you please show me the right direction to use API for changing that computer assignment part:

Computers - Users and Locations - Department

Thanks!

85deb15b4f154b9ebc4b4102d0fee7c9