Application crashing when calling macOS installer through Process()

Hey everyone,

This is probably a very ****** question as I have just started botching something together with Swift and therefore know very little as of now 😅

I am trying to write a little SwiftUI application that can download and reinstall macOS with some custom packages. For downloading the installer I use softwareupdate --fetch-full-installer through Process() and then parse the output to show the progress which works fine so far.

I do have trouble launching the installer (/Applications/Install macOS Monterey.app/Contents/Resources/startosinstall) though.

This is the function I am using. I removed some of the UI code that updates some labels and progress bars.

func installMacOS(installPath: String) {
        
        let task = Process()
        task.executableURL = URL(fileURLWithPath: installPath)
        
        task.arguments = [ "--nointeraction", "--agreetolicense", "--allowremoval", "--eraseinstall", "--cloneuser", "--stdinpass"]
        let outputPipe = Pipe()
        let inputPipe = Pipe()
        task.standardOutput = outputPipe
        task.standardInput = inputPipe
        
        let outputHandle = outputPipe.fileHandleForReading
        outputHandle.readabilityHandler = { pipe in
            if let ouput = String(data: pipe.availableData, encoding: .utf8) {
                if !ouput.isEmpty {
                    
                    if ouput.lowercased().range(of:"preparing") != nil {
                        print("Preparing macOS install...")
                    } else if ouput.lowercased().range(of:"error") != nil {
                        print("Something is wrong")
                    } else if ouput.lowercased().range(of:"restart") != nil {
                       print("Mac will restart")
                    } else {
                        let result = ouput.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
                        if let number = Float(result) {
                            print("Progress: " + String(number) + "%")
                        }
                    }
                }
            } else {
                print("Error: \(pipe.availableData)")
            }
        }
        task.launch()
        
        // I will replace this with a alert asking for the password at some point but security isn't important for this one so this is fine for now
        inputPipe.fileHandleForReading.write("Password\n".data(using: .utf8)!)
        inputPipe.fileHandleForWriting.closeFile()
        
    }

The function is called like this although the string is assembled through another function but this is the result:

installMacOS(installPath: "/Applications/Install macOS Monterey.app/Contents/Resources/startosinstall")

Running it results in the app crashing with different errors.

I would be very grateful for any tipps and hints in what I am doing wrong!

Thank you!

Best, Paul

Accepted Answer

The problem was of course that '''inputPipe.fileHandleForReading.write("Password\n".data(using: .utf8)!)''' should be '''inputPipe.fileHandleForWriting.write("Password\n".data(using: .utf8)!)''' 😅

I’m glad to hear that you get this sorted out.

Just FYI, Process is much harder to use than you think. See Running a Child Process with Standard Input and Output for my (relatively) lightweight wrapper.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Application crashing when calling macOS installer through Process()
 
 
Q