├── Application Usage ├── applicationUsage.sh └── applicationUsageEA.sh ├── ChangeSitesInParsedXML.sh ├── Computer Information.bash ├── DeleteCasperRemotePolicies.sh ├── DeletedLocalUsers.sh ├── DownloadBuildingsList.sh ├── DownloadNetworkSegments.sh ├── List Mobile Device Apps.sh ├── PopulateMobileDeviceAssetTags.sh ├── Precreate Jamf Computer Record ├── Precreate Jamf Computer Record List.txt └── Precreate Jamf Computer Record.sh ├── README ├── Rename Buildings ├── RenameBuildings.sh └── RenameBuildingsList.tab ├── ReportOfficeLicense.sh ├── ReportSIPStatus.sh ├── Set Time Zone.sh ├── UploadBuildingsList.sh ├── UploadDepartmentsList.sh ├── UploadNetworkSegments.sh └── rsync to DPs ├── net.talkingmoose.syncjamfdps.plist ├── rsync-servers.txt ├── send-to-dp2.sh └── smb-servers.txt /Application Usage/applicationUsage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | < "/Library/${dataFolder}/latestXML.txt" 68 | 69 | fi 70 | 71 | exit 0 72 | -------------------------------------------------------------------------------- /Application Usage/applicationUsageEA.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | <" | /usr/bin/awk -F "|" '{ print $2 }' ) 43 | 44 | # sum open seconds 45 | openSeconds=$( echo "$openSecondsList" | /usr/bin/paste -sd+ - | /usr/bin/bc ) 46 | 47 | # calculate open minutes 48 | openMinutes=$((openSeconds/60)) 49 | 50 | # read locally stored application usage file for number of days in report 51 | usageDays=$( /usr/bin/defaults read "/Library/${dataFolder}/applicationusage.plist" Days ) 52 | 53 | # return app usage to JSS 54 | echo "$openMinutes minutes over $usageDays days" 55 | 56 | exit 0 -------------------------------------------------------------------------------- /ChangeSitesInParsedXML.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: October 29, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Updates a Site name in parsed XML from the JSS Migration 15 | # Utility: https://github.com/igeekjsc/JSSAPIScripts. Useful for 16 | # migrating to new sites in a different Jamf Pro server. 17 | # 18 | # The script creates a log file in the same folder as the script. 19 | # 20 | # Except where otherwise noted, this work is licensed under 21 | # http://creativecommons.org/licenses/by/4.0/ 22 | # 23 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 24 | 25 | # INSTRUCTIONS 26 | 27 | # 1) Modify the siteName variable below. 28 | # 2) Run the jssMigrationUtility.bash script to download the source XML files. 29 | # 3) Move the script to the same level as the parsed_xml folder in the JSS_Migration folder. 30 | # 4) Run the script via Terminal or an editor with a "run script" feature. 31 | # 5) Review the XML files in the parsed_xml folder and verify Site nodes are changed. 32 | 33 | siteName="New Site Name" 34 | 35 | # path to this script 36 | currentDirectory=$( /usr/bin/dirname "$0" ) 37 | 38 | # name of this script 39 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 40 | 41 | # set the parsed_xml directory in the same directory as script 42 | outputDirectory="$currentDirectory/parsed_xml" 43 | 44 | # set the log file in same directory as script 45 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 46 | 47 | # functions 48 | function logresult() { 49 | if [ $? = 0 ] ; then 50 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 51 | else 52 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 53 | continue 54 | fi 55 | } 56 | 57 | # the time right now 58 | startTime=$( /bin/date '+%s' ) 59 | 60 | # start the log 61 | logresult "--------------------- Begin Script ---------------------" 62 | 63 | # get list of XML files 64 | fileList=$( /bin/ls "$outputDirectory" ) 65 | logresult "Creating XML file list." "Failed creating XML file list." 66 | 67 | while IFS= read aFile 68 | do 69 | XMLContent=$( /bin/cat "$currentDirectory/parsed_xml/$aFile" ) 70 | 71 | logresult "Reading file \"$aFile\"." "Failed reading file \"$aFile\"." 72 | 73 | unwrappedXML=$( echo "$XMLContent" | /usr/bin/xmllint --noblanks - ) 74 | 75 | logresult "Unwrapping XML from file \"$aFile\"." "Failed unwrappingXML from file \"$aFile\"." 76 | 77 | updatedXML=$( echo "$unwrappedXML" | /usr/bin/sed "s/.*<\/name><\/site>/$siteName<\/name><\/site>/g" ) 78 | 79 | logresult "Replacing site in XML from file \"$aFile\"." "Failed replacing site in XML from file \"$aFile\"." 80 | 81 | newXML=$( echo "$updatedXML" | /usr/bin/xmllint --format - ) 82 | 83 | logresult "Rewrapping XML from file \"$aFile\"." "Failed rewrapping XML from file \"$aFile\"." 84 | 85 | echo "$newXML" > "$currentDirectory/parsed_xml/$aFile" 86 | 87 | logresult "Writing modified XML to file \"$aFile\"." "Failed writing modified XML to file \"$aFile\"." 88 | 89 | fileCount=$((fileCount+1)) 90 | 91 | done <<< "$fileList" 92 | 93 | # stop the timer 94 | # calculate how long the script ran 95 | 96 | logresult "Completing script." 97 | logresult "Modified $fileCount files." 98 | 99 | # the time right now 100 | stopTime=$( /bin/date '+%s' ) 101 | 102 | # subtract start time from stop time and log the time in seconds 103 | diff=$(($stopTime-$startTime)) 104 | logresult "Script operations took $diff seconds to complete." 105 | 106 | logresult "---------------------- End Script ---------------------- 107 | 108 | " 109 | 110 | exit 0 111 | -------------------------------------------------------------------------------- /Computer Information.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | < Computer Mangement > 38 | Scripts and create a new script. Copy this script in full to the 39 | script body and save. 40 | 4) Then choose Computers > Policies and create a new policy. Add 41 | the script to the policy and enable it for Self Service. 42 | 5) When an end user calls your Help Desk, the technician can instruct 43 | him or her to open Self Service and run the script for trouble- 44 | shooting. 45 | 46 | ----------------------------------------------------------------------- 47 | ABOUT_THIS_SCRIPT 48 | 49 | 50 | # if reporting on Active Directory domain 51 | adDomain="talkingmoose.pvt" 52 | netbiosDomain="TALKINGMOOSE" 53 | 54 | # if using mailto option 55 | supportEmail="support@talkingmoose.pvt" 56 | 57 | 58 | 59 | ## General section ##### 60 | 61 | 62 | # Display computer name 63 | runCommand=$( /usr/sbin/scutil --get ComputerName ) 64 | computerName="Computer Name: $runCommand" 65 | 66 | 67 | # Display serial number 68 | runCommand=$( /usr/sbin/system_profiler SPHardwareDataType | /usr/bin/grep "Serial Number" | /usr/bin/awk -F ": " '{ print $2 }' ) 69 | serialNumber="Serial Number: $runCommand" 70 | 71 | 72 | # Display uptime 73 | runCommand=$( /usr/bin/uptime | /usr/bin/awk -F "(up |, [0-9] users)" '{ print $2 }' ) 74 | if [[ "$runCommand" = *day* ]] || [[ "$runCommand" = *sec* ]] || [[ "$runCommand" = *min* ]] ; then 75 | upTime="Uptime: $runCommand" 76 | else 77 | upTime="Uptime: $runCommand hrs/min" 78 | fi 79 | 80 | 81 | 82 | ## Network section ##### 83 | 84 | 85 | # Display active network services and IP Addresses 86 | 87 | networkServices=$( /usr/sbin/networksetup -listallnetworkservices | /usr/bin/grep -v asterisk ) 88 | 89 | while IFS= read aService 90 | do 91 | activePort=$( /usr/sbin/networksetup -getinfo "$aService" | /usr/bin/grep "IP address" | /usr/bin/grep -v "IPv6" ) 92 | if [ "$activePort" != "" ] && [ "$activeServices" != "" ]; then 93 | activeServices="$activeServices\n$aService $activePort" 94 | elif [ "$activePort" != "" ] && [ "$activeServices" = "" ]; then 95 | activeServices="$aService $activePort" 96 | fi 97 | done <<< "$networkServices" 98 | 99 | activeServices=$( echo "$activeServices" | /usr/bin/sed '/^$/d') 100 | 101 | 102 | # Display Wi-Fi SSID 103 | model=$( /usr/sbin/system_profiler SPHardwareDataType | /usr/bin/grep 'Model Name' ) 104 | 105 | if [[ "$model" = *Book* ]]; then 106 | runCommand=$( /usr/sbin/networksetup -getairportnetwork en0 | /usr/bin/awk -F ": " '{ print $2 }' ) 107 | else 108 | runCommand=$( /usr/sbin/networksetup -getairportnetwork en1 | /usr/bin/awk -F ": " '{ print $2 }' ) 109 | fi 110 | 111 | SSID="SSID: $runCommand" 112 | 113 | 114 | # Display SSH status 115 | runCommand=$( /usr/sbin/systemsetup -getremotelogin | /usr/bin/awk -F ": " '{ print $2 }' ) 116 | SSH="SSH: $runCommand" 117 | 118 | 119 | # Display date, time and time zone 120 | runCommand=$( /bin/date ) 121 | timeInfo="Date and Time: $runCommand" 122 | 123 | 124 | # Display network time server 125 | runCommand=$( /usr/sbin/systemsetup -getnetworktimeserver ) 126 | timeServer="$runCommand" 127 | 128 | 129 | 130 | ## Active Directory section ##### 131 | 132 | 133 | # Display Active Directory binding 134 | runCommand=$( /usr/sbin/dsconfigad -show | /usr/bin/grep "Directory Domain" | /usr/bin/awk -F "= " '{ print $2 }' ) 135 | 136 | if [ "$runCommand" = "$adDomain" ]; then 137 | AD="Bound to Active Directory: Yes" 138 | else 139 | AD="Bound to Active Directory: No" 140 | fi 141 | 142 | 143 | # Test Active Directory binding 144 | runCommand=$( /usr/bin/dscl "/Active Directory/$netbiosDomain/All Domains" read /Users ) 145 | 146 | if [ "$runCommand" = "name: dsRecTypeStandard:Users" ]; then 147 | testAD="Test Active Directory Connection: Success" 148 | else 149 | testAD="Test Active Directory Connection: Fail" 150 | fi 151 | 152 | 153 | 154 | ## Hardware/Software section ##### 155 | 156 | 157 | # Display free space 158 | FreeSpace=$( /usr/sbin/diskutil info / | /usr/bin/grep -E 'Free Space|Available Space|Container Free Space' | /usr/bin/awk -F ":\s*" '{ print $2 }' | awk -F "(" '{ print $1 }' | xargs ) 159 | FreeBytes=$( /usr/sbin/diskutil info / | /usr/bin/grep -E 'Free Space|Available Space|Container Free Space' | /usr/bin/awk -F "(\\\(| Bytes\\\))" '{ print $2 }' ) 160 | DiskBytes=$( /usr/sbin/diskutil info / | /usr/bin/grep -E 'Total Space' | /usr/bin/awk -F "(\\\(| Bytes\\\))" '{ print $2 }' ) 161 | FreePercentage=$(echo "scale=2; $FreeBytes*100/$DiskBytes" | bc) 162 | diskSpace="Disk Space: $FreeSpace free (${FreePercentage}% available)" 163 | 164 | 165 | # Display operating system 166 | runCommand=$( /usr/bin/sw_vers -productVersion) 167 | operatingSystem="Operating System: $runCommand" 168 | 169 | 170 | # Display battery cycle count 171 | runCommand=$( /usr/sbin/ioreg -r -c "AppleSmartBattery" | /usr/bin/grep '"CycleCount" = ' | /usr/bin/awk '{ print $3 }' | /usr/bin/sed s/\"//g ) 172 | batteryCycleCount="Battery Cycle Count: $runCommand" 173 | 174 | 175 | 176 | ## Format information ##### 177 | 178 | 179 | displayInfo="---------------------------------------------- 180 | GENERAL 181 | $computerName 182 | $serialNumber 183 | $upTime 184 | ---------------------------------------------- 185 | NETWORK 186 | $activeServices 187 | $SSID 188 | $SSH 189 | $timeInfo 190 | $timeServer 191 | ---------------------------------------------- 192 | ACTIVE DIRECTORY 193 | $AD 194 | $testAD 195 | ---------------------------------------------- 196 | HARDWARE/SOFTWARE 197 | $diskSpace 198 | $operatingSystem 199 | $batteryCycleCount 200 | ----------------------------------------------" 201 | 202 | 203 | 204 | ## Display information to end user ##### 205 | 206 | 207 | runCommand="button returned of (display dialog \"$displayInfo\" with title \"Computer Information\" with icon file posix file \"/System/Library/CoreServices/Finder.app/Contents/Resources/Finder.icns\" buttons {\"Enable Remote Support\", \"OK\"} default button {\"OK\"})" 208 | 209 | clickedButton=$( /usr/bin/osascript -e "$runCommand" ) 210 | 211 | 212 | 213 | ## Run additional commands ##### 214 | 215 | # function sourced from https://gist.github.com/cdown/1163649 216 | urlencode() { 217 | # urlencode 218 | 219 | old_lc_collate=$LC_COLLATE 220 | LC_COLLATE=C 221 | 222 | local length="${#1}" 223 | for (( i = 0; i < length; i++ )) 224 | do 225 | local c="${1:$i:1}" 226 | case $c in 227 | [a-zA-Z0-9.~_-]) printf '%s' "$c" ;; 228 | *) printf '%%%02X' "'$c" ;; 229 | esac 230 | done 231 | 232 | LC_COLLATE=$old_lc_collate 233 | } 234 | 235 | 236 | if [ "$clickedButton" = "Enable Remote Support" ]; then 237 | 238 | # open a remote support application 239 | # /usr/bin/open -a "/Applications/TeamViewer.app" 240 | 241 | # run a policy to enable remote support 242 | # /usr/local/bin/jamf policy -event EnableRemoteSupport 243 | 244 | # email computer information to help desk 245 | currentUser=$( stat -f "%Su" /dev/console ) 246 | subject="Computer Information ($serialNumber)" 247 | message="$displayInfo" 248 | encodedSubject=$( urlencode "$subject" ) 249 | encodedMessage=$( urlencode "$message" ) 250 | su "$currentUser" -c "/usr/bin/open mailto:$supportEmail\?subject=$encodedSubject\&body=$encodedMessage" 251 | 252 | if [ $? = 0 ]; then 253 | /usr/bin/osascript -e 'display dialog "Remote support enabled." with title "Computer Information" with icon file posix file "/System/Library/CoreServices/Finder.app/Contents/Resources/Finder.icns" buttons {"OK"} default button {"OK"}' & 254 | else 255 | /usr/bin/osascript -e 'display dialog "Failed enabling remote support." with title "Computer Information" with icon file posix file "/System/Library/CoreServices/Finder.app/Contents/Resources/Finder.icns" buttons {"OK"} default button {"OK"}' & 256 | fi 257 | 258 | fi 259 | 260 | 261 | exit 0 -------------------------------------------------------------------------------- /DeleteCasperRemotePolicies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: October 26, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: each run of Casper Remote generates a new policy that's 15 | # stored in the Jamf Pro server. However, those policies are not visible and 16 | # the server has no means to allow administrators to delete them. This 17 | # script identifies all Jamf Pro policies with names in the format: 18 | # '2013-08-07 at 4:18 PM | jsanchez | 1 Computer' 19 | # and deletes them. 20 | # 21 | # The script creates a log file in the same folder as the script. 22 | # 23 | # Except where otherwise noted, this work is licensed under 24 | # http://creativecommons.org/licenses/by/4.0/ 25 | # 26 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 27 | 28 | # INSTRUCTIONS 29 | 30 | # 1) Modify URL, userName and password below to access your Jamf Pro server. 31 | # 2) Save and run this script via Terminal or an editor with a "run script" feature. 32 | # 3) Verify policies in your Jamf Pro server or by appending /api to your Jamf Pro URL. 33 | 34 | URL="https://jamfpro.talkingmoose.net:8443" 35 | userName="API-Editor" 36 | password="password" 37 | 38 | # create the output directory and log file 39 | # in the same directory as this script 40 | 41 | # path to this script 42 | currentDirectory=$( /usr/bin/dirname "$0" ) 43 | 44 | # name of this script 45 | CURRENTSCRIPT=$( /usr/bin/basename -s .sh "$0" ) 46 | 47 | # create log file in same directory as script 48 | logFile="$currentDirectory/$CURRENTSCRIPT - $( /bin/date '+%y-%m-%d' ).log" 49 | 50 | # functions 51 | function logresult() { 52 | if [ $? = 0 ] ; then 53 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 54 | else 55 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 56 | fi 57 | } 58 | 59 | # the time right now 60 | startTime=$( /bin/date '+%s' ) 61 | 62 | # start the log 63 | logresult "--------------------- Begin Script ---------------------" 64 | 65 | # get list of existing policies in the Jamf Pro server 66 | 67 | policyXML=$( /usr/bin/curl -k $URL/JSSResource/policies --user "$userName:$password" -H "Accept: text/xml" -X GET | /usr/bin/xmllint --format - ) 68 | 69 | logresult "Reading policy XML." "Failed to read policy XML." 70 | 71 | # create a list of IDs to delete 72 | idList=$( echo "$policyXML" | /usr/bin/egrep -B1 '[0-9]+-[0-9]{2}-[0-9]{2} at [0-9]{1,2}:[0-9]{2,2} [AP]M \| .* \| .*' | /usr/bin/grep '' | /usr/bin/awk -F '[><]' '{print $3}' ) 73 | 74 | while IFS= read aLine 75 | do 76 | /usr/bin/curl -k "$URL/JSSResource/policies/id/$aLine" --user "$userName:$password" -X DELETE 77 | 78 | logresult "Deleted ID \"$aLine\"." "Failed to delete ID \"$aLine\"." 79 | 80 | idCount=$((idCount+1)) 81 | 82 | done <<< "$idList" 83 | 84 | # stop the timer 85 | # calculate how long the script ran 86 | 87 | logresult "Completing script." 88 | logresult "Processed $idCount policies." 89 | 90 | # the time right now 91 | stopTime=$( /bin/date '+%s' ) 92 | 93 | # subtract start time from stop time and log the time in seconds 94 | DIFF=$(($stopTime-$startTime)) 95 | logresult "Script operations took $DIFF seconds to complete." 96 | 97 | logresult "---------------------- End Script ---------------------- 98 | 99 | " 100 | 101 | exit 0 102 | -------------------------------------------------------------------------------- /DeletedLocalUsers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | < Computer Management 28 | > Scripts. 29 | 3) Click the " + " button to create a new script with these settings: 30 | Display Name: Office 2016 License 31 | Category: 32 | Notes: Deletes local non-mobile and non-Active Directory user accounts. 33 | Script: < Copy and paste this entire script > 34 | 4) Save the script. 35 | 5) Add the script to a policy or run using Casper Remote. 36 | 6) Consult the Jamf Pro policy log for results of the script. 37 | 38 | ----------------------------------------------------------------------- 39 | ABOUT_THIS_SCRIPT 40 | 41 | # EDIT LIST: local user accounts to keep, separating them with a space 42 | keepUsers="talkingmoose mmoose" 43 | echo "Keeping users: $keepUsers." 44 | 45 | # get currently logged in user 46 | # cannot delete an active user 47 | currentUser=$( /usr/bin/stat -f "%Su" /dev/console ) 48 | echo "Currently logged in user: $currentUser." 49 | 50 | # create a list of local usernames (non-AD) with UIDs between 500 and 1024 51 | userList=$( /usr/bin/dscl /Local/Default -list /Users uid | /usr/bin/awk '$2 >= 501 && $2 <= 1024 { print $1 }' ) 52 | echo "Local non-AD users with UIDs between 500 and 1024:\n$userList" 53 | 54 | while IFS= read aUser 55 | do 56 | 57 | # checks to see if an O365 subscription license file is present for each user 58 | if [[ "$keepUsers" != *"$aUser"* && "$aUser" != "$currentUser" ]] ; then 59 | /usr/bin/dscl . delete "/Users/$aUser" # comment this line to get results of the script without making changes 60 | echo "Deleted user: $aUser." 61 | fi 62 | done <<< "$userList" 63 | 64 | exit 0 65 | -------------------------------------------------------------------------------- /DownloadBuildingsList.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: July 9, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Downloads a list of buildings from your Jamf Pro server and 15 | # saves the list in a buildingsList.txt file. When used with 16 | # UploadBuildingsList.sh, a Jamf Pro administrator can start with a list from 17 | # an old Jamf Pro server, clean up the text and then upload the text to 18 | # another Jamf Pro server. 19 | # 20 | # The script creates a log file in the same folder as the script. 21 | # 22 | # Except where otherwise noted, this work is licensed under 23 | # http://creativecommons.org/licenses/by/4.0/ 24 | # 25 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 26 | 27 | # INSTRUCTIONS 28 | 29 | # 1) Modify URL, userName and passWord below to access your Jamf Pro server. 30 | # 2) Save and run this script via Terminal or an editor with a "run script" feature. 31 | # 3) Review the "buildingsList.txt" file in the JSS_Output folder. 32 | 33 | URL="https://jamfpro.talkingmoose.net:8443" 34 | userName="API-Auditor" 35 | passWord="password" 36 | 37 | # define the output directory and log file 38 | # in the same directory as this script 39 | 40 | # path to this script 41 | currentDirectory=$( /usr/bin/dirname "$0" ) 42 | 43 | # name of this script 44 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 45 | 46 | # set the JSS_Output directory in the same directory as script 47 | outputDirectory="$currentDirectory/JSS_Output" 48 | 49 | # set the log file in same directory as script 50 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 51 | 52 | # functions 53 | function logresult() { 54 | if [ $? = 0 ] ; then 55 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 56 | else 57 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 58 | fi 59 | } 60 | 61 | # the time right now 62 | startTime=$( /bin/date '+%s' ) 63 | 64 | # start the log 65 | logresult "--------------------- Begin Script ---------------------" 66 | 67 | # create the output directory if necessary 68 | /bin/mkdir -p "$outputDirectory" 69 | logresult "Created $outputDirectory directory." "Failed creating $outputDirectory directory or it already exists." 70 | 71 | # download building XML file from Jamf Pro server 72 | buildingXML=$( /usr/bin/curl -k $URL/JSSResource/buildings --user "$userName:$passWord" -H "Accept: text/xml" -X GET | /usr/bin/xmllint --format - ) 73 | 74 | logresult "Downloaded building XML information." "Failed downloading building XML information." 75 | 76 | # parse the list for just building names 77 | buildingsList=$( /bin/echo "$buildingXML" | /usr/bin/perl -lne 'BEGIN{undef $/} while (/(.*?)<\/name>/sg){print $1}' ) 78 | 79 | logresult "Parsed building XML information for building names." "Failed parsing building XML information for building names." 80 | 81 | # write the list to the output file 82 | echo "$buildingsList" > "$outputDirectory/buildingsList.txt" 83 | 84 | logresult "Wrote building information to JSS_Output directory." "Failed to write building information to JSS_Output directory." 85 | 86 | # count the buildings 87 | buildingCount=$( echo "$buildingsList" | /usr/bin/grep -c ^ ) 88 | 89 | logresult "Counted number of buildings." "Failed to count number of buildings." 90 | 91 | # stop the timer 92 | # calculate how long the script ran 93 | 94 | logresult "Completing script." 95 | logresult "Listed $buildingCount buildings." 96 | 97 | # the time right now 98 | stopTime=$( /bin/date '+%s' ) 99 | 100 | # subtract start time from stop time and log the time in seconds 101 | DIFF=$(($stopTime-$startTime)) 102 | logresult "Script operations took $DIFF seconds to complete." 103 | 104 | logresult "---------------------- End Script ---------------------- 105 | 106 | " 107 | 108 | exit 0 109 | -------------------------------------------------------------------------------- /DownloadNetworkSegments.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: July 9, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Downloads each network segment from your Jamf Pro server and 15 | # saves it as an XML file in the JSS_Output directory. When used with 16 | # UploadNetworkSegments.sh, a Jamf Pro administrator can start with a list 17 | # from an old Jamf Pro server, delete unwanted network segment files and 18 | # then upload the remaining files to another Jamf Pro server. 19 | # 20 | # The script creates a log file in the same folder as the script. 21 | # 22 | # Except where otherwise noted, this work is licensed under 23 | # http://creativecommons.org/licenses/by/4.0/ 24 | # 25 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 26 | 27 | # INSTRUCTIONS 28 | 29 | # 1) Modify URL, userName and passWord below to access your source Jamf Pro server. 30 | # 2) Save and run this script via Terminal or an editor with a "run script" feature. 31 | # 3) Review the XML files in the JSS_Output folder and Trash any you do not wish to upload to your destination Jamf Pro server. 32 | # 4) Run the UploadNetworkSegments.sh script to populate your destination Jamf Pro server. 33 | 34 | URL="https://jamfpro.talkingmoose.net:8443" 35 | userName="API-Auditor" 36 | passWord="password" 37 | 38 | # define the output directory and log file 39 | # in the same directory as this script 40 | 41 | # path to this script 42 | currentDirectory=$( /usr/bin/dirname "$0" ) 43 | 44 | # name of this script 45 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 46 | 47 | # set the JSS_Output directory in the same directory as script 48 | outputDirectory="$currentDirectory/JSS_Output" 49 | 50 | # set the log file in same directory as script 51 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 52 | 53 | # functions 54 | function logresult() { 55 | if [ $? = 0 ] ; then 56 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 57 | else 58 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 59 | fi 60 | } 61 | 62 | # the time right now 63 | startTime=$( /bin/date '+%s' ) 64 | 65 | # start the log 66 | logresult "--------------------- Begin Script ---------------------" 67 | 68 | # create a working directory on the desktop 69 | if [ -d "$outputDirectory" ] ; then 70 | 71 | /bin/rm -R "$outputDirectory" 72 | logresult "Removed old $outputDirectory directory." "Failed removing old $outputDirectory directory." 73 | 74 | /bin/mkdir -p "$outputDirectory" 75 | logresult "Created new $outputDirectory directory." "Failed creating new $outputDirectory directory." 76 | 77 | else 78 | /bin/mkdir -p "$outputDirectory" 79 | logresult "Created $outputDirectory directory." "Failed creating $outputDirectory directory." 80 | fi 81 | 82 | # download a list of network segment IDs 83 | nsIDs=$( /usr/bin/curl -k $URL/JSSResource/networksegments --user "$userName:$passWord" -H "Accept: text/xml" -X GET | /usr/bin/perl -lne 'BEGIN{undef $/} while (/(.*?)<\/id>/sg){print $1}' ) 84 | 85 | logresult "Created Network Segments ID list." "Failed to create Network Segments ID list." 86 | 87 | # download XML for each network segment and prepare for upload 88 | while IFS= read aLine 89 | do 90 | # get the full XML for a network segment 91 | ITEMXML=$( /usr/bin/curl -k $URL/JSSResource/networksegments/id/$aLine --user "$userName:$passWord" -H "Accept: text/xml" -X GET | /usr/bin/xmllint --format - ) 92 | 93 | nsName=$( echo "$ITEMXML" | /usr/bin/awk -F "[><]" '/name/{print $3;exit}' ) 94 | 95 | logresult "Retrieved XML for network segment \"$nsName\"." "Failed to retrieve XML for network segment \"$nsName\"." 96 | 97 | # modify the returned XML and write to a file 98 | echo "$ITEMXML" > "$outputDirectory/$nsName.xml" 99 | 100 | logresult "Created XML file for network segment \"$nsName\"." "Failed to create XML file for network segment \"$nsName\"." 101 | 102 | downLoad=$((downLoad+1)) 103 | 104 | done <<< "$nsIDs" 105 | 106 | # stop the timer 107 | # calculate how long the script ran 108 | 109 | logresult "Completing script." 110 | logresult "Processed $downLoad network segments." 111 | 112 | # the time right now 113 | stopTime=$( /bin/date '+%s' ) 114 | 115 | # subtract start time from stop time and log the time in seconds 116 | DIFF=$(($stopTime-$startTime)) 117 | logresult "Script operations took $DIFF seconds to complete." 118 | 119 | logresult "---------------------- End Script ---------------------- 120 | 121 | " 122 | 123 | exit 0 -------------------------------------------------------------------------------- /List Mobile Device Apps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | <> "$logFile" 56 | else 57 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 58 | fi 59 | } 60 | 61 | # the time right now 62 | startTime=$( /bin/date '+%s' ) 63 | 64 | # start the log 65 | logresult "--------------------- Begin Script ---------------------" 66 | 67 | # create a working directory 68 | if [ -d "$outputDirectory" ] ; then 69 | 70 | /bin/rm -R "$outputDirectory" 71 | logresult "Removed old $outputDirectory directory." "Failed removing old $outputDirectory directory." 72 | 73 | /bin/mkdir -p "$outputDirectory" 74 | logresult "Created new $outputDirectory directory." "Failed creating new $outputDirectory directory." 75 | 76 | else 77 | /bin/mkdir -p "$outputDirectory" 78 | logresult "Created $outputDirectory directory." "Failed creating $outputDirectory directory." 79 | fi 80 | 81 | # download a list of mobile device app IDs 82 | appIDs=$( /usr/bin/curl -ks $URL/JSSResource/mobiledeviceapplications --user "$userName:$password" -H "Accept: text/xml" -X GET | /usr/bin/xmllint --format - | /usr/bin/grep "" | /usr/bin/awk -F "(|)" '{ print $2 }' | /usr/bin/sort ) 83 | logresult "Created mobile apps ID list." "Failed to create mobile apps ID list." 84 | 85 | # download XML for each mobile device app 86 | while IFS= read aLine 87 | do 88 | # get the full XML for a mobile app 89 | /usr/bin/curl -ks $URL/JSSResource/mobiledeviceapplications/id/$aLine --user "$userName:$password" -H "Accept: text/xml" -X GET > "$outputDirectory/$aLine.xml" 90 | logresult "Retrieving XML for mobile device app ID $aLine." "Failed retrieving XML for mobile device app ID $aLine." 91 | 92 | # write the XML to a file and rename the file to the mobile device app name 93 | appName=$( /usr/bin/xmllint --xpath 'string(/mobile_device_application/general/name)' "$outputDirectory/$aLine.xml" ) 94 | 95 | # remove any colons, forward slashes and back slashes from the object's name 96 | cleanedName=$( echo "$appName" | /usr/bin/sed 's/[:\/\\]//g' ) 97 | 98 | /bin/mv "$outputDirectory/$aLine.xml" "$outputDirectory/$cleanedName.xml" 99 | logresult "Name for mobile device app ID $aLine is \"$cleanedName\"." "Failed reading name for mobile device app ID $aLine." 100 | 101 | done <<< "$appIDs" 102 | 103 | # get a list of the XML files 104 | xmlFiles=$( /bin/ls "$outputDirectory" ) 105 | 106 | # process each XML file 107 | while IFS= read aFile 108 | do 109 | # get a list of scopes from the XML file 110 | appScopes=$( /usr/bin/xmllint --xpath '/mobile_device_application/scope/*/*/name' "$outputDirectory/$aFile" | /usr/bin/perl -00pe 's/<\/name>/\n/g' | /usr/bin/sed 's/// ; s/<\/name>//' ) 111 | 112 | # start a file for each scope if necessary 113 | while IFS= read aScope 114 | do 115 | if [ "$aScope" = "" ] ; then 116 | aScope="All Mobile Devices" 117 | fi 118 | 119 | if [[ ! -f "$outputDirectory/$aScope.js" ]] ; then 120 | # begin js file 121 | echo "getData( 122 | { 123 | \"mobile_device_applications\": {" > "$outputDirectory/$aScope.js" 124 | logresult "Creating file \"$aScope.js\"." "Failed creating file \"$aScope.js\"." 125 | fi 126 | 127 | # begin new mobile device application 128 | /bin/echo " \"mobile_device_application\": {" >> "$outputDirectory/$aScope.js" 129 | logresult "Starting mobile device application record in file \"$aScope\"." "Failed starting mobile device application record in file \"$aScope\"." 130 | 131 | # write mobile device application category to js file 132 | appCategory=$( /usr/bin/xmllint --xpath 'string(/mobile_device_application/general/category/name)' "$outputDirectory/$aFile" ) 133 | /bin/echo " \"category\": \"$appCategory\"," >> "$outputDirectory/$aScope.js" 134 | logresult "Adding category \"$appCategory\" to mobile device application record \"$appName\" in file \"$aScope\"." "Failed adding category \"$appCategory\" to mobile device application record \"$appName\" in file \"$aScope\"." 135 | 136 | # write mobile device application URL to js file 137 | appURL=$( /usr/bin/xmllint --xpath 'string(/mobile_device_application/general/itunes_store_url)' "$outputDirectory/$aFile" ) 138 | /bin/echo " \"itunes_store_url\": \"$appURL\"," >> "$outputDirectory/$aScope.js" 139 | logresult "Adding URL \"$appURL\" to mobile device application record \"$appName\" in file \"$aScope\"." "Failed adding URL \"$appURL\" to mobile device application record \"$appName\" in file \"$aScope\"." 140 | 141 | # write mobile device application name to js file - no comma 142 | appName=$( /usr/bin/xmllint --xpath 'string(/mobile_device_application/general/name)' "$outputDirectory/$aFile" ) 143 | /bin/echo " \"name\": \"$appName\"" >> "$outputDirectory/$aScope.js" 144 | logresult "Adding name \"$appName\" to mobile device application record \"$appName\" in file \"$aScope\"." "Failed adding name \"$appName\" to mobile device application record \"$appName\" in file \"$aScope\"." 145 | 146 | # end new mobile device application 147 | /bin/echo " }" >> "$outputDirectory/$aScope.js" 148 | logresult "Ending mobile device application record in file \"$aScope\"." "Failed ending mobile device application record in file \"$aScope\"." 149 | 150 | done <<< "$appScopes" 151 | 152 | # count each XML file for the log 153 | appCount=$((appCount+1)) 154 | 155 | done <<< "$xmlFiles" 156 | 157 | # get a list of js files 158 | jsFiles=$( /bin/ls -1 "$outputDirectory/"*.js ) 159 | 160 | # write closing informaiton to each js file 161 | while IFS= read aFile 162 | do 163 | /bin/echo "});" >> "$aFile" 164 | logresult "Completing js file \"$aFile\"." "Failed completing js file \"$aFile\"." 165 | done <<< "$jsFiles" 166 | 167 | # delete working XML files 168 | /bin/rm -R "$outputDirectory"/*.xml 169 | logresult "Deleting working XML files." "Failed deleting working XML files." 170 | 171 | # delete unwanted js files 172 | /usr/bin/find "$outputDirectory" ! -name "_All Student 1 to 1 iPads.js" ! -name "All Cart Based iPads - DEP.js" ! -name "*.xml" -delete 173 | logresult "Deleting unwanted js files." "Failed deleting unwanted js files." 174 | 175 | # stop the timer 176 | # calculate how long the script ran 177 | 178 | logresult "Completing script." 179 | logresult "Processed $appCount apps." 180 | 181 | # the time right now 182 | stopTime=$( /bin/date '+%s' ) 183 | 184 | # subtract start time from stop time and log the time in seconds 185 | duration=$(($stopTime-$startTime)) 186 | logresult "Script operations took $duration seconds to complete." 187 | 188 | logresult "---------------------- End Script ---------------------- 189 | 190 | " 191 | 192 | exit 0 -------------------------------------------------------------------------------- /PopulateMobileDeviceAssetTags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: April 21, 2015 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Searches a Jamf Pro server for mobile device assets 15 | # with empty Asset Tag fields and populates those fields from lists 16 | # provided by Apple. Script relies on the Jamf Pro Classic API. Requires 17 | # a text file of device serial numbers and asset tags in the format 18 | # "SerialNumber > tab > AssetTag > return" and named FullList.txt in 19 | # the same directory as the script. 20 | # 21 | # The script creates a log file in the same folder as the script. 22 | # 23 | # Except where otherwise noted, this work is licensed under 24 | # http://creativecommons.org/licenses/by/4.0/ 25 | # 26 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 27 | 28 | 29 | #################################### 30 | # start the timer 31 | #################################### 32 | 33 | 34 | # the time right now 35 | startTime=$( /bin/date '+%s' ) 36 | 37 | 38 | #################################### 39 | # Jamf Pro URL and credentials 40 | #################################### 41 | 42 | 43 | URL="https://jamfpro.domain.com:8443" 44 | userName="API-Editor" 45 | passWord="password" 46 | 47 | 48 | #################################### 49 | # File locations 50 | #################################### 51 | 52 | 53 | # path to this script 54 | currentDirectory=$( /usr/bin/dirname "$0" ) 55 | 56 | # name of this script 57 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 58 | 59 | # set the log file in same directory as script 60 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 61 | 62 | # store Apple-provided spreadsheets file in same directory as script 63 | fullList=$( /bin/cat "$currentDirectory/FullList.txt" ) 64 | 65 | 66 | #################################### 67 | # Functions 68 | #################################### 69 | 70 | 71 | function stripreturns() { 72 | stripped=$( /bin/echo $1 | /usr/bin/xmllint --noblanks - ) 73 | /bin/echo $stripped 74 | } 75 | 76 | 77 | function logresult() { 78 | if [ $? = 0 ] ; then 79 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 80 | else 81 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 82 | fi 83 | } 84 | 85 | 86 | #################################### 87 | # Create list of computer 88 | # serial numbers without asset tags 89 | #################################### 90 | 91 | 92 | # start the log 93 | logresult "--------------------- Begin Script ---------------------" 94 | 95 | # rotate logs -- delete all but the five most recent log files 96 | deleteOldLogs=$( /bin/ls -1t "$currentDirectory/$currentScript"*.log | /usr/bin/tail -n +6 ) 97 | 98 | while IFS= read -r aLine 99 | do 100 | logFileName=$( /usr/bin/basename "$aLine" ) 101 | /bin/rm "$aLine" 102 | logresult "Deleting old log file: $logFileName." 103 | done <<< "$deleteOldLogs" 104 | 105 | # creating a list of computers without asset tags 106 | logresult "Gathering list of computers without asset tags." 107 | 108 | # human-readable POST XML for a new search 109 | TEHxml=" 110 | Mobile Devices with no asset tags as of $( /bin/date ) 111 | 112 | 113 | Asset Tag 114 | 0 115 | and 116 | is 117 | 118 | 119 | 120 | 121 | 122 | Serial Number 123 | 124 | 125 | " 126 | 127 | # this strips the returns before POSTing the XML 128 | POSTxml=$( stripreturns "$TEHxml" ) 129 | 130 | # create a temporary advanced computer search in the Jamf Pro server using the criteria in the POST XML above 131 | createSearch=$( /usr/bin/curl -k -s 0 $URL/JSSResource/advancedmobiledevicesearches/id/0 --user "$userName:$passWord" -H "Content-Type: text/xml" -X POST -d "$POSTxml" ) 132 | 133 | # log the result 134 | logresult "Created temporary Advanced Mobile Device Search in Jamf Pro at $URL." "Failed creating temporary Advanced Mobile Device Search in Jamf Pro at $URL." 135 | 136 | # get temporary advanced computer search ID 137 | searchID=$( /bin/echo $createSearch | /usr/bin/awk -F "|" '{ print $2 }' ) 138 | 139 | # run the search and return serial numbers 140 | search=$( /usr/bin/curl -k -s 0 $URL/JSSResource/advancedmobiledevicesearches/id/$searchID --user "$userName:$passWord" -H "Accept: text/xml" -X GET ) 141 | 142 | # turn the returned list into a list of just serial numbers 143 | serialNumberList=$( /bin/echo "$search" | /usr/bin/perl -lne 'BEGIN{undef $/} while (/(.*?)<\/Serial_Number>/sg){print $1}' ) 144 | 145 | # count the serial numbers and log the results 146 | serialNumberCount=$( /bin/echo $serialNumberList | /usr/bin/wc -w ) 147 | serialNumberCount=$( stripreturns "$serialNumberCount" ) 148 | 149 | # log the result 150 | logresult "Found $serialNumberCount mobile devices without asset tags." "Failed finding mobile devices without asset tags." 151 | 152 | # delete the temporary advanced computer search 153 | /usr/bin/curl -k -s 0 $URL/JSSResource/advancedmobiledevicesearches/id/$searchID --user "$userName:$passWord" -X DELETE 154 | 155 | # log the result 156 | logresult "Deleted temporary Advanced Mobile Device Search." "Failed deleting temporary Advanced Computer Search." 157 | 158 | 159 | #################################### 160 | # Compare Apple's list of serial 161 | # numbers with the found list of 162 | # serial numbers. Populate asset 163 | # tags for serial numbers that 164 | # have no asset tag. 165 | #################################### 166 | 167 | for aLine in $serialNumberList 168 | do 169 | matchedDevice=$( echo "$fullList" | grep "$aLine" ) 170 | 171 | if [ "$matchedDevice" = "" ] ; then 172 | # log the result 173 | logresult "Serial number $aLine not found in the spreadsheet from Apple." 174 | else 175 | serialNumber=$( /bin/echo "$matchedDevice" | /usr/bin/awk '{ print $1 }' ) 176 | assetTag=$( /bin/echo "$matchedDevice" | /usr/bin/awk '{ print $2 }' ) 177 | 178 | THExml=" 179 | 180 | $assetTag 181 | 182 | " 183 | 184 | PUTxml=$( stripreturns "$THExml" ) 185 | 186 | /usr/bin/curl -k 0 $URL/JSSResource/mobiledevices/serialnumber/$serialNumber --user "$userName:$passWord" -H "Content-Type: text/xml" -X PUT -d "$PUTxml" 187 | 188 | # log the result 189 | logresult "Added asset tag $assetTag to mobile device with serial number $serialNumber." "Failed to add asset tag $assetTag to mobile device with serial number $serialNumber." 190 | 191 | # keep count of populated asset tags 192 | matched=$((matched+1)) 193 | fi 194 | 195 | done 196 | 197 | 198 | #################################### 199 | # stop the timer 200 | # calculate how long the script ran 201 | #################################### 202 | 203 | 204 | logresult "Completing script." 205 | logresult "Populated $matched asset tags of $serialNumberCount mobile devices without asset tags." 206 | 207 | # the time right now 208 | stopTime=$( /bin/date '+%s' ) 209 | 210 | # subtract start time from stop time and log the time in seconds 211 | DIFF=$(($stopTime-$startTime)) 212 | logresult "Script operations took $DIFF seconds to complete." 213 | 214 | 215 | logresult "---------------------- End Script ---------------------- 216 | 217 | " 218 | 219 | exit 0 220 | -------------------------------------------------------------------------------- /Precreate Jamf Computer Record/Precreate Jamf Computer Record List.txt: -------------------------------------------------------------------------------- 1 | VM2lzmpdAiHa1 00:50:56:23:58:12 None 2 | VM2lzmpdAiHa2 00:50:56:23:58:13 John Glenn Elementary School 3 | VM2lzmpdAiHa3 00:50:56:23:58:14 Carver Elementary School 4 | VM2lzmpdAiHa4 00:50:56:23:58:15 Greenbriar Elementary School 5 | VM2lzmpdAiHa5 00:50:56:23:58:16 None -------------------------------------------------------------------------------- /Precreate Jamf Computer Record/Precreate Jamf Computer Record.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | <> "$logFile" 56 | else 57 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 58 | fi 59 | } 60 | 61 | # the time right now 62 | startTime=$( /bin/date '+%s' ) 63 | 64 | # start the log 65 | logresult "--------------------- Begin Script ---------------------" 66 | 67 | # read the list of computers 68 | computersList=$( /bin/cat "Precreate Jamf Computer Record List.txt" ) 69 | logresult "Reading computer record list." "Failed to read computer record list." 70 | 71 | # precreate computers, one at a time 72 | while IFS= read aComputer 73 | do 74 | # parse the computer's information 75 | serialNumber=$( echo "$aComputer" | /usr/bin/awk -F \t '{ print $1 }' ) 76 | macAddress=$( echo "$aComputer" | /usr/bin/awk -F \t '{ print $2 }' ) 77 | site=$( echo "$aComputer" | /usr/bin/awk -F \t '{ print $3 }' ) 78 | 79 | # create XML to upload 80 | theXML="$serialNumber$macAddress$serialNumber$site" 81 | 82 | # upload the XML to create a new computer record 83 | /usr/bin/curl -k $uRL/JSSResource/computers --user "$username:$password" -H "Content-Type: text/xml" -X POST -d "$theXML" 84 | logresult "Processing computer: $serialNumber." "Failed to process computer: $serialNumber." 85 | 86 | # keep count of processed records 87 | uploadCount=$((uploadCount+1)) 88 | 89 | done <<< "$computersList" 90 | 91 | # stop the timer 92 | # calculate how long the script ran 93 | 94 | logresult "Completing script." 95 | logresult "Processed $uploadCount computers." 96 | 97 | # the time right now 98 | stopTime=$( /bin/date '+%s' ) 99 | 100 | # subtract start time from stop time and log the time in seconds 101 | diff=$(($stopTime-$startTime)) 102 | logresult "Script operations took $diff seconds to complete." 103 | 104 | logresult "---------------------- End Script ---------------------- 105 | 106 | " 107 | 108 | exit 0 109 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Jamf Scripts 2 | bill@talkingmoose.net 3 | 4 | 5 | Purpose 6 | 7 | These are a random set of scripts I've made for customers to work with Jamf Pro. They are some examples for accessing a Jamf Pro server to download, upload or modify data as well as other functions. 8 | 9 | 10 | Support 11 | 12 | Jamf does not support these scripts. Please do not contact them for assistance. Contact Jamf if you need a custom script tailored to your environment. 13 | 14 | For basic Jamf Pro Classic API documentation, use a web browser to access the API page on your server at: 15 | https://server.yourdomain.com:8443/api or 16 | https://yourinstance.jamfcloud.com/api 17 | 18 | 19 | License 20 | 21 | This work is licensed under http://creativecommons.org/licenses/by/4.0/. 22 | 23 | These scripts may be freely modified for personal or commercial purposes but may not be republished for profit without prior consent. -------------------------------------------------------------------------------- /Rename Buildings/RenameBuildings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: July 9, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Reads a tab-delimited file (requires UNIX line-endings) 15 | # to get the name of a building in a Jamf Pro server and rename it. This 16 | # lets an administrator rename inconsistently named buildings to a consistent 17 | # format. Because buildings are referenced in other parts of the Jamf Pro 18 | # server by ID rather than name, renaming buildings does not affect existing 19 | # functionality. 20 | # 21 | # The script creates a log file in the same folder as the script. 22 | # 23 | # Except where otherwise noted, this work is licensed under 24 | # http://creativecommons.org/licenses/by/4.0/ 25 | # 26 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 27 | 28 | # INSTRUCTIONS 29 | 30 | # 1) Modify URL, userName and passWord below to access your Jamf Pro server. 31 | # 2) Edit the RenameBuildingsList.tab file. 32 | # One set of names per line in the format: 33 | # Old building name _tab_ New building name 34 | # Use a quality text editor such as BBEdit or TextWranlger to save the file with Unix line endings. 35 | # 3) Place the RenameBuildingsList.tab file in the same directory as this script. 36 | # 4) Run this script via Terminal or an editor with a "run script" feature. 37 | # 5) Verify buildings in your Jamf Pro server. 38 | 39 | # the time right now 40 | startTime=$( /bin/date '+%s' ) 41 | 42 | URL="https://jamfpro.talkingmoose.net:8443" 43 | userName="API-Editor" 44 | passWord="password" 45 | 46 | # create the output directory and log file 47 | # in the same directory as this script 48 | 49 | # path to this script 50 | currentDirectory=$( /usr/bin/dirname "$0" ) 51 | 52 | # name of this script 53 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 54 | 55 | # create log file in same directory as script 56 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 57 | 58 | # functions 59 | function logresult() { 60 | if [ $? = 0 ] ; then 61 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 62 | else 63 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 64 | fi 65 | } 66 | 67 | # the time right now 68 | startTime=$( /bin/date '+%s' ) 69 | 70 | # start the log 71 | logresult "--------------------- Begin Script ---------------------" 72 | 73 | renameBuildingsList=$( cat "$currentDirectory/RenameBuildingsList.tab" ) 74 | 75 | # verify the working directory on the desktop 76 | if [ ! -f "$currentDirectory/RenameBuildingsList.tab" ] ; then 77 | echo "File \"$currentDirectory/RenameBuildingsList.tab\" does not exist. Fix this path first." 78 | logresult "File \"$currentDirectory/RenameBuildingsList.tab\" does not exist. Fix this path first." 79 | exit 0 80 | fi 81 | 82 | while IFS= read aLine 83 | do 84 | oldBuilding=$( echo "$aLine" | awk -F \t '{print $1}' ) 85 | newBuilding=$( echo "$aLine" | awk -F \t '{print $2}' ) 86 | converted=${oldBuilding// /%20} 87 | putXML="$newBuilding" 88 | 89 | /usr/bin/curl -k $URL/JSSResource/buildings/name/$converted --user "$userName:$passWord" -H "Content-Type: text/xml" -X PUT -d "$putXML" 90 | 91 | logresult "Renamed building \"$oldBuilding\" to \"$newBuilding\"" "Failed renaming \"$oldBuilding\" to \"$newBuilding\"" 92 | 93 | buildingCount=$((buildingCount+1)) 94 | 95 | done <<< "$renameBuildingsList" 96 | 97 | # stop the timer 98 | # calculate how long the script ran 99 | 100 | logresult "Completing script." 101 | logresult "Processed $buildingCount building name changes." 102 | 103 | # the time right now 104 | stopTime=$( /bin/date '+%s' ) 105 | 106 | # subtract start time from stop time and log the time in seconds 107 | DIFF=$(($stopTime-$startTime)) 108 | logresult "Script operations took $DIFF seconds to complete." 109 | 110 | logresult "---------------------- End Script ---------------------- 111 | 112 | " 113 | 114 | exit 0 115 | -------------------------------------------------------------------------------- /Rename Buildings/RenameBuildingsList.tab: -------------------------------------------------------------------------------- 1 | Dome of the Rock 01 Dome of the Rock 2 | La Pedrera 02 La Pedrera 3 | One World Trade Center 03 One World Trade Center 4 | St Paul's Cathedral 04 St Paul's Cathedral 5 | Petronas Towers 05 Petronas Towers 6 | The White House 06 The White House 7 | Leaning Tower of Pisa 07 Leaning Tower of Pisa 8 | The Kaaba 08 The Kaaba 9 | The Shard 09 The Shard 10 | St Basil's Cathedral 10 St Basil's Cathedral 11 | Colosseum 11 Colosseum 12 | Taj Mahal 12 Taj Mahal 13 | Sydney Opera House 13 Sydney Opera House 14 | Space Needle 14 Space Needle 15 | Pantheon 15 Pantheon 16 | Turning Torso 16 Turning Torso -------------------------------------------------------------------------------- /ReportOfficeLicense.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | < Computer Management > Extension Attributes. 32 | 3) Click the " + " button to create a new extension attribute with these settings: 33 | Display Name: Microsoft Office for Mac License 34 | Description: Reports Microsoft Office for Mac licenses in use. 35 | Data Type: String 36 | Inventory Display: Extension Attributes 37 | Input Type: Script 38 | Script: < Copy and paste this entire script > 39 | 4) Save the extension attribute. 40 | 5) Use Recon.app or "sudo jamf recon" to inventory a Mac with Office 2016 or 2019. 41 | 6) View the results under the Extension Attributes payload 42 | of the computer's record or include the extension attribute 43 | when adding criteria to an Advanced Computer Search or Smart Group. 44 | 45 | ----------------------------------------------------------------------- 46 | ABOUT_THIS_SCRIPT 47 | 48 | 49 | # Functions 50 | function DetectPerpetualLicense { 51 | perpetualLicense="/Library/Preferences/com.microsoft.office.licensingV2.plist" 52 | 53 | # checks to see if a perpetual license file is present and what kind 54 | if [[ $( /bin/cat "$perpetualLicense" | grep "A7vRjN2l/dCJHZOm8LKan11/zCYPCRpyChB6lOrgfi" ) ]]; then 55 | echo "Office 2019 Volume" 56 | elif [[ $( /bin/cat "$perpetualLicense" | grep "Bozo+MzVxzFzbIo+hhzTl4JKv18WeUuUhLXtH0z36s" ) ]]; then 57 | echo "Office 2019 Preview Volume" 58 | elif [[ $( /bin/cat "$perpetualLicense" | grep "A7vRjN2l/dCJHZOm8LKan1Jax2s2f21lEF8Pe11Y+V" ) ]]; then 59 | echo "Office 2016 Volume" 60 | elif [[ $( /bin/cat "$perpetualLicense" | grep "DrL/l9tx4T9MsjKloHI5eX" ) ]]; then 61 | echo "Office 2016 Home and Business" 62 | elif [[ $( /bin/cat "$perpetualLicense" | grep "C8l2E2OeU13/p1FPI6EJAn" ) ]]; then 63 | echo "Office 2016 Home and Student" 64 | elif [[ $( /bin/cat "$perpetualLicense" | grep "Bozo+MzVxzFzbIo+hhzTl4m" ) ]]; then 65 | echo "Office 2019 Home and Business" 66 | elif [[ $( /bin/cat "$perpetualLicense" | grep "Bozo+MzVxzFzbIo+hhzTl4j" ) ]]; then 67 | echo "Office 2019 Home and Student" 68 | else 69 | echo "No" 70 | fi 71 | } 72 | 73 | function DetectO365License { 74 | # creates a list of local usernames with UIDs above 500 (not hidden) 75 | userList=$( /usr/bin/dscl /Local/Default -list /Users uid | /usr/bin/awk '$2 >= 501 { print $1 }' ) 76 | 77 | while IFS= read aUser 78 | do 79 | # get the user's home folder path 80 | homePath=$( eval echo ~$aUser ) 81 | 82 | # list of potential Office 365 activation files 83 | O365SUBMAIN="$homePath/Library/Group Containers/UBF8T346G9.Office/com.microsoft.Office365.plist" 84 | O365SUBBAK1="$homePath/Library/Group Containers/UBF8T346G9.Office/com.microsoft.e0E2OUQxNUY1LTAxOUQtNDQwNS04QkJELTAxQTI5M0JBOTk4O.plist" 85 | O365SUBBAK2="$homePath/Library/Group Containers/UBF8T346G9.Office/e0E2OUQxNUY1LTAxOUQtNDQwNS04QkJELTAxQTI5M0JBOTk4O" # hidden file 86 | O365SUBMAINB="$homePath/Library/Group Containers/UBF8T346G9.Office/com.microsoft.Office365V2.plist" 87 | O365SUBBAK1B="$homePath/Library/Group Containers/UBF8T346G9.Office/com.microsoft.O4kTOBJ0M5ITQxATLEJkQ40SNwQDNtQUOxATL1YUNxQUO2E0e.plist" 88 | O365SUBBAK2B="$homePath/Library/Group Containers/UBF8T346G9.Office/O4kTOBJ0M5ITQxATLEJkQ40SNwQDNtQUOxATL1YUNxQUO2E0e" 89 | 90 | # checks to see if an O365 subscription license file is present for each user 91 | if [[ -f "$O365SUBMAIN" || -f "$O365SUBBAK1" || -f "$O365SUBBAK2" || -f "$O365SUBMAINB" || -f "$O365SUBBAK1B" || -f "$O365SUBBAK2B" ]]; then 92 | activations=$((activations+1)) 93 | fi 94 | done <<< "$userList" 95 | 96 | # returns the number of activations to O365Activations 97 | echo $activations 98 | } 99 | 100 | ## Main 101 | 102 | PLPresent=$(DetectPerpetualLicense) 103 | O365Activations=$(DetectO365License) 104 | 105 | if [ "$PLPresent" != "No" ] && [ "$O365Activations" ]; then 106 | echo "$PLPresent and Office 365 licenses detected. Only the $PLPresent license will be used." 107 | 108 | elif [ "$PLPresent" != "No" ]; then 109 | echo "$PLPresent license" 110 | 111 | elif [ "$O365Activations" ]; then 112 | echo "Office 365 activations: $O365Activations" 113 | 114 | elif [ "$PLPresent" == "No" ] && [ ! "$O365Activations" ]; then 115 | echo "No licenses" 116 | fi 117 | 118 | exit 0 -------------------------------------------------------------------------------- /ReportSIPStatus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: November 20, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Shell script for Jamf Pro Extension Attribute to report SIP status 15 | # as Enabled, Disabled or Not Supported. 16 | # 17 | # Except where otherwise noted, this work is licensed under 18 | # http://creativecommons.org/licenses/by/4.0/ 19 | # 20 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 21 | 22 | # Instructions: 23 | # In the Jamf Pro server, create a new Extension Attribute: 24 | # Display Name: SIP Status 25 | # Description: Report whether System Integrity Protection is Enabled or Disabled. 26 | # Data Type: String 27 | # Inventory Display: Operating System 28 | # Input Type: Script 29 | # Script: Contents of this script 30 | 31 | #!/bin/sh 32 | 33 | # run command to report SIP status 34 | status=$( /usr/bin/csrutil status 2>/dev/null ) 35 | 36 | case "$status" in 37 | 38 | # SIP is enabled 39 | "System Integrity Protection status: enabled.") 40 | echo "Enabled";; 41 | 42 | # SIP is disabled 43 | "System Integrity Protection status: disabled.") 44 | echo "Disabled";; 45 | 46 | # SIP is not supported 47 | "") 48 | echo "Not Supported";; 49 | esac 50 | 51 | exit 0 -------------------------------------------------------------------------------- /Set Time Zone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | <> "$logFile" 81 | else 82 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 83 | fi 84 | } 85 | 86 | # use this icon (Date & Time preference pane icon) in dialogs 87 | dialogIcon="/System/Library/PreferencePanes/DateAndTime.prefPane/Contents/Resources/DateAndTime.icns" 88 | 89 | 90 | # determine whether time zone is set automatically 91 | setAutomatically=$( /usr/bin/defaults read /Library/Preferences/com.apple.timezone.auto Active ) 92 | 93 | if [ "$setAutomatically" = 0 ]; then # time zone is set manually, offer to set it automatically 94 | 95 | logresult "Time zone is set manually." "Time zone is set automatically." 96 | 97 | userResponse=$( /usr/bin/osascript -e "button returned of (display dialog \"Your Mac's time zone was manually set to $( date +%Z ). Would you like to try automatically setting it?\" buttons {\"Manual\", \"Automatic\"} default button {\"Automatic\"} with title \"Set Time Zone\" with icon file POSIX file \"$dialogIcon\")" ) 98 | 99 | else 100 | 101 | logresult "Time zone is set manually." "Time zone is set automatically." 102 | 103 | fi 104 | 105 | 106 | if [ "$userResponse" = "Automatic" ]; then # set the time zone to update automatically 107 | 108 | logresult "User has chosen to set time zone automatically." 109 | 110 | # modify the time zone plist to update automatically 111 | /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool TRUE 112 | logresult "Setting time zone automatically." "Failed setting time zone automatically." 113 | 114 | # open the date & time system preference for the user to verify settings 115 | # this is a workaround to force the Mac to update settings after changing the plist 116 | /usr/bin/open "/System/Library/PreferencePanes/DateAndTime.prefPane" 117 | 118 | /bin/sleep 2 # allow time to change settings 119 | 120 | # notify the user time zone is set to update automatically 121 | theCommand="display dialog \"Your system is now set to $( date +%Z ) timezone. Opening the Time Zone preference pane for you to verify settings.\" with title \"Set Time Zone\" with icon file POSIX file \"$dialogIcon\" buttons {\"OK\"} default button {\"OK\"}" 122 | /usr/bin/osascript -e "$theCommand" 123 | 124 | exit 0 125 | 126 | fi 127 | 128 | 129 | # if user chooses to manually set a time zone 130 | 131 | logresult "User has chosen to set time zone manually." 132 | 133 | # present the user the short list of time zones 134 | 135 | listNames=$( /usr/bin/printf '%s\n' "${name[@]}" ) 136 | 137 | theCommand="choose from list (every paragraph of \"$listNames\") with prompt \"Choose your current time zone.\" OK button name \"OK\" cancel button name \"More Choices\" with title \"Set Time Zone\"" 138 | listChoice=$( /usr/bin/osascript -e "$theCommand" ) 139 | 140 | # determine which time zone the user selected from the list 141 | choiceIndex=$( /usr/bin/sdiff <(/bin/echo "$listNames") <(/bin/echo "$listChoice") | /bin/cat -n | /usr/bin/grep -v "<" | /usr/bin/awk '{ print $1 }' ) 142 | 143 | if [[ "$listChoice" != false ]]; then # user has chosen a time zone from the short list 144 | 145 | chosenTimeZone="${zone[$choiceIndex]}" 146 | 147 | else # user has requested to see more time zones 148 | 149 | # read system time zone list 150 | timeZoneList=$( /usr/sbin/systemsetup -listtimezones ) 151 | 152 | # parse and list regions from time zone list 153 | timeZoneRegion=$( /bin/echo "$timeZoneList" | /usr/bin/grep / | /usr/bin/awk -F '( |/)' '{ print $2 }' | /usr/bin/sort | /usr/bin/uniq ) 154 | theCommand="choose from list (every paragraph of \"$timeZoneRegion\") with prompt \"Choose your current world region.\" with title \"Set Time Zone\"" 155 | selectedRegion=$( /usr/bin/osascript -e "$theCommand" ) 156 | 157 | # parse and list cities for chosen region in time zone list 158 | timeZoneCity=$( /bin/echo "$timeZoneList" | /usr/bin/grep "$selectedRegion" | /usr/bin/awk -F '(\/)' '{ print $2 }' | /usr/bin/sort | /usr/bin/uniq ) 159 | theCommand="choose from list (every paragraph of \"$timeZoneCity\") with prompt \"Choose the nearest city to you for world region $selectedRegion.\" with title \"Set Time Zone\"" 160 | selectedCity=$( /usr/bin/osascript -e "$theCommand" ) 161 | 162 | # set new time zone to Region/City format 163 | chosenTimeZone="$selectedRegion/$selectedCity" 164 | 165 | fi 166 | 167 | 168 | # disable setting time zone automatically 169 | /usr/bin/defaults write /Library/Preferences/com.apple.timezone.auto Active -bool False 170 | 171 | # set the time zone manually to chosen time zone 172 | /usr/sbin/systemsetup -settimezone "$chosenTimeZone" 173 | 174 | logresult "Setting time zone to $chosenTimeZone." "Failed setting time zone to $chosenTime." 175 | 176 | # open the date & time system preference for the user to verify settings 177 | /usr/bin/open "/System/Library/PreferencePanes/DateAndTime.prefPane" 178 | /bin/sleep 2 # allow time to change settings 179 | 180 | # notify the user time zone has been set 181 | theCommand="display dialog \"Your system is now set to $( date +%Z ) timezone. Opening the Time Zone preference pane for you to verify settings.\" with title \"Set Time Zone\" with icon file POSIX file \"$dialogIcon\" buttons {\"OK\"} default button {\"OK\"}" 182 | /usr/bin/osascript -e "$theCommand" 183 | 184 | exit 0 -------------------------------------------------------------------------------- /UploadBuildingsList.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: July 9, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Uploads a list of buildings to your Jamf Pro server by reading a 15 | # BuildingsList.txt file or a list pasted into this script. When used 16 | # with DownloadBuildingsList.sh, a Jamf Pro administrator can start with a list 17 | # from an old Jamf Pro server, clean up the text and then upload the text 18 | # to another Jamf Pro server. 19 | # 20 | # The script creates a log file in the same folder as the script. 21 | # 22 | # Except where otherwise noted, this work is licensed under 23 | # http://creativecommons.org/licenses/by/4.0/ 24 | # 25 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 26 | 27 | # INSTRUCTIONS 28 | 29 | # 1) Modify URL, userName and passWord below to access your Jamf Pro server. 30 | # 2) Edit the buildingsList variable below or modify the script to "cat" a text file with the list. 31 | # 3) Save and run this script via Terminal or an editor with a "run script" feature. 32 | # 4) Verify buildings in your Jamf Pro server. 33 | 34 | URL="https://jamfpro.talkingmoose.net:8443" 35 | userName="API-Editor" 36 | passWord="password" 37 | 38 | # create the output directory and log file 39 | # in the same directory as this script 40 | 41 | # path to this script 42 | currentDirectory=$( /usr/bin/dirname "$0" ) 43 | 44 | # name of this script 45 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 46 | 47 | # create log file in same directory as script 48 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 49 | 50 | # functions 51 | function logresult() { 52 | if [ $? = 0 ] ; then 53 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 54 | else 55 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 56 | fi 57 | } 58 | 59 | # the time right now 60 | startTime=$( /bin/date '+%s' ) 61 | 62 | # start the log 63 | logresult "--------------------- Begin Script ---------------------" 64 | 65 | # get list of buildings from a file or from text pasted below 66 | 67 | # buildingsList=$( /bin/cat '/path/to/buildingslist.txt' ) 68 | # or 69 | buildingsList="Dome of the Rock 70 | La Pedrera 71 | One World Trade Center 72 | St Paul's Cathedral 73 | Petronas Towers 74 | The White House 75 | Leaning Tower of Pisa 76 | The Kaaba 77 | The Shard 78 | St Basil's Cathedral 79 | Colosseum 80 | Taj Mahal 81 | Sydney Opera House 82 | Space Needle 83 | Pantheon 84 | Turning Torso" 85 | 86 | logresult "Reading buildings list." "Failed to read buildings list." 87 | 88 | # upload building names, one at a time 89 | # the script will not modify buildings that already exist in the Jamf Pro server 90 | 91 | while IFS= read aLine 92 | do 93 | THExml="$aLine" 94 | 95 | /usr/bin/curl -k $URL/JSSResource/buildings --user "$userName:$passWord" -H "Content-Type: text/xml" -X POST -d "$THExml" 96 | 97 | logresult "Uploaded builidng \"$aLine\"." "Failed to upload building \"$aLine\"." 98 | 99 | UPLOAD=$((UPLOAD+1)) 100 | 101 | done <<< "$buildingsList" 102 | 103 | # stop the timer 104 | # calculate how long the script ran 105 | 106 | logresult "Completing script." 107 | logresult "Processed $UPLOAD buildings." 108 | 109 | # the time right now 110 | stopTime=$( /bin/date '+%s' ) 111 | 112 | # subtract start time from stop time and log the time in seconds 113 | DIFF=$(($stopTime-$startTime)) 114 | logresult "Script operations took $DIFF seconds to complete." 115 | 116 | logresult "---------------------- End Script ---------------------- 117 | 118 | " 119 | 120 | exit 0 121 | -------------------------------------------------------------------------------- /UploadDepartmentsList.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | <> "$logFile" 53 | else 54 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 55 | fi 56 | } 57 | 58 | # the time right now 59 | startTime=$( /bin/date '+%s' ) 60 | 61 | # start the log 62 | logresult "--------------------- Begin Script ---------------------" 63 | 64 | # get list of buildings from a file or from text pasted below 65 | 66 | # departmentsList=$( /bin/cat '/path/to/departmentsList.txt' ) 67 | # or 68 | departmentsList="Accounting 69 | Sales 70 | Department of Redundancy 71 | Parks 72 | Recreation" 73 | 74 | logresult "Reading departments list." "Failed to read departments list." 75 | 76 | # upload department names, one at a time 77 | # the script will not modify departments that already exist in the Jamf Pro server 78 | 79 | while IFS= read aLine 80 | do 81 | THExml="$aLine" 82 | 83 | /usr/bin/curl -k $URL/JSSResource/departments --user "$userName:$password" -H "Content-Type: text/xml" -X POST -d "$THExml" 84 | 85 | logresult "uploaded departments \"$aLine\"." "Failed to upload departments \"$aLine\"." 86 | 87 | upload=$((upload+1)) 88 | 89 | done <<< "$departmentsList" 90 | 91 | # stop the timer 92 | # calculate how long the script ran 93 | 94 | logresult "Completing script." 95 | logresult "Processed $upload departments." 96 | 97 | # the time right now 98 | stopTime=$( /bin/date '+%s' ) 99 | 100 | # subtract start time from stop time and log the time in seconds 101 | difference=$(($stopTime-$startTime)) 102 | logresult "Script operations took $difference seconds to complete." 103 | 104 | logresult "---------------------- End Script ---------------------- 105 | 106 | " 107 | 108 | exit 0 109 | -------------------------------------------------------------------------------- /UploadNetworkSegments.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # 5 | # Written by: William Smith 6 | # Professional Services Engineer 7 | # Jamf 8 | # bill@talkingmoose.net 9 | # https://github.com/talkingmoose/Jamf-Scripts 10 | # 11 | # Originally posted: July 9, 2016 12 | # Last updated: August 13, 2018 13 | # 14 | # Purpose: Uploads network segment XML files to your Jamf Pro server. 15 | # When used with DownloadNetworkSegments.sh, a Jamf Pro administrator can 16 | # start with a list from an old server, delete unwanted network segment 17 | # files and then upload the remaining files to another server. 18 | # 19 | # The script creates a log file in the same folder as the script. 20 | # 21 | # Except where otherwise noted, this work is licensed under 22 | # http://creativecommons.org/licenses/by/4.0/ 23 | # 24 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 25 | 26 | # INSTRUCTIONS 27 | 28 | # 1) Run the DownloadNetworkSegments.sh script against your source Jamf Pro server to create a list of network segment XML files. 29 | # 2) Review the XML files in the JSS_Output folder and Trash any you do not wish to upload to your destination Jamf Pro server. 30 | # 3) Modify URL, userName and passWord below to access your destination Jamf Pro server. 31 | # 4) Save and run this script via Terminal or an editor with a "run script" feature. 32 | # 5) Verify network segments in your destination Jamf Pro server. 33 | 34 | # the time right now 35 | startTime=$( /bin/date '+%s' ) 36 | 37 | URL="https://jamfpro.talkingmoose.net:8443" 38 | userName="API-Editor" 39 | passWord="password" 40 | 41 | # create the output directory and log file 42 | # in the same directory as this script 43 | 44 | # path to this script 45 | currentDirectory=$( /usr/bin/dirname "$0" ) 46 | 47 | # name of this script 48 | currentScript=$( /usr/bin/basename -s .sh "$0" ) 49 | 50 | # create the JSS_Output directory in the same directory as script 51 | outputDirectory="$currentDirectory/JSS_Output" 52 | 53 | # create log file in same directory as script 54 | logFile="$currentDirectory/$currentScript - $( /bin/date '+%y-%m-%d' ).log" 55 | 56 | # functions 57 | function logresult() { 58 | if [ $? = 0 ] ; then 59 | /bin/date "+%Y-%m-%d %H:%M:%S $1" >> "$logFile" 60 | else 61 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 62 | fi 63 | } 64 | 65 | # the time right now 66 | startTime=$( /bin/date '+%s' ) 67 | 68 | # start the log 69 | logresult "--------------------- Begin Script ---------------------" 70 | 71 | # verify the working directory on the desktop 72 | if [ ! -d "$outputDirectory" ] ; then 73 | echo "Output directory at $outputDirectory does not exist. Fix this path first." 74 | logresult "Output directory $outputDirectory does not exist. Fix this path first." 75 | exit 0 76 | fi 77 | 78 | # create a list of network segment XML files to upload 79 | nsFiles=$( ls "$outputDirectory" ) 80 | logresult "Created list of network segment XML files from $outputDirectory." "Failed to create list of network segment XML files from $outputDirectory." 81 | 82 | # upload XML files to create network segments 83 | while IFS= read aLine 84 | do 85 | # read the XML file and remove formatting 86 | nsXML=$( /bin/cat "$outputDirectory/$aLine" | /usr/bin/xmllint --noblanks - ) 87 | logresult "Reading XML file \"$aLine\"" "Failed to read XML file \"$aLine\"" 88 | 89 | /usr/bin/curl -k $URL/JSSResource/networksegments --user "$userName:$passWord" -H "Content-Type: text/xml" -X POST -d "$nsXML" 90 | logresult "Uploaded XML file \"$aLine\"" "Failed to upload XML file \"$aLine\"" 91 | 92 | upload=$((upload+1)) 93 | 94 | done <<< "$nsFiles" 95 | 96 | # stop the timer 97 | # calculate how long the script ran 98 | 99 | logresult "Completing script." 100 | logresult "Processed $upload network segment XML files." 101 | 102 | # the time right now 103 | stopTime=$( /bin/date '+%s' ) 104 | 105 | # subtract start time from stop time and log the time in seconds 106 | DIFF=$(($stopTime-$startTime)) 107 | logresult "Script operations took $DIFF seconds to complete." 108 | 109 | logresult "---------------------- End Script ---------------------- 110 | 111 | " 112 | 113 | exit 0 -------------------------------------------------------------------------------- /rsync to DPs/net.talkingmoose.syncjamfdps.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EnvironmentVariables 6 | 7 | PATH 8 | /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/VMware Fusion.app/Contents/Public/Library/Application Support/Microsoft/MAU2.0/Microsoft AutoUpdate.app/Contents/MacOS:/usr/local/sbin 9 | 10 | KeepAlive 11 | 12 | SuccessfulExit 13 | 14 | 15 | Label 16 | net.talkingmoose.syncjamfdps 17 | ProgramArguments 18 | 19 | /path/to/send-to-dp2.sh 20 | 21 | RunAtLoad 22 | 23 | StartInterval 24 | 300 25 | 26 | 27 | -------------------------------------------------------------------------------- /rsync to DPs/rsync-servers.txt: -------------------------------------------------------------------------------- 1 | # Servers are synchronized in the order below. 2 | # Move higher priority servers to the top. 3 | # Format (tab separated): 4 | # server address > remote admin name > remote path to Packages folder 5 | server1.talkingmoose.net casperadmin /CasperShare/Packages 6 | server2.talkingmoose.net casperadmin /CasperShare/Packages 7 | server3.talkingmoose.net casperadmin /CasperShare/Packages 8 | 192.168.0.2 casperadmin /CasperShare/Packages 9 | -------------------------------------------------------------------------------- /rsync to DPs/send-to-dp2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | <> "$logFile" 61 | else 62 | /bin/date "+%Y-%m-%d %H:%M:%S $2" >> "$logFile" 63 | fi 64 | } 65 | 66 | 67 | 68 | # the time right now 69 | startTime=$( /bin/date '+%s' ) 70 | 71 | # start the log 72 | logresult "--------------------- Begin Script ---------------------" 73 | 74 | # rotate logs -- delete all but the five most recent log files 75 | deleteOldLogs=$( /bin/ls -1t "$currentDirectory/$currentScript"*.log | /usr/bin/tail -n +6 ) 76 | 77 | while IFS= read -r aLog 78 | do 79 | logFileName=$( /usr/bin/basename "$aLog" ) 80 | /bin/rm "$aLog" 81 | logresult "Deleting old log file: $logFileName." 82 | done <<< "$deleteOldLogs" 83 | 84 | 85 | 86 | # read list of servers using rsync 87 | rsyncServers=$( /usr/bin/grep -v \# "$currentDirectory/rsync-servers.txt") 88 | 89 | # read list of servers using smb 90 | smbServers=$( /usr/bin/grep -v \# "$currentDirectory/smb-servers.txt" ) 91 | 92 | 93 | 94 | # rsync each server in the rsyncServer file 95 | while IFS= read aServer 96 | do 97 | # parse each line for address, username and password 98 | sshAddress=$( echo "$aServer" | /usr/bin/awk '{ print $1 }' ) 99 | sshUsername=$( echo "$aServer" | /usr/bin/awk '{ print $2 }' ) 100 | sshPath=$( echo "$aServer" | /usr/bin/awk '{ print $3 }' ) 101 | 102 | /usr/bin/rsync --archive --human-readable --verbose -e "ssh -i $HOME/.ssh/id_rsa" --exclude=".*" --delete --progress --stats "$pathToPackages" "$sshUsername@$sshAddress:$sshPath" >> $logFile 103 | logresult "Completed Rsync to $aServer server." "Failed Rsync to $aServer server." 104 | done <<< "$rsyncServers" 105 | 106 | 107 | 108 | # rsync each server in the smbServer file 109 | while IFS= read aServer 110 | do 111 | # parse each line for address, username and password 112 | smbAddress=$( echo "$aServer" | /usr/bin/awk '{ print $1 }' ) 113 | smbUsername=$( echo "$aServer" | /usr/bin/awk '{ print $2 }' ) 114 | smbPassword=$( echo "$aServer" | /usr/bin/awk '{ print $3 }' ) 115 | smbShare=$( echo "$aServer" | /usr/bin/awk '{ print $4 }' ) 116 | smbPath=$( echo "$aServer" | /usr/bin/awk '{ print $5 }' ) 117 | 118 | # mount remote SMB server. 119 | /bin/mkdir "/Volumes/$smbShare" 120 | /sbin/mount_smbfs "//$smbUsername:$smbPassword@$smbAddress/$smbShare" "/Volumes/$smbAddress" 121 | logresult "Mounted SMB server $smbAddress." "Failed mount SMB server $smbAddress." 122 | 123 | /usr/bin/rsync --archive --human-readable --verbose --exclude=".*" --delete --progress --stats "$pathToPackages" "/Volumes/$smbShare$smbPath" >> $logFile 124 | logresult "Completed Rsync to $aServer server." "Failed Rsync to $aServer server." 125 | 126 | # unmount SMB Volume 127 | /sbin/umount "/Volumes/$smbShare" 128 | logresult "Unmounted $aServer server." "Failed unmount $aServer server." 129 | 130 | done <<< "$smbServers" 131 | 132 | 133 | 134 | # stop the timer 135 | # calculate how long the script ran 136 | 137 | logresult "Completing script." 138 | logresult "Processed $printerCount printers." 139 | 140 | # the time right now 141 | stopTime=$( /bin/date '+%s' ) 142 | 143 | # subtract start time from stop time and log the time in seconds 144 | timer=$(($stopTime-$startTime)) 145 | logresult "Script operations took $timer seconds to complete." 146 | 147 | logresult "---------------------- End Script ---------------------- 148 | 149 | " 150 | 151 | exit 0 -------------------------------------------------------------------------------- /rsync to DPs/smb-servers.txt: -------------------------------------------------------------------------------- 1 | # Servers are synchronized in the order below. 2 | # Move higher priority servers to the top. 3 | # Format (tab separated): 4 | # server address > remote admin name > admin password > remote shre name > remote path to Packages folder 5 | server6.talkingmoose.net casperadmin P@55w0rd ShareName /path/to/packages 6 | --------------------------------------------------------------------------------