Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
BIG-RAT committed Oct 5, 2024
1 parent 5b33456 commit a2ece89
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 68 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Thanks @fauxserve for coming up with the idea and initial bash version.

## History

- 2024-10-05: Fix issue calling automated device enrollment.

- 2024-07-27: Fix authentication issue. Update apiMDM_removal script to use an API client and authenticate MDM removal request with a bearer token.

- 2023-12-10: Fix authentication issue with Jamf Pro 11.
Expand Down
4 changes: 4 additions & 0 deletions ReEnroller.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
B5E2587325D725B100ABD528 /* com.jamf.ReEnroller.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5E2587225D725B100ABD528 /* com.jamf.ReEnroller.plist */; };
B5E2587625D7273600ABD528 /* ReEnroller-component.plist in Resources */ = {isa = PBXBuildFile; fileRef = B5E2587525D7273600ABD528 /* ReEnroller-component.plist */; };
B5F6492127C96423007B7C26 /* JamfPro.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5F6492027C96423007B7C26 /* JamfPro.swift */; };
CE627F6F2CB1E16F00B03815 /* ade.sh in Resources */ = {isa = PBXBuildFile; fileRef = CE627F6E2CB1E16200B03815 /* ade.sh */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -56,6 +57,7 @@
B5E2587525D7273600ABD528 /* ReEnroller-component.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ReEnroller-component.plist"; sourceTree = "<group>"; };
B5F6492027C96423007B7C26 /* JamfPro.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JamfPro.swift; sourceTree = "<group>"; };
CE3FE44C293FE2E200D27323 /* Notes.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Notes.md; sourceTree = "<group>"; };
CE627F6E2CB1E16200B03815 /* ade.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ade.sh; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -91,6 +93,7 @@
B5480D5A25D6AE1700BFCC86 /* ReEnroller */ = {
isa = PBXGroup;
children = (
CE627F6E2CB1E16200B03815 /* ade.sh */,
B5480DAA25D6B8CA00BFCC86 /* ApiCall.swift */,
B535677425DB56110017769D /* Alert.swift */,
B5480D5B25D6AE1700BFCC86 /* AppDelegate.swift */,
Expand Down Expand Up @@ -201,6 +204,7 @@
B5E2587025D7252100ABD528 /* settings.plist in Resources */,
B5E2587325D725B100ABD528 /* com.jamf.ReEnroller.plist in Resources */,
B5E2587625D7273600ABD528 /* ReEnroller-component.plist in Resources */,
CE627F6F2CB1E16F00B03815 /* ade.sh in Resources */,
B5480D6325D6AE1A00BFCC86 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Binary file not shown.
6 changes: 3 additions & 3 deletions ReEnroller/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="23094" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<plugIn identifier="com.apple.WebKit2IBPlugin" version="22690"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23094"/>
<plugIn identifier="com.apple.WebKit2IBPlugin" version="23094"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand Down
15 changes: 14 additions & 1 deletion ReEnroller/Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class Command: NSObject {

let outdata = pipe_pkg.fileHandleForReading.readDataToEndOfFile()
if var string = String(data: outdata, encoding: .utf8) {
WriteToLog.shared.message(theMessage: "command result: \(string)")
var currentEnrollment = betweenTags(xmlString: string, startTag: "ConfigurationURL = \"", endTag: "\";")
if currentEnrollment == "" { currentEnrollment = string }
WriteToLog.shared.message(theMessage: "command result: \(currentEnrollment)")
}

task_pkg.waitUntilExit()
Expand Down Expand Up @@ -70,3 +72,14 @@ class Command: NSObject {
// function to return value of bash command - end

}

func betweenTags(xmlString:String, startTag:String, endTag:String) -> String {
var rawValue = ""
if let start = xmlString.range(of: startTag),
let end = xmlString.range(of: endTag, range: start.upperBound..<xmlString.endIndex) {
rawValue.append(String(xmlString[start.upperBound..<end.lowerBound]))
} else {
// WriteToLog.shared.message(stringOfText: "[ListPackages.betweenTags] Nothing found between \(startTag) and \(endTag).")
}
return rawValue
}
2 changes: 1 addition & 1 deletion ReEnroller/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>20241005.015658</string>
<string>20241005.231930</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
Expand Down
89 changes: 26 additions & 63 deletions ReEnroller/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,13 @@ class ViewController: NSViewController, URLSessionDelegate {

// process function - start
@IBAction func process(_ sender: Any) {
processQuickAdd_Button.isEnabled = false
// get invitation code - start
// var jssUrl = jssUrl_TextField.stringValue.baseUrl
JamfProServer.destination = jssUrl_TextField.stringValue.baseUrl
if "\(JamfProServer.destination)" == "" {
Alert.shared.display(header: "Alert", message: "Please provide the URL for the new server.")
processQuickAdd_Button.isEnabled = true
return
}
// jssUrl = dropTrailingSlash(theSentString: jssUrl)
Expand All @@ -327,6 +329,7 @@ class ViewController: NSViewController, URLSessionDelegate {
if "\(mgmtAcct)" == "" {
Alert.shared.display(header: "Attention", message: "You must supply a management account username.")
mgmtAccount_TextField.becomeFirstResponder()
processQuickAdd_Button.isEnabled = true
return
}

Expand All @@ -340,11 +343,13 @@ class ViewController: NSViewController, URLSessionDelegate {
if "\(mgmtAcctPwd)" == "" {
Alert.shared.display(header: "Attention", message: "Password cannot be left blank.")
mgmtAccount_TextField.becomeFirstResponder()
processQuickAdd_Button.isEnabled = true
return
}
if "\(mgmtAcctPwd)" != "\(mgmtAcctPwd2)" {
Alert.shared.display(header: "Attention", message: "Management account passwords do not match.")
mgmtAcctPwd_TextField.becomeFirstResponder()
processQuickAdd_Button.isEnabled = true
return
}

Expand All @@ -363,6 +368,7 @@ class ViewController: NSViewController, URLSessionDelegate {
// check the local system for the existance of the management account
if ( userOperation(mgmtUser: mgmtAcct, operation: "find") != "" ) {
Alert.shared.display(header: "Attention:", message: "Account \(mgmtAcct) cannot be used with a random password as it exists on this system.")
processQuickAdd_Button.isEnabled = true
return
}
/*
Expand Down Expand Up @@ -395,6 +401,7 @@ class ViewController: NSViewController, URLSessionDelegate {
if jamfSchool_Button.state.rawValue == 1 {
if networkId_TextField.stringValue == "" || apiKey_TextField.stringValue == "" {
Alert.shared.display(header: "Attention:", message: "Migrating from Jamf School requires the server URL, the Network ID, and API key.")
processQuickAdd_Button.isEnabled = true
return
} else {
// generate token for Jamf School API
Expand All @@ -408,13 +415,14 @@ class ViewController: NSViewController, URLSessionDelegate {

self.spinner.startAnimation(self)

healthCheck(server: JamfProServer.destination) {
healthCheck(server: JamfProServer.destination) { [self]
(result: [String]) in
print("health check result: \(result)")
if ( result[1] != "[]" ) {
let lightFormat = self.removeTag(xmlString: result[1].replacingOccurrences(of: "><", with: ">\n<"))
Alert.shared.display(header: "Attention", message: "The new server, \(JamfProServer.destination), does not appear ready for enrollments.\nResult of healthCheck: \(lightFormat)\nResponse code: \(result[0])")
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
} else {
// server is reachable
Expand All @@ -424,6 +432,7 @@ class ViewController: NSViewController, URLSessionDelegate {
if "\(self.jssUsername)" == "" || "\(self.jssPassword))" == "" {
Alert.shared.display(header: "Alert", message: "Please provide both a username and password for the server.")
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
}

Expand All @@ -436,7 +445,7 @@ class ViewController: NSViewController, URLSessionDelegate {
let jpsBase64Creds = jpsCredentials.data(using: .utf8)?.base64EncodedString() ?? ""


JamfPro().getToken(serverUrl: JamfProServer.destination, base64creds: jpsBase64Creds) {
JamfPro().getToken(serverUrl: JamfProServer.destination, base64creds: jpsBase64Creds) { [self]
authResult in

let (statusCode,theResult) = authResult
Expand All @@ -449,6 +458,7 @@ class ViewController: NSViewController, URLSessionDelegate {
switch verifySslSetting {
case "failedCredentials":
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
case "":
Alert.shared.display(header: "Alert", message: "Unable to determine verifySSLCert setting on server, setting to always_except_during_enrollment")
Expand All @@ -472,14 +482,15 @@ class ViewController: NSViewController, URLSessionDelegate {
Xml.objectArray.append("invitation")

// get invitation code
self.apiAction(action: "POST", xml: Xml.objectDict["invitation"]!, theApiObject: "invitation") {
self.apiAction(action: "POST", xml: Xml.objectDict["invitation"]!, theApiObject: "invitation") { [self]
(result: [Any]) in
let responseCode = result[0] as! Int
let responseMesage = result[1] as! String
if !(responseCode > 199 && responseCode < 300) {
let lightFormat = self.removeTag(xmlString: responseMesage.replacingOccurrences(of: "><", with: ">\n<"))
Alert.shared.display(header: "Attention", message: "Failed to create invitation code.\nMessage: \(lightFormat)\nResponse code: \(responseCode)")
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
} else {
print("full reply for invitation code request:\n\t\(responseMesage)\n")
Expand All @@ -489,6 +500,7 @@ class ViewController: NSViewController, URLSessionDelegate {
if "\(self.theNewInvite)" == "" {
Alert.shared.display(header: "Alert", message: "Unable to create invitation. Verify the account, \(self.jssUsername), has been assigned permissions to do so.")
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
} else {
print("Found invitation code: \(self.theNewInvite)")
Expand Down Expand Up @@ -541,6 +553,7 @@ class ViewController: NSViewController, URLSessionDelegate {
} else {
print("invalid reply from the Jamf server when requesting an invitation code.")
self.spinner.stopAnimation(self)
processQuickAdd_Button.isEnabled = true
return
}
}
Expand Down Expand Up @@ -1285,7 +1298,7 @@ class ViewController: NSViewController, URLSessionDelegate {
fullPackageName = "\(packageName)-\(self.shortHostname).pkg"
// alert the user, we're done
Alert.shared.display(header: "Process Complete", message: "A package (\(packageName)-\(self.shortHostname).pkg) has been created in Downloads which is ready to be deployed with your current Jamf server.\n\nThe package \(self.includesMsg) a postinstall script to load the launch daemon and start the \(packageName) app.\(self.includesMsg2)\(self.policyMsg)")

processQuickAdd_Button.isEnabled = true
}

func connectedToNetwork() -> Bool {
Expand Down Expand Up @@ -1761,58 +1774,8 @@ class ViewController: NSViewController, URLSessionDelegate {
return mdm
}

// function to return exit code of bash command - start
// func myExitCode(cmd: String, args: String...) -> Int8 {
// var pipe_pkg = Pipe()
// let task_pkg = Process()
//
// task_pkg.launchPath = cmd
// task_pkg.arguments = args
// task_pkg.standardOutput = pipe_pkg
// //var test = task_pkg.standardOutput
//
// task_pkg.launch()
//
// let outdata = pipe_pkg.fileHandleForReading.readDataToEndOfFile()
// if var string = String(data: outdata, encoding: .utf8) {
// WriteToLog.shared.message(theMessage: "command result: \(string)")
// }
//
// task_pkg.waitUntilExit()
// let result = task_pkg.terminationStatus
//
// return(Int8(result))
// }
// function to return exit code of bash command - end

// function to return value of bash command - start
func myExitValue(cmd: String, args: String...) -> [String] {
var status = [String]()
let pipe = Pipe()
let task = Process()

task.launchPath = cmd
task.arguments = args
task.standardOutput = pipe
// let outputHandle = pipe.fileHandleForReading

task.launch()

let outdata = pipe.fileHandleForReading.readDataToEndOfFile()
if var string = String(data: outdata, encoding: .utf8) {
string = string.trimmingCharacters(in: .newlines)
status = string.components(separatedBy: "\n")
}

task.waitUntilExit()

// print("status: \(status)")
return(status)
}
// function to return value of bash command - end

func profileInstall() -> Bool {
let en = myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | grep -A1 Wi-Fi | grep Device | awk '{ print $2 }'")[0]
let en = Command.shared.myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | grep -A1 Wi-Fi | grep Device | awk '{ print $2 }'")[0]

WriteToLog.shared.message(theMessage: "[profileInstall] en: \(en)")
WriteToLog.shared.message(theMessage: "[profileInstall] ssid: \(ssid)")
Expand Down Expand Up @@ -1856,7 +1819,7 @@ class ViewController: NSViewController, URLSessionDelegate {
let ssid = stringFromPlist(plistURL: plistURL!, startString: "<key>SSID_STR</key><string>", endString: "</string><key>Interface</key><string>")
let ssidPwd = stringFromPlist(plistURL: plistURL!, startString: "<key>Password</key><string>", endString: "</string><key>EncryptionType</key>")
let encrypt = stringFromPlist(plistURL: plistURL!, startString: "<key>EncryptionType</key><string>", endString: "</string><key>AutoJoin</key>")
let en = myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | grep -A1 Wi-Fi | grep Device | awk '{ print $2 }'")[0]
let en = Command.shared.myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | grep -A1 Wi-Fi | grep Device | awk '{ print $2 }'")[0]

let _ = Command.shared.myExitCode(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -addpreferredwirelessnetworkatindex \(en) \"\(ssid)\" 0 \(encrypt) \"\(ssidPwd)\"")
} catch {
Expand Down Expand Up @@ -1984,12 +1947,12 @@ class ViewController: NSViewController, URLSessionDelegate {
var power = ""

// get Wi-Fi interface
let interfaceArray = myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | egrep -A 1 \"(Airport|Wi-Fi)\" | awk '/Device:/ { print $2 }'")
let interfaceArray = Command.shared.myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -listallhardwareports | egrep -A 1 \"(Airport|Wi-Fi)\" | awk '/Device:/ { print $2 }'")
if interfaceArray.count > 0 {
interface = interfaceArray[0]

// check airport power
let powerArray = myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -getairportpower \(interface) | awk -F': ' '{ print $2 }'")
let powerArray = Command.shared.myExitValue(cmd: "/bin/bash", args: "-c", "/usr/sbin/networksetup -getairportpower \(interface) | awk -F': ' '{ print $2 }'")
if powerArray.count > 0 {
power = powerArray[0]

Expand Down Expand Up @@ -2269,16 +2232,16 @@ class ViewController: NSViewController, URLSessionDelegate {
}
}
// update inventory - end


// see if device is scoped to a prestage enrollment
_ = Command.shared.myExitCode(cmd: "/bin/launchctl", args: "asuser", "$(id -u \"$(stat -f%Su /dev/console)\")", "/usr/bin/profiles", "show", "-type", "enrollment")

if callEnrollment == "yes" {
// see if device is scoped to a prestage enrollment
_ = Command.shared.myExitCode(cmd: "/usr/bin/profiles", args: "status", "-type", "enrollment")
// launch profiles renew -type enrollment to initiate ADE process
if Command.shared.myExitCode(cmd: "/usr/bin/profiles", args: "renew", "-type", "enrollment") == 0 {
if Command.shared.myExitCode(cmd: "/bin/bash", args: "-c", (Bundle.main.bundlePath+"/Contents/Resources/ade.sh").replacingOccurrences(of: " ", with: "\\ ")) == 0 {
WriteToLog.shared.message(theMessage: "Successfully called profiles renew -type enrollment")
} else {
WriteToLog.shared.message(theMessage: "call to profiles renew -type enrollment failed")
//exit(1)
}
} else {
WriteToLog.shared.message(theMessage: "not calling profiles renew -type enrollment")
Expand Down
4 changes: 4 additions & 0 deletions ReEnroller/ade.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

/bin/launchctl asuser $(id -u "$(stat -f%Su /dev/console)") /usr/bin/profiles renew -type enrollment

0 comments on commit a2ece89

Please sign in to comment.