Posted on 07-31-2019 03:56 AM
Hi,
Im looking to create a scripted install of an application that is hosted internally.
The script needs to download and run various commands to install the software. This we have worked out.
The application has multiple available versions and multiple locations dependent on the project you are working on.
What I need to do, is when this script executes, it asks for User interaction and asks for the server name and the agent version, this then passes into the script and off it goes installing :)
What is the best way to request the user interaction. I can make it work using automater but i'm not sure if that is the best way to go?
Thanks
Dan
Posted on 07-31-2019 06:10 AM
Depends on what scripting language your using to start with, but an osascript call is a pretty good way to prompt a dialogue because you can just tell the system to present it to the user, there are a few options for text boxes and drop down lists etc...
Posted on 07-31-2019 06:21 AM
The language is bash. But osascript is what I keep coming across. Wanted to make sure that is what other would advise before I commit to writing something.
Thank you
Posted on 07-31-2019 06:41 AM
if going bash instead of osascript - could always use the built in JamfHelper - some examples below if not familiar
another option, nesting/calling osascript inside a shell script is a nice blend & allows for versatility all in one script.
https://github.com/retrac81/JamfHelper
https://github.com/smashism/jamfpro-scripts/blob/master/self-service/assign_this_mac.sh
Posted on 07-31-2019 09:04 AM
I'd suggest using bash but with osascript embedded into it as @Hugonaut mentioned above. I usually do this by creating a variable that will capture the input using osascript and then that variable can be passed back to the rest of the shell script and used.
If it's a standalone app this will be used in, then there's not a lot needed to make it work. If it's a script that will be run from a Jamf policy, then take a look at the second link in the post above this one for an example of how to do that, since any osascript/Applescript calls must be done as the user, not as root. The OS will block it from appearing in almost all cases if not called properly.
Posted on 07-31-2019 03:42 PM
This may get you started:
#!/bin/bash
results=$( /usr/bin/osascript -e "display dialog "Text and Buttons!" default answer "Some text..." buttons {"Cancel","OK"} default button {"OK"}" )
theButton=$( echo "$results" | /usr/bin/awk -F "button returned:|," '{print $2}' )
theText=$( echo "$results" | /usr/bin/awk -F "text returned:" '{print $2}' )
echo $theButton
echo $theText
exit 0
Posted on 07-31-2019 06:06 PM
Just remember to be careful using bash because the default shell when 10.15 Catalina releases this year will be ZSH. Bash is still there, but you know, for future proofing.
Posted on 10-22-2019 01:38 PM
Did you every get this working?
i kinda want to do the same thing have a script that runs once, and at user login. I needs to run as root but be presented to the current user that is logged in...
how did you do it?
@DanielDarnbrough
Posted on 10-23-2019 12:44 AM
There is a trend of admins starting to use DEPNotify for something like this. One shop uses it for Adobe CC installs
Posted on 10-24-2019 02:39 AM
@DanielDarnbrough have look at this example from another discussion in Jamf Nation.
Self Service - Get User Input with Script
We use a lot of osascript inside bash scripts here when we need to get users' input.
Furthermore as we have a global customer base we try as much as possible to localise the messages to make the process easier for all, and AppleScript (osascript) allow you to do that.
Other options:
JamfHelp is good but limited.
After that you are looking in installing another tool to support the task when osascript is native to the macOS (for now at least).
@Nix4Life We use the same concept (osascript inside bash) for Adobe CC Installs.
This allow us to offer multi-language installs with one single Adobe package/app.
All the end user has to do is choose the language for the Adobe app and after that the installation is set in that language.
Saved us a lot of policies and HD space.
Also that follows the same concept of localisation, the prompt is in the user's language.
Here is the "sanitised" example of our script to illustrate the osascript part.
#!/bin/bash
##########################################################################################
#
# Author: Mauricio Pellizzon 2019
#
##########################################################################################
selectLangInterface() {
consoleUser=$(stat -f %Su /dev/console)
useHome=$(eval echo "~$consoleUser")
userLocale=$(defaults read "$useHome"/Library/Preferences/.GlobalPreferences.plist AppleLocale)
case "$userLocale" in
"cs_CZ"|"da_DK"|"de_DE"|"en_AE"|"en_GB"|"en_IL"|"en_US"|"en_XM"|"es_ES"|"es_LA"|"es_MX"|"es_NA"|"fi_FI"|"fr_CA"|"fr_FR"|"fr_MA"|"fr_XM"|"hu_HU"|"it_IT"|"ja_JP"|"ko_KR"|"nb_NO"|"nl_NL"|"pl_PL"|"pt_BR"|"ru_RU"|"sv_SE"|"tr_TR"|"uk_UA"|"zh_CN"|"zh_TW");;
* ) userLocale=${userLocale::${#userLocale}-3};;
esac
case "$userLocale" in
"cs_CZ" ) selectLang="Zvolte jazyk" lang="Jazyk" ;;
"cs" ) selectLang="Zvolte jazyk" lang="Jazyk" ;;
"da_DK" ) selectLang="Vælg sprog" lang="Sprog" ;;
"da" ) selectLang="Vælg sprog" lang="Sprog" ;;
"de_DE" ) selectLang="Sprache wählen" lang="Sprache" ;;
"de" ) selectLang="Sprache wählen" lang="Sprache" ;;
"en_GB" ) selectLang="Select Language" lang="Language" ;;
"en_US" ) selectLang="Select Language" lang="Language" ;;
"en_XM" ) selectLang="Select Language" lang="Language" ;;
"en" ) selectLang="Select Language" lang="Language" ;;
"es_ES" ) selectLang="Seleccione idioma" lang="Idioma" ;;
"es_LA" ) selectLang="Seleccione idioma" lang="Idioma" ;;
"es_MX" ) selectLang="Seleccione idioma" lang="Idioma" ;;
"es_NA" ) selectLang="Seleccione idioma" lang="Idioma" ;;
"es" ) selectLang="Seleccione idioma" lang="Idioma" ;;
"fi_FI" ) selectLang="Valitse kieli" lang="Kieli" ;;
"fi" ) selectLang="Valitse kieli" lang="Kieli" ;;
"fr_CA" ) selectLang="Choisir une langue" lang="Langue" ;;
"fr_FR" ) selectLang="Choisir une langue" lang="Langue" ;;
"fr_XM" ) selectLang="Choisir une langue" lang="Langue" ;;
"fr" ) selectLang="Choisir une langue" lang="Langue" ;;
"hu_HU" ) selectLang="Nyelv választása" lang="Nyelv" ;;
"hu" ) selectLang="Nyelv választása" lang="Nyelv" ;;
"it_IT" ) selectLang="Selezionare la lingua" lang="Lingua" ;;
"it" ) selectLang="Selezionare la lingua" lang="Lingua" ;;
"ja_JP" ) selectLang="言語を選択" lang="言語" ;;
"ja" ) selectLang="言語を選択" lang="言語" ;;
"ko_KR" ) selectLang="언어 선택" lang="언어" ;;
"ko" ) selectLang="언어 선택" lang="언어" ;;
"nb_NO" ) selectLang="Velg språk" lang="Språk" ;;
"nb" ) selectLang="Velg språk" lang="Språk" ;;
"nl_NL" ) selectLang="Taal selecteren" lang="Taal" ;;
"nl" ) selectLang="Taal selecteren" lang="Taal" ;;
"pl_PL" ) selectLang="Wybierz język" lang="Język" ;;
"pl" ) selectLang="Wybierz język" lang="Język" ;;
"pt_BR" ) selectLang="Selecione o idioma" lang="Idioma" ;;
"pt" ) selectLang="Selecione o idioma" lang="Idioma" ;;
"ru_RU" ) selectLang="Выбрать язык" lang="Язык" ;;
"ru" ) selectLang="Выбрать язык" lang="Язык" ;;
"sv_SE" ) selectLang="Välj språk" lang="Språk" ;;
"sv" ) selectLang="Välj språk" lang="Språk" ;;
"tr_TR" ) selectLang="Dil Seçin" lang="Dil" ;;
"tr" ) selectLang="Dil Seçin" lang="Dil" ;;
"uk_UA" ) selectLang="Вибрати мову" lang="Мова" ;;
"uk" ) selectLang="Вибрати мову" lang="Мова" ;;
"zh_CN" ) selectLang="选择语言" lang="语言" ;;
"zh_TW" ) selectLang="選取語言" lang="語言" ;;
esac
}
localizableString() {
lang="$1"
selectLang="$2"
choosenLanguage=$(sudo -u "$userName" osascript <<EOF
set systemUIServer to "SystemUIServer"
if systemUIServer is not in every paragraph of (do shell script "ps -Ac -o comm=") then return
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
tell application systemUIServer
set myOK to localized string of "OK" from table "Localizable" in bundle "/System/Library/CoreServices/Installer.app"
set myCancel to localized string of "Cancel" from table "Localizable" in bundle "/System/Library/CoreServices/Installer.app"
tell application "System Events"
activate
set theLanguages to {"Česky", "Dansk", "Deutsch", "English يدعم العربية", "English (International)", "English תומך עברית", "English (North America)", "Español", "Español (América Latina)", "Suomi", "Français canadien", "Français", "Français (Maroc)", "Magyar", "Italiano", "日本語", "한국어", "Norsk (Bokmål)", "Nederlands", "Polski", "Português do Brasil", "Pусский", "Svenska", "Türkçe", "Українська", "У简体中文", "繁體中文"}
set theChoosenLanguage to choose from list theLanguages with title "Adobe Creative Cloud App $lang" with prompt "$selectLang" OK button name myOK cancel button name myCancel
end tell
end tell
EOF
)
}
localeSetup() {
# user interface to setup the locale....
selectLangInterface
localizableString "$lang" "$selectLang"
case "$choosenLanguage" in
"Česky" ) choosenLocale="cs_CZ";;
"Dansk" ) choosenLocale="da_DK";;
"Deutsch" ) choosenLocale="de_DE";;
"English يدعم العربية" ) choosenLocale="en_AE";;
"English (International)" ) choosenLocale="en_GB";;
"English תומך עברית" ) choosenLocale="en_IL";;
"English (North America)" ) choosenLocale="en_US";;
"Español" ) choosenLocale="es_ES";;
"Español (América Latina)" ) choosenLocale="es_MX";;
"Suomi" ) choosenLocale="fi_FI";;
"Français canadien" ) choosenLocale="fr_CA";;
"Français" ) choosenLocale="fr_FR";;
"Français (Maroc)" ) choosenLocale="fr_MA";;
"Magyar" ) choosenLocale="hu_HU";;
"Italiano" ) choosenLocale="it_IT";;
"日本語" ) choosenLocale="ja_JP";;
"한국어" ) choosenLocale="ko_KR";;
"Norsk (Bokmål)" ) choosenLocale="nb_NO";;
"Nederlands" ) choosenLocale="nl_NL";;
"Polski" ) choosenLocale="pl_PL";;
"Português do Brasil" ) choosenLocale="pt_BR";;
"Pусский" ) choosenLocale="ru_RU";;
"Svenska" ) choosenLocale="sv_SE";;
"Türkçe" ) choosenLocale="tr_TR";;
"Українська" ) choosenLocale="uk_UA";;
"У简体中文" ) choosenLocale="zh_CN";;
"繁體中文" ) choosenLocale="zh_TW";;
* ) echo "$FUNCNAME" ;;
esac
}
##########################################################################################
#
# SCRIPT CONTENTS
#
##########################################################################################
userName=$(ls -la /dev/console | cut -d " " -f 4)
localeSetup
echo "$choosenLanguage"
Attached the screen shot of the policy for illustration.
PS: We write a local file with the chosen language for subsequent installs, so this prompt is done once unless the user requires another language, which is available via another self-service policy.
Posted on 05-06-2020 12:50 PM
@mm2270, I'm curious what the syntax would be to get the user's input via a dialog that they enter and then set it as a variable. I have the following osascript to enter a computer name. What ever value is entered, it will use that to rename the computer.
#!/bin/bash
/usr/bin/osascript << EOF
property compName : ""
repeat while compName is ""
tell application "Finder"
activate
display dialog "Set the Computer Name. (Example: iMac-12345, mbp-67890)" default answer compName
set compName to text returned of result
end tell
end repeat
try
do shell script "hostname " & quoted form of compName
on error errorMsg number errorNum
display alert "Error " & errorNum message errorMsg buttons "Cancel" default button 1
end try
EOF
name=$(hostname)
scutil --set ComputerName "${name}"
scutil --set LocalHostName "${name}"
If I want to take it one step further where the user would enter the text but then append the serial number of the Mac to it without them having to enter it, do you know what that would look like?
For example, the end result would be something like "mbp-serialnumber". "mbp-" would be what the user would enter and "serialnumber" would be put in automagically.
It would be more ideal but probably requires more scripting smarts to use if/then or case statements to name it automatically. For example, use the below command to get the model number
(system_profiler SPHardwareDataType | grep "Model Name" | awk -F ":" '{ sub(" ",""); print $2}' | tr -d ' ')
then use the result to name it. For example, if the model is an iMac, use the string "im-" or if the model is MacBook, use the string "mb-", etc then append the serial number. This would minimize "user typos" and offer consistent naming conventions.
Posted on 05-06-2020 01:43 PM
@joethedsa Hi there. So generally with these kinds of situations, where input from the user is an absolute requirement before proceeding with another operation, I usually handle this more in the bash section than within the AppleScript/osascript part. I put the portion where AppleScript requests input into a bash function. Outside of that, I check the variable that was returned, and if it was empty or not what we expected, I re-run the function, so it pops up the AppleScript window to request input again. Essentially it creates a loop that won't exit until the input is something we expect. That could be as simple as "not empty", but you could go further with it and check the length of the string returned for example, so if it's not at least "x" number of characters long, re-pop up the window for input.
Once we have something that works, then you can go on with combining the serial number and the user input into a single string and then use that to rename the Mac.
Here's what my script might look like.
#!/bin/bash
function askForCompName ()
{
## Capture the user input into a variable
COMPNAME=$(/usr/bin/osascript << EOF
tell application "System Events"
activate
display dialog "Set the Computer Name. (Example: iMac-12345, mbp-67890)" default answer ""
set compName to text returned of result
end tell
EOF)
## Check the variable to make sure it's not empty...
if [ "$COMPNAME" == "" ]; then
echo "Computer name was not entered. Re prompting the user..."
askForCompName
else
echo "Computer name entered was: $COMPNAME"
fi
}
## Run the function above
askForCompName
## Get the Macs serial number
SERIALNUMBER=$(/usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice | awk -F'"' '/IOPlatformSerialNumber/{print $4}')
## Generate a new computer name from the above information
NEWCOMPNAME="${COMPNAME}-${SERIALNUMBER}"
## Rename the Mac using scutil (can also use the Jamf binary here)
/usr/sbin/scutil --set ComputerName "${NEWCOMPNAME}"
/usr/sbin/scutil --set LocalHostName "${NEWCOMPNAME}"
I haven't actually tested this script in it's entirety. I only tested the main function loop where it keeps popping up unless some input is given, which does work. The rest should also work since it's pretty simple in what its doing.
Posted on 05-07-2020 01:50 PM
@mm2270, Thank you! I tested this out and it works just as intended. I like the error checking loop if there is no input. I did noticed though, if the Cancel button is clicked, it also just loops. Is that intended? I ran it in Catalina.
Is there a way to make a "cap" as to only allowing a maximum of two characters for input? These systems will be bound to Active Directory. There is a 15 character limit that it uses. Adding two letters, a dash, and then the serial number reaches 15 characters.
Posted on 05-08-2020 12:07 AM
Hi @joethedsa ,
I haven't tested this, but you should be able to accomplish your cap by using Regex to test against the input:
#!/bin/bash
#Script to prompt user for two letter Asset Tag and set Computer name to Asset Tag and Serial Number
#Shaquir Tannis
#AppleScript for user input
promptUser ()
{
assetTag=$(/usr/bin/osascript << EOF
tell application "System Events"
activate
set input to display dialog "Enter Asset Tag: " default answer "##" buttons {"OK"} default button 1
return text returned of input as string
end tell
EOF
)
#Loop until user inputs two letters
until [[ "$assetTag" =~ ^[a-zA-Z]{2}$ ]]
do
promptUser
done
}
#Call on function to prompt user
promptUser
#Grab Computer Serial Number
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
#Set computer name
/usr/sbin/scutil --set HostName "$assetTag-$serialNumber"
/usr/sbin/scutil --set LocalHostName "$assetTag-$serialNumber"
/usr/sbin/scutil --set ComputerName "$assetTag-$serialNumber"
/usr/local/bin/jamf setComputerName -name "$assetTag-$serialNumber"
exit
fi
Posted on 05-11-2020 08:40 AM
@shaquir, thanks for your input. I added the below syntax from your script but adjusted the function name and the variable to fit the one @mm2270 shared and it worked as expected:
until [[ "$assetTag" =~ ^[a-zA-Z]{2}$ ]]
do
promptUser
done
For some reason though if I hit Cancel, the dialog box just re-appears. Still trying to work through that annoyance.
Posted on 05-11-2020 11:04 AM
I'm sure there is a better way to do this, but you could try:
promptUser ()
{
assetTag=$(/usr/bin/osascript << EOF
tell application "System Events"
activate
set input to display dialog "Enter Asset Tag: " default answer "##" buttons {"Not Now", "OK"} default button 2
set buttonSelected to button returned of the result
if buttonSelected is "OK" then
return text returned of input as string
else
return buttonSelected
end if
end tell
EOF
)
if [ "$assetTag" = "Not Now" ];
then
echo "User Selected Not Now"
exit 1
else
#Loop until user inputs two letters
until [[ "$assetTag" =~ ^[a-zA-Z]{2}$ ]]
do
promptUser
done
fi
}
#Call on function to prompt user
promptUser
#Grab Computer Serial Number
serialNumber=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')
#Set computer name
/usr/sbin/scutil --set HostName "$assetTag-$serialNumber"
/usr/sbin/scutil --set LocalHostName "$assetTag-$serialNumber"
/usr/sbin/scutil --set ComputerName "$assetTag-$serialNumber"
/usr/local/bin/jamf setComputerName -name "$assetTag-$serialNumber"
exit
fi
I substituted Applescript's default "Cancel" to "Not Now". There is probably a better way to handle the error, but this should work for you.
Posted on 07-24-2020 03:41 AM
If I run the script, I was asked to allow Jamf to control System Events.
Is there a way to configure this using a configuration policy or something else?
Posted on 07-24-2020 04:44 AM
Hi @oli,
You'd need to whitelist Jamf using the AppleEvents: Creating Privacy Preferences Policy Control profiles for macOS.
Untested but this may be a good start for you: Jamf_All_Notifications_v1.mobileconfig
Posted on 07-24-2020 04:58 AM
Hi @shaquir ,
thank you for quick responce! I will give it a try.
Best regards!
10-07-2021 06:41 AM - edited 10-07-2021 06:44 AM
I have built a script that prompts for the asset tag of the computer and then applies it to the Computer record in Jamf. I used snippets of code from a couple posts here on JamfNation and some extra bits on the web. It functions by displaying a dialog box with Cancel and OK buttons and a text box for entering the asset tag. If the user types nothing and hits OK, it will prompt again. If the user hits Cancel, it exits without doing anything. If the user types anything in the box and hits OK, that information is applied to the Computer record. One Caveat is if the user enters spaces in the text, only the text before the first space will be applied.
#!/bin/sh
# the purpose of this script is to prompt the user for the asset tag of the computer, save it as a variable,
# then use that variable in jamf recon -assetTag $ASSETTAG so the computer record gets updated.
function askForAssetTag ()
{
## Capture the user input into a variable
ASSETTAG=$(/usr/bin/osascript << EOF
tell application "System Events"
activate
display dialog "Please enter the Company Asset Tag number of this computer. (please include all the leading zeros. No spaces permitted)" default answer ""
set assetTag to text returned of result
end tell
EOF)
# Check status of osascript. Clicking Cancel will just exit without doing anything.
if [ "$?" != "0" ] ; then
echo "User aborted. Exiting..."
exit 0
fi
## Check the variable to make sure it's not empty...
if [ "$ASSETTAG" == "" ]; then
echo "Asset Tag was not entered. Re prompting the user..."
askForAssetTag
else
echo "Asset Tag entered was: $ASSETTAG"
fi
}
## Run the function above
askForAssetTag
#then apply the output to the recon -assetTag command
jamf recon -assetTag $ASSETTAG
echo "The asset tag of this computer is now $ASSETTAG"
exit 0
I'm sure you could apply RegEx to make sure the text entered meets your organization's standards, but that's beyond my skills. My intent with the script where I am is that only the tech setting up the computer would need to run this and it is in their best interest to enter valid text.
Posted on 10-07-2021 07:47 AM
Not sure where that caveat is coming from.
Is that in Jamf record? Have you tried to change this part of your code?
jamf recon -assetTag "$ASSETTAG"
10-07-2021 07:53 AM - edited 10-07-2021 07:54 AM
the Jamf recon -assetTag xxxxx command will only accept the contiguous text entered after -assetTag . It will accept all of "2374657896" but it will only accept the first part of "23746 57896" as "23746" I discovered that in my testing. I did not try putting the variable in quotes though because our asset tags have to be entered as a single chunk of digits with no spaces in all our systems anyway.
Posted on 10-07-2021 08:31 AM
Ok that makes sense, if spaces are not allowed just clean up before putting in Jamf
ASSETTAG=$(echo "$ASSETTAG" | sed 's/ //g')