Tuesday, January 15, 2019

Fix "Network accounts are unavailable" on macOS Login Screen with a caffeinate LaunchDaemon

On Macs that are bound to Active Directory, you may from time to time see this popup next to the username box on the macOS login screen:


In most cases, assuming that the Mac is in fact connected to a wired Ethernet connection, this is not actually true, and if you try to log in with your AD credentials you will be successful, and if you wait 30 seconds or so, the message will go away. This message usually appears when the Mac has not been in use for a while and fallen asleep, or after booting up.

It seems that this is probably caused by a decision to show the login screen as quickly as possible, to the point that the network stack and/or AD connection is not fully initialized by the time it is visible. When you try to log in, it kick-starts the OS into loading everything, and should let you right in. However, if you are bothered by this, or have users who are, there is a simple fix that has some other benefits: creating a LaunchDaemon running caffeinate.

caffeinate is a macOS Terminal command that creates an "assertion" to keep certain parts of the computer from going to sleep. These assertions inform the System Management Controller (SMC) that the Mac should not sleep because an application requires it to stay awake, because a user is currently active, etc. Different assertions have different effects, which are reflected in caffeinate's different options. For example, to keep a Mac from putting its display to sleep, you can use caffeinate -d, and, to keep the disk from sleeping, use caffeinate -m.

To keep the Mac from going into idle sleep, which is the state in which the network stack appears to turn off, causing the popup, you can use caffeinate -i for desktop Macs, and caffeinate -s for mobile Macs. This difference is important: -i creates an assertion that does not let the Mac go into idle sleep at all; -s creates an assertion that is only valid when the system is running on AC power, meaning that a laptop will not stay awake in a bag, or other potentially damaging situation, as long as it is disconnected from its charger.

You can also use the caffeinate command to create an assertion that is only valid for a certain number of seconds, with caffeinate -t <seconds> -<mode>, or to create one that stays valid as long as a certain command is running, such as caffeinate -i make to keep the Mac awake as long as make is running.

So, with all of that out of the way, how can you use caffeinate to prevent that message from popping up on the login screen? Use a LaunchDaemon. LaunchDaemons run at system startup, and continue running regardless of whether a user is on the machine or not. I use a LaunchDaemon like this, located at /Library/LaunchDaemons, to keep the popup from appearing on our lab desktop Macs:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple Computer/DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<dict>
<key>Label</key>
<string>com.example.caffeinate.plist</string>
<key>Program</key>
<string>/usr/bin/caffeinate</string>
<key>ProgramArguments</key>
<array>
    <string>/usr/bin/caffeinate</string>
    <string>-s</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>

Install that LaunchDaemon and reboot the Mac to make it take effect. The popup will still appear for 30 seconds or so after a reboot, as the OS hasn't had a chance to initialize everything yet, but it should not reappear afterwards. This still allows the screen to go to sleep, as well as the HDDs, but keeps the rest of the OS awake so that the popup does not appear.

Since this keeps the networking components of the OS awake, it also helps resolve situations where pinging a Mac that has gone to sleep can take several tries as it tries to wake up. This, therefore, makes the process of getting Macs to check in to Jamf or another management system more reliable.

1 comment:

Tableau, TabPy, and the Case of No Input Rows

 I haven't scientifically confirmed this or anything, but it sure seems like if you pass an empty dataframe to a TabPy script, then no m...