@mbezzo If you make a Configuration Profile available in Self Service with Allow Removal set to Yes it will remain in Self Service after installation but the button name will change to Remove. If it's still in scope then after it's removed you should then be able to re-install it. That might work for you if you're OK with your users being able to remove the profile on their own.
I don't have a great solution to this, but I acknowledge this can be a problem because of how certs are deployed via a profile. The cert can still be removed, but the profile already did it's job of delivering it initially, so it isn't going to do it again unless you intervene.
The only thing I can think of is, if these certs are machine level and not individual to each user account, you may be able to do something where you can have an Extension Attribute check to see if the cert is in the keychain as it should be, coming back with a simple Yes/No kind of response, and pair that with looking for the profile installed. In your Smart Group you would have to check for the existing of one, but not the other - specifically, Macs that have the Config Profile installed, but are missing the cert would fall into a group you could use for Exclusion from the Config Profile. Meaning, they would get removed from Scope, thereby removing the profile. You would then have another Smart Group that looked for Macs that had neither the Profile or the certificate, and use that as the main scope for the profile that will deliver the certificate. Machines with both cert and profile in place don't get anything redeployed since they are in good standing.
I can't say I've tested anything like the above, but if it works, what would happen is, on a recon, the machines with the profile installed but missing the certificate would move into the group to get the profile removed. When the next inventory check takes place, they should get moved back into scope to have the profile repushed to them.
It's possible none of the above will work as I'm thinking. Again, haven't tried it, but essentially the only way I can think to address this is something like the above - checking for specific conditions and using those for scopes and exclusions.
Maybe someone else has a better idea though.
Hi @sdagley
I don't mind if users remove the profile - but it does still leave the "pushed to everyone" config profile on the device. I guess I could turn off the auto deployment of that and stick to a Self Service only config - but man. That just seems like the wrong way. Automating this is better than having to make it fully manual!
thanks,
Matt
What about something like this:
Single script that runs from self service scoped to techs.
Script does the following:
remove from Smart or Static group (that profile is scoped to)
Recon - removes profile
re-add to smart or static group
Recon - reinstalls profile and cert.
If the cert is how you get on wifi then they would have to do this while hard wired.
@mbezzo I have a Policy in Self Service scoped to Macs that aren't connected to the corporate Wi-Fi and that SSID is visible which adds the computer running it to a Static Group which excludes the Mac from the scope of the pushed configuration profile and then adds it to a group that enables the Self Service installable profile. If you only want the pushed configuration profile to be re-installed you could have a script that adds it to a static group that's scoped as an exclusion, delay for a few seconds, then remove it from that list to put it back into scope for the profile. The delay might not be necessary, but I've seen a cases where the profile doesn't get removed and re-installed without one. I'm using a Self Service profile install as pushing a User Level profile won't install immediately while a Self Service profile does.
Thanks @mm2270, I've been tossing some similar ideas around in my head as well. It's rough that seemingly the only options are this complicated! Will keep thinking on it. :)
Thanks again!
@sdagley @m.donovan
These are interesting ideas, but I think it'd have to be a static group right? - which begs the question, how do you populate/maintain that static group?
lots to think about - thanks all! I think I'll open a ticket with Apple Enterprise support and see what they say too.
@mbezzo I create the static groups in the Jamf Pro GUI then use the Jamf API in a script to add & delete computers to the groups as needed.
Ok, I just had a thought. Haven't had a chance to test, but curious if you all think it's possible:
- Create a new, empty Static group and add to the Exclusions for the Config Profile
- Create a self service item that runs an API call to add that device to the exclusion group, and performs a recon
- Wait for config profile removal - The config profile should be removed, right?
- A second self service item that runs a similar API call to remove the device from the excluded static group and runs a recon.
- Profit?
Crazy? Doable? I suppose with a little scriptage it could be one Self Service item that would wait for the config profile to be removed, then yank the device from the excluded static group.
Hopefully will be able to test tomorrow - but holler if you think there's any glaring reason why this just won't work!
Thanks,
Matt
@mbezzo You can create an extension attribute with a "Text Field" type. This could be populated with specific strings. Through the GUI or through the API you could populate this extension attribute. You could then create a smart group where that extension attribute equals a specific string. You could then use this to unscope/rescope machines for the profile to essentially remove/reinstall the profile easily. You'd have to use exclusions for this to function.
Let me know if you need me to elaborate.
Hi @ryan.ball nope - totally makes sense! Definitely another way to do this.
FWIW, in my very-manual-and-not-yet-scripted testing, adding/removing a device from the static group scoped to be excluded from the config profile works well. So I'm gonna head down this path. Will report back!
Thanks again,
Matt
on that note... if anyone has a chunk of code for adding a device to a static group with the API - do share! :)
This happened to me before, but I went on a different route. First, I created a new wireless network using PSK. I created a Wireless Config Profile for this new WiFi Network and deployed it to my devices. I made sure all my devices got the profile by looking at logs and dashboard. I used a script that runs on login and recurring check-in to switch them to new WiFi network, put the new network on index 0, and delete all preferred wireless network except the new one of course. then I unscoped all devices from the 802.1x profile that has an expiring cert. Then I just made a new profile with the new cert and redeploy. then use the same script to switch their wifi back.
Regarding adding computers to a Static Group, this thread may help: https://www.jamf.com/jamf-nation/discussions/30085/how-do-you-put-a-computer-into-a-static-group-with-api
You'll also need to come up with a way to remove the computer from the group, which is a little more work I believe.
@sdagley
How can you make a configuration profile available in self service ? . If i open a config profile there is no self service option available ?- but if it could be put in self service it would be great
EDIT: Yeah ok - found it :)
@mbezzo Here's an example of my script to add/remove a computer to/from a static group:
#!/bin/bash
# Add and remove a computer from a group example by @sdagley
# Thanks to unknown author for the example of breaking out the xmlHeader and apiData
# for API calls
#
# Parameter 4 - JSS URL
# Parameter 5 - Encrypted username for Jamf Pro API access account
# Parameter 6 - Encrypted password for Jamf Pro API access account
jssAddress="$4"
jssAPIUsernameEncrypted="$5"
jssAPIUsernameSalt="UsernameSaltHere"
jssAPIUsernamePassphrase="UsernamePassphraseHere"
jssAPIPasswordEncrypted="$6"
jssAPIPasswordSalt="PasswordSaltHere"
jssAPIPasswordPassphrase="PasswordPassphraseHere"
function DecryptString() {
# Usage: ~$ DecryptString "Encrypted String" "Salt" "Passphrase"
echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}
jssAPIUsername=$(DecryptString $jssAPIUsernameEncrypted $jssAPIUsernameSalt $jssAPIUsernamePassphrase)
jssAPIPassword=$(DecryptString $jssAPIPasswordEncrypted $jssAPIPasswordSalt $jssAPIPasswordPassphrase)
ComputerName=$(/usr/sbin/scutil --get ComputerName)
apiURL="JSSResource/computergroups/id/"
#XML header stuff
xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"
TargetGroupID="GroupID#Here"
TargetGroupName="GroupNameHere"
# Add computer to a group
apiData="<computer_group><id>${TargetGroupID}</id><name>${TargetGroupName}</name><computer_additions><computer><name>$ComputerName</name></computer></computer_additions></computer_group>"
curl -sSkiu ${jssAPIUsername}:${jssAPIPassword} "${jssAddress}/${apiURL}${TargetGroupID}"
-H "Content-Type: text/xml"
-d "${xmlHeader}${apiData}"
-X PUT
TargetGroupID="GroupID#Here"
TargetGroupName="GroupNameHere"
# Delete computer from a group
apiData="<computer_group><id>${TargetGroupID}</id><name>${TargetGroupName}</name><computer_deletions><computer><name>$ComputerName</name></computer></computer_deletions></computer_group>"
curl -sSkiu ${jssAPIUsername}:${jssAPIPassword} "${jssAddress}/${apiURL}${TargetGroupID}"
-H "Content-Type: text/xml"
-d "${xmlHeader}${apiData}"
-X PUT
exit 0
A word of warning to anyone using Configuration Profiles installed via Self Service - even though the install is manually initiated if the computer falls out of scope for the profile it will automatically be removed.
Thanks @mm2270 and @sdagley That's a great start for getting a script cobbled together!
@sdagley
I've got my script (mostly) done - thanks to you! But MAN, I can't figure out what's failing during the api PUT command. I keep getting 401 Unauthorized errors but I'm using an account with full perms (don't worry, it's my test environment!) When I run the script from terminal for testing (while hard coding all the Jamf provided variables) the username/password are decrypting accurately. Any pointers? Here's some sanitized verbose output from the terminal:
++ /usr/sbin/scutil --get ComputerName
+ ComputerName=TestComputerName
+ apiURL=JSSResource/computergroups/id/
+ xmlHeader='<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
+ apiData='<computer_group><id>221</id><name>WiFive Fix (test)</name><computer_additions><computer><name>TestComputerName</name></computer></computer_additions></computer_group>'
+ curl -sSkiu ‘theActualAPIuser:theActualAPIpassword’ https://ourjssurl.com/JSSResource/computergroups/id/221 -H 'Content-Type: text/xml' -d '<?xml version="1.0" encoding="UTF-8" standalone="no"?><computer_group><id>221</id><name>WiFive Fix (test)</name><computer_additions><computer><name>TestComputerName</name></computer></computer_additions></computer_group>' -X PUT
HTTP/1.1 401 Unauthorized
Accept-Ranges: bytes
Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0
Content-Type: text/html;charset=UTF-8
Date: Thu, 04 Apr 2019 18:23:38 GMT
Server: Jamf Cloud Node
WWW-Authenticate: Basic realm="Restful JSS Access -- Please supply your credentials"
X-FRAME-OPTIONS: SAMEORIGIN
Content-Length: 424
Connection: keep-alive
<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;">Unauthorized</p>
<p>The request requires user authentication</p>
<p>You can get technical details <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">here</a>.<br>
Please continue your visit at our <a href="/">home page</a>.
</p>
</body>
</html>
Anything jump out to you?
Really appreciate it!
Matt
@mbezzo Are you sure the account you're using for the API call has Read and Update permissions for Static Computer Groups? It also looks like you're using Jamf Cloud, so you might ask Jamf support if there are additional steps required for accessing the API with it.
Yup - just verified again and the account has full access to everything. I'm using this same account for another API script I've made and that one is working just fine... So, something is weird here! Now to just find it lol.
Thanks for the help!
@mbezzo Just noticed your snippet shows ‘theActualAPIuser:theActualAPIpassword’
("smart" quotes rather than '). That's going to be a problem as bash doesn't consider them to be the same thing. There may also be a problem with having the username:password inside a single quoted glob if that's actually how you constructed your curl command as it's going to be parsed as a single argument rather than 2 arguments separated by a : so follow the format in the sample I posted.
AHHHHHHHH I hate everything. Created new API account - boom. Works perfectly. NO IDEA why my existing account is failing for this specific use case...
Anyway, @sdagley - your script is a perfect use for this. I put a "sleep 10" between adding the computer to the group and removing it - watched my test device as the config profile was removed, and seconds later reappeared issuing a new cert. FANFRICKINTASTIC. :)
So, in summary: Create a new (empty) static computer group and scope it to be excluded from the config profile in question.
Create Self Service item that runs @sdagley's script above, configuring it so it adds the computer to your newly created static group. Add a short sleep in the script after adding to the group before removing from the group.
And there you have a quick and easy way to remove/redeploy a config profile!
Thanks everyone!
okay, I'm fancying up (that's a word, right?) this script with some pop up notifications, but I'm finding that the curl connection is remaining open so it's passing my recon data and prompt data through curl, which means everything is failing again. Anybody have ideas on how to end the curl session after it's done the work?
@mbezzo Try removing the standalone="no"
from the xmlHeader
line in the script so that it reads xmlHeader="<?xml version="1.0" encoding="UTF-8"?>"
. It's an artifact of the script I borrowed to break out the components of the curl call and I don't believe it's necessary.