You can use scale to control how the desktop pictures are scaled. I have matched the options to the options in the Desktop preference pane:
fill: scale the image up or down so that it fills the entire screen (this is the default behavior)
stretch: stretch the image non-proportionally along both axes to fill the screen
center: show the image in the center in the original size
fit: scale the image up or down so that all of the image is shown
> desktoppr scale center
Background color
The center and fit options for image scaling may result in the desktop picture not fully covering the entire desktop. You can then control the background color with the color verb. The color verb takes a single hex coded color (as in web colors) (no leading # required):
desktoppr color 000000 # black background
desktoppr color FFFFFF # white background
desktoppr color FF0000 # red background
Future of desktoppr
This tool has always been meant to be a simple ‘one-trick-pony.’ The option to control the image settings has been nearly since I published the first version. I am glad I have finally gotten around to implementing it.
I have learnt a lot about Swift since I first built this tool. When I look at the code now, I want to re-write the entire thing from scratch. I’d also like build better argument parsing. However, it does what it is supposed to do and if I rewrote it now it would probably change the syntax, breaking other people’s workflows
I don’t expect the tool will need updates, other than when it has to adapt to future macOS updates, but we will see.
The Coronavirus pandemic seems to be affecting nearly everything this week. WWDC will be an online event this year. Apple Stores outside of China are closed, as are most of our work places and schools.
But, we also got a new MacBook Air (new keyboard), a new iPad Pro (amazing looking, albeit expensive Magic Keyboard), bumped SSD storage on the Mac mini, and a GM release for the iOS 13.4 family (with trackpad support on iPadOS) and macOS Catalina 10.15.4, with a release date for the OS updates next week.
WWDC20 – Apple Developer (Note: the Apple Developer app to take part in this event “is available only on the App Store for iPhone, iPad, Apple Watch, and Apple TV.” Not for macOS. You can access the old videos in a browser, but…)
Mike Boylan: “Mac Admin Pro Tip: The checkbox to allow an app to record the screen is able to be checked even by a standard user on the Mac. The whole pane does not need to be unlocked. This means your users don’t need to be admins to approve camera, mic, and/or screen sharing for a conf tool.”
Tim Perfitt: “the new ipad pro looks like a laptop. i am officially calling BS on the ARM based macs. apple strategy is clear: ios is the future. macs are trucks. Xcode on iOS is coming. The new ipad pro convinces me of that. ARM-based macs rumors are a distraction.”
Hacker Fantastic: “There is a 0day in VMware fusion for MacOS that allows any user to get root permissions. The bug is public and the fix for cve2020–3950 is incorrect, thus the weakness is a public 0day. It is a very straight forward LPE on any macOS with fusion installed.”
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
A while back I introduced desktoppr. It is a very simple tool; its singular goal is to set the desktop picture (users and admins migrating from Windows call it ‘wallpaper,’ but that is not the proper macOS nomenclature) without requiring PPPC/TCC whitelisting.
The good news is that desktoppr still works fine, nearly one-and-a-half years in! Even though Catalina brought in many changes and restrictions, desktoppr kept doing its job.
Nevertheless, as I have used desktoppr myself in several different deployments, and I have a few different approaches to deployment, depending on the requirements.
Catalina split system volume
One of the new features of Catalina is a read-only system volume, separate from the data volume. This means that the pre-installed desktop pictures are no longer in /Library/Desktop Pictures/ but can now be found in /System/Library/Desktop Pictures. This is on the read-only part of the file system.
On a new “fresh” macOS installation, the /Library/Desktop Pictures does not exist. However, when you create this folder, its contents will appear in the ‘Desktop’ preference pane, merged with the contents of the protected system folder. So, we can continue to use /Library/Desktop Pictures as a place to store and install custom desktop image files.
Note: if you do not want the custom desktop picture to appear in the Desktop preference pane, then you can install the file in a different location. /Users/Shared or /Library/MyOrganization/ are useful locations.
These command will create a payload folder, copy an image file (my example is BoringBlueDesktop.png) and build an installation pkg using the pkgbuild command.
In classroom, lab, and kiosk settings, MacAdmins may want to set and lock the desktop picture. In this use case, you do not need desktoppr at all.
Use the above pkg to install the image file and then use your management system to push a configuration profile that sets and locks a Desktop Picture.
Many management systems will have the desktop picture controls hidden in the ‘Restrictions’ payload among many other settings. Please consult the documentation. You can also use this custom profile that only controls the desktop setting.
Preset the desktop, but the let user change it
This is the most common way MacAdmins will want to deploy is to pre-set a custom Desktop Picture but allow the user to change it later. This is what desktoppr was created for.
There are two approaches you can take to do this. Well, to be honest, there are way more, and all of them are valid, as long as they work. I should say: I will show two different approaches.
The modular approach
In this case you use your management system to install and run all the pieces:
install the custom desktop picture using the above pkg
The advantage of this approach is that we already did the first part earlier, and the desktoppr pkg can be downloaded from the git repo,. So, we already have two of the three parts.
Note that this script has changed slightly since the last post. Originally, the script used launchctl asuser. The behavior of launchctl asuser seems to have changed somewhat in a recent update and I have switched the script to use sudo -u instead.
This approach can be used with Munki, Jamf, outset, and many other management solutions.
All in one package
The downside of the modular approach is that you have to manage three pieces (the image file, the desktoppr binary, and a script) in your management system. This can be especially problematic when you are not the actual administrator of the management system but more active in a ‘consulting role.’
In this case, I have found it easier to build a single package that does all the work. This is easier to hand over to another admin. It is also more flexible and can be used in even more situations. It is a bit more work to assemble, though.
Note the different version number, so the system can recognize this as a different pkg from the one you might have built earlier.
This form of the pkg does not actually install the desktoppr binary on the target system. When the pkg is created, the entire contents of the scripts folder will be archived into the pkg file. When the pkg is being installed, the contents will be expanded into a temporary directory. That means that the postinstall script can see the binary in the same director ‘next to it.’ This happens in lines 22–27 of the postinstall script.
After the installation is complete, the temporary files will be removed, so the postinstall script and the desktoppr binary will be removed automatically. You don’t need to worry about the cleanup.
Conclusion
Which approach works best depends on your specific deployment needs, your management setup and workflows and (not the least) your comfort with building scripts and packages.
Even when you have defined your deployment needs, there are multiple solutions on how to build and deploy a custom desktop picture. As long as they achieve the desired goal, there is no “best” solution.
Also, this is or was the week where all the remote work emergency planning was put into reality. In Europe and America, many countries, companies, schools, and other organisations are sending employees and students to remote work or studies. Games, conferences, concerts, and parties are being canceled. All in an effort to slow down the rate of contagion
This is an exceptional situation on so many levels. Everyone, be safe!
When, because of ‘social distancing,’ ‘self-isolation,’ or straight quarantine, you find yourself with extra time, maybe buy and read one of my books!
Victor (groob): “I’m a big advocate for remote work, but I doubt we’ll see many positive outcomes in this scenario. – many are going to be sick. – childcare will eat up a lot of time. – employers that weren’t already offering remote are not prepared. Remote work requires a lot of planning.”
Rene Ritchie: “NB: Apple’s Mac computers are unaffected by this latest Intel CSME security flaw. FileVault doesn’t use any Intel security features and T2 Macs exclusively use T2.” (ArsTechnica article)
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
The world is holding their breath (some quite literally) as COVID–19 spreads. Conferences, companies, schools, and other organisations are reacting and implementing quarantine or other emergency plans. For many IT organisations this will mean a thorough stress test of their remote infrastructure. Some will have to implement entirely new solutions to deal with this situation.
Whatever situation you are in, I wish you health, strength, and the necessary nerves, patience, and luck to get through this!
tlark: “Wrote a quick and dirty python tool for jamf to rip Crowdstrike off macOS devices due to how their tamper protection can cause edge cases where their install tokens don’t work.”
Erik Gomez: “I really want to know where you are now @lauraroesler because we finally caught up! This includes minor versions as well, not just major.” (follow link for diagram)
Laura Rösler: “We have around 93% of our fleet on #Catalina with the majority on 10.15.3. Luckily, we got rid of our last two 10.12 devices in the last weeks.” (Love MacAdmins bragging about their adoption rates. Well done all!)
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
Of course, you can easily create a new Terminal window from the ‘Shell’ menu or by using the ⌘N (or ⌘T) keyboard shortcut. But in some cases, it can be more useful to use a shell command.
New windows created with the keyboard shortcut or from the menu will always have the home directory ~ as the current working directory. What I want, is a new window that defaults to current working directory or a custom directory that I can provide with an argument:
> new # opens a new terminal window at the current working directory
> new ~/Desktop # opens a new terminal window at ~/Desktop
No luck with AppleScript
After my last success using AppleScript, I thought this would be the best solution again. Unfortunately, this particular piece of the AppleScript dictionary is broken. The make new window or make new tab commands fail with errors and I have tried several combinations.
You can create a new Terminal window with AppleScript using the do script command in the Terminal dictionary. (Not to be confused with do shell script.) So this AppleScript, sort of does what I want, but seems cumbersome.
tell application "Terminal"
do script "cd ~/Desktop"
end tell
If you know of a better way to create a new Terminal window or, even better, a Terminal tab with AppleScript, then please let me know. (No UI Scripting solutions – those have their own issues.) I have a few other ideas where this might come in useful.
Enter the open command
During those web searches, I also found suggestions to use the open command, instead:
> open -a Terminal ~/Documents
Will open a new Terminal window with ~/Documents as the working directory. This is already really close to what I wanted.
I created this function in my shell configuration file (bash, zsh):
# creates a new terminal window
function new() {
if [[ $# -eq 0 ]]; then
open -a "Terminal" "$PWD"
else
open -a "Terminal" "$@"
fi
}
With this, I can now type
> new Projects/desktoppr
and get a new Terminal window there. This is very useful when combined with the history substitution variable!$ (last argument of previous command):
> mkdir Projects/great_new_tool
> new !$
And an unexpected, but useful side effect is that the new function can also open an ssh session in a new window:
tlark: “We have successfully POC’d using ChromeOS for our digital signage. I’ll be ripping out every Mac Mini soon and replacing macOS with ChromeOS. I’ll never have to worry about softwareupdate on these devices again.”
Bryson Tyrrell: “I foresee an indeterminate period of time where we have Macs running ARM or x86. The iMac Pro and Mac Pro I think need to stay x86. iMac and Mac mini I could see going ARM. Shifting over entirely doesn’t feel right with their “pro” focus in the past year.”
Brad Neuberg: “Oh hey Homebrew just completely removed the Python 2.7 cask with a smarmy ”you should have upgraded“ message. Thanks Homebrew!” (via groob)
Mr. Macintosh: “The macOS Catalina 10.15.4 Beta 3 (19E242d) Update is now Available Apple also made a Full .app installer available for Beta 3 Updated Beta 3 AppleSeed Notes include changes around the Kernel Extension Incompatibility warning messages that first arrived in Beta 2.”
There are no ads on my webpage or this newsletter. If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
Another slow-ish news week for MacAdmins. At least what we can talk about. 10.15.4 beta 2 (and iOS 13.4. beta 2 and related) dropped this week. As the last few “Spring Updates” this update has new “features” that will affect managed deployments. You should be using your AppleSeed for IT accounts and start testing the impact on your environment.
Nathaniel Strauss: “10.15.4 beta 2 includes new kext deprecation notices. Occurs every 30 days even if kexts are MDM approved. File feedback! Apple: We are obsessed with the end user experience Also Apple: Recurring notices about software installed by IT with text you don’t understand. ”
There are no ads on my webpage or this newsletter. If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
Somewhat quiet week on the Apple Admin side. I think 10.15.3 is now the point where many MacAdmins are busy rolling out Catalina, or at least seriously preparing for it.
There are no ads on my webpage or this newsletter. If you are enjoying what you are reading here, please spread the word and recommend it to another Mac Admin!
If you want to support me and this website even further, then consider buying one (or all) of my books. It’s like a subscription fee, but you also get a useful book or two extra!
As I noted in my last Weekly News Summary, several open source projects for MacAdmins have completed their transition to Python 3. AutoPkg, JSSImport and outset announced Python 3 compatible versions last week and Munki already had the first Python 3 version last December.
Why?
Apple has included a version of Python 2 with Mac OS X since 10.2 (Jaguar). Python 3.0 was released in 2008 and it was not fully backwards compatible with Python 2. For this reason, Python 2 was maintained and updated alongside Python 3 for a long time. Python 2 was finally sunset on January 1, 2020. Nevertheless, presumably because of the compatibility issues, Apple has always pre-installed Python 2 with macOS and still does so in macOS 10.15 Catalina. With the announcement of Catalina, Apple also announced that in a “future version of macOS” there will be no pre-installed Python of any version.
Scripting language runtimes such as Python, Ruby, and Perl are included in macOS for compatibility with legacy software. Future versions of macOS won’t include scripting language runtimes by default, and might require you to install additional packages. If your software depends on scripting languages, it’s recommended that you bundle the runtime within the app. (macOS 10.15 Catalina Release Notes)
This also applies to Perl and Ruby runtimes and other libraries. I will be focussing on Python because it is used more commonly for MacAdmin tools, but most of this post will apply equally to Perl and Ruby. Just mentally replace “Python” for your preferred language.
The final recommendation is what AutoPkg and Munki are following: they are bundling their own Python runtime.
How to get Python
There is a second bullet in the Catalina release notes, though:
Use of Python 2.7 isn’t recommended as this version is included in macOS for compatibility with legacy software. Future versions of macOS won’t include Python 2.7. Instead, it’s recommended that you run python3 from within Terminal. (51097165)
This is great, right? Apple says there is a built-in Python 3! And it’s pre-installed? Just move all your scripts to Python 3 and you’ll be fine!
Unfortunately, not quite. The python3 binary does exist on a ‘clean’ macOS, but it is only a stub tool, that will prompt a user to download and install the Command Line Developer Tools (aka “Developer Command Line Tools” or “Command Line Tools for Xcode”). This is common for many tools that Apple considers to be of little interest to ‘normal,’ non-developer users. Another common example is git.
When you install Xcode, you will also get all the Command Line Developer Tools, including python3 and git. This is useful for developers, who may want to use Python scripts for build operation, or for individuals who just want to ‘play around’ or experiment with Python locally. For MacAdmins, it adds the extra burden of installing and maintaining either the Command Line Developer Tools or the full Xcode install.
Python Versions, a multitude of Snakes
After installing Xcode or the Command Line Developer Tools, you can check the version of python installed: (versions on macOS 10.15.3 with Xcode 11.3.1)
When you go on the download page for Python.org, you will get Python 3.8.1 (as of this writing). But, on that download page, you will also find download links for “specific versions” which include (as of this writing) versions 3.8.1, 3.7.6, 3.6.10, 3.5.9, and the deprecated 2.7.17.
The thing is, that Python isn’t merely split into two major release versions, which aren’t fully compatible with each other, but there are several minor versions of Python 3, which aren’t fully compatible with each other, but are still being maintained in parallel.
Developers (individuals, teams, and organisations) that use Python will often hold on to a specific minor (and sometimes even patch) version for a project to avoid issues and bugs that might appear when changing the run-time.
When you install the latest version of Munki, it will install a copy of the Python framework in /usr/local/munki/ and create a symbolic link to that python binary at /usr/local/munki/python. You can check its version as well:
% /usr/local/munki/python --version
Python 3.7.4
All the Python code files for Munki will have a shebang (the first line in the code file) of
#!/usr/local/munki/python
This ensures that Munki code files use this particular instance of Python and no other copy of Python that may have been installed on the system.
The latest version of AutoPkg has a similar approach:
In both cases the python binary is a symbolic link. This allows the developer to change the symbolic link to point to a different Python framework. The shebangs in the all the code files point to the symbolic link, which can be changed to point to a different Python framework.
This is useful for testing and debugging. Could MacAdmins use this to point both tools to the same Python framework? Should they?
The Bridge to macOS
On top of all these different versions of Python itself, many scripts, apps, and tools written in Python rely on ‘Python modules.’ These are libraries (or frameworks) of code for a certain task, that can be downloaded and included with a Python installation to extend the functionality of Python.
The most relevant of these modules for MacAdmins is the “Python Objective-C Bridge.” This module allows Python code to access and use the native macOS Cocoa and CoreFoundation Frameworks. This not only allows for macOS native GUI applications to be written in Python (e.g. AutoDMG and Munki’s Managed Software Center [update: MSC was re-written in Swift last year]), but also allows short scripts to access system functions. This is sometimes necessary to get a data that matches what macOS applications “see” rather than what the raw unix tools see.
For example, the defaults tool can be used to read the value of property lists on disk. But those might not necessarily reflect the actual preference value an application sees, because that value might be controlled by a different plist file or configuration profile.
You could build a tool with Swift or Objective-C that uses the proper frameworks to get the “real” preference value. Or you can use Python with the Objective-C bridge:
#!/usr/bin/python
from Foundation import CFPreferencesCopyAppValue
print CFPreferencesCopyAppValue("idleTime", "com.apple.screensaver")
Three simple lines of Python code. This will work with the pre-installed Python 2.7, because Apple also pre-installs the Python Objective-C bridge with that. When you try this with the Developer Tools python3 you get an error:
ModuleNotFoundError: No module named 'Foundation'
This is because the Developer Tools do not include the Objective-C bridge in the installation. You could easily add it with:
> sudo python3 -m pip install pyobjc
But again, while this command is “easy” enough for a single user on a single Mac, it is just the beginning of a Minoan labyrinth of management troubles.
Developers and MacAdmins, have to care about the version of the Python they install, as well as the list of modules and their versions, for each Python version.
It is as if the Medusa head kept growing more smaller snakes for every snake you cut off.
(Ok, I will ease off with Greek mythology metaphors.)
You can get a list of modules included with the AutoPkg and the Munki project with:
> /usr/local/munki/python -m pip list
> /usr/local/autopkg/python -m pip list
You will see that not only do Munki and AutoPkg include different versions of Python, but also a different list of modules. While Munki and AutoPkg share many modules, their versions might still differ.
Snake Herding Solutions
Apple’s advice in the Catalina Release Notes is good advice:
It’s recommended that you bundle the runtime within the app.
Rather than the MacAdmin managing a single version of Python and all the modules for every possible solution, each tool or application should provide its own copy of Python and its required modules.
This might seem wasteful. A full Python 3 Framework uses about 80MB of disk space, plus some extra for the modules. But it is the safest way to ensure that the tool or application gets the correct version of Python and all the modules. Anything else will quickly turn into a management nightmare.
This is the approach that Munki and AutoPkg have chosen. But what about smaller, single script solutions? For example simple Python scripts like quickpkg or prefs-tool?
Should I bundle my own Python framework with quickpkg or prefs-tool? I think that would be overkill and I am not planning to do that. I think the solution that Joseph Chilcote chose for the outset tool is a better approach for less complex Python scripts.
In this case, the project is written to run with Python 3 and generic enough to not require a specific version or extra modules. An admin who wants to use this script or tool, can change the shebang (the first line in the script) to point to either the Developer Tool python3, the python3 from the standard Python 3 installer or a custom Python version, such as the Munki python. A MacAdmin would have to ensure that the python binary in the shebang is present on the Mac when the tool runs.
You can also choose to provide your organization’s own copy Python with your chosen set of modules for all your management Python scripts and automations. You could build this with the relocatable Python tool and place it in a well-known location the clients. When updates for the Python run-time or modules are required, you can build and push them with your management system. (Thanks to Nathaniel Strauss for pointing out this needed clarifying.)
When you build such scripts and tools, it is important to document which Python versions (and module versions) you have tested the tool with.
(I still have to do that for my Python tools.)
What about /usr/bin/env python?
The env command will determine the path to the python binary in the current environment. (i.e. using the current PATH) This is useful when the script has to run in various environments where the location of the python binary is unknown.
This is useful when developers want to use the same script in different environments across different computers, user accounts, and platforms. However, this renders the actual version of python that will interpret the script completely unpredictable.
Not only is it impossible to predict which version of Python will interpret a script, but you cannot depend on any modules being installed (or their versions) either.
For MacAdmin management scripts and tools, a tighter control is necessary. You should use fixed, absolute paths in the shebang.
Conclusion
Managing Python runtimes might seem like a hopeless sisyphean task. I believe Apple made the right choice to not pre-install Python any more. Whatever version and pre-selection of module versions Apple would have chosen, it would only have been the correct combination for a few Python solutions and developers.
While it may seem wasteful to have a multitude of copies of the Python frameworks distributed through out the system, it is the easiest and most manageable solution to ensure that each tool or application works with the expected combination of run-time and modules.