-
-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathmacos-config.sh
More file actions
executable file
·2469 lines (1956 loc) · 106 KB
/
Copy pathmacos-config.sh
File metadata and controls
executable file
·2469 lines (1956 loc) · 106 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env zsh
set -Eeuxo pipefail
# This file is sourced by install.sh, and the line above re-enables errexit in
# the caller's shell. That silently defeated survey mode: the ERR trap recorded
# a failure and the run aborted on it anyway, one line at a time, which is the
# behaviour the survey exists to avoid. See the rationale in install.sh.
if (( ${SURVEY:-0} )); then
set +e
fi
# Record when this run started, for `tools/audit_defaults.py --menubar`. A
# declaration older than this stamp has been applied at least once, which is
# what separates a key macOS refused from one the script has never reached: a
# plist timestamp cannot say, since it covers a whole domain and moves whenever
# anything else in that domain is touched.
#
# A file rather than a `defaults` key, on two counts. The audit parses this
# script for `defaults` calls, so a stamp written that way would come back as
# one more declaration to check, under a domain no system binary reads. And the
# killall block at the foot of this file takes cfprefsd down, which can discard
# a write it has not flushed yet.
mkdir -p "${HOME}/.local/state"
date +%s > "${HOME}/.local/state/macos-config-last-run"
###############################################################################
# Plist and preferences #
###############################################################################
# There is a couple of plist editing tools:
#
# * defaults
# Triggers update notification update to running process, but usage is
# tedious.
#
# * /usr/libexec/PlistBuddy
# Great for big update, can create non-existing files.
#
# * plutil
# Can manipulate arrays and dictionaries with key paths.
#
# Sources:
# * https://scriptingosx.com/2016/11/editing-property-lists/
# * https://scriptingosx.com/2018/02/defaults-the-plist-killer/
# * https://apps.tempel.org/PrefsEditor/index.php
#
# Some of these changes still require a logout/restart to take effect.
# Close any open System Settings panes, to prevent them from overriding
# settings we’re about to change
osascript -e 'tell application "System Settings" to quit'
###############################################################################
# Permissions and Access #
###############################################################################
# CLI to open the automation preference panel:
# ❯ open "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation"
#
# Raw list of permission names:
# ❯ strings /System/Library/PrivateFrameworks/TCC.framework/Versions/Current/Resources/tccd | grep "^kTCCService[A-Z a-z]" | sort | uniq
# Ask for the administrator password upfront
sudo --validate
# Update existing `sudo` time stamp until script has finished, so a standalone
# run does not re-prompt every 5 minutes (the timeout pinned further below).
# Harmless duplicate of install.sh's keep-alive when sourced from there.
while true; do sleep 60; sudo --non-interactive true; kill -0 "$$" || exit; done 2> /dev/null &
# tccutil commands below only works if SIP is disabled.
if (( ${SIP_DISABLED:-0} )); then
echo "System Integrity Protection (SIP) is disabled."
# List existing entries for debug.
sudo tccutil --list
# Add Terminal as a developer tool. Any app referenced in the hidden Developer
# Tools category will be able to bypass GateKeeper.
# Source: an Apple Xcode engineer at:
# https://news.ycombinator.com/item?id=23278629
# https://news.ycombinator.com/item?id=23273867
sudo spctl developer-mode enable-terminal
sudo tccutil --service "kTCCServiceDeveloperTool" --insert "com.apple.Terminal"
sudo tccutil --service "kTCCServiceDeveloperTool" --enable "com.apple.Terminal"
# Since 10.15, BSD-userland processes now also deal with sandboxing, since the
# BSD syscall ABI is now reimplemented in terms of macOS security capabilities.
# Source: https://news.ycombinator.com/item?id=23274213
#
# Also, some plist preferences files are not readable either by the user or root
# unless the Terminal.app gets Full Disk Access permission.
#
# ❯ cat /Users/kde/Library/Preferences/com.apple.AddressBook.plist
# cat: /Users/kde/Library/Preferences/com.apple.AddressBook.plist: Operation not permitted
#
# ❯ sudo cat /Users/kde/Library/Preferences/com.apple.AddressBook.plist
# Password:
# cat: /Users/kde/Library/Preferences/com.apple.AddressBook.plist: Operation not permitted
# Grant Full Disk Access permission
for app (
"com.apple.Terminal"
"/Applications/BlockBlock.app"
"/Applications/KnockKnock.app"
); do
sudo tccutil --service "kTCCServiceSystemPolicyAllFiles" --insert "${app}"
sudo tccutil --service "kTCCServiceSystemPolicyAllFiles" --enable "${app}"
done
# Grant Accessibility permission.
#
# The Logitech entry is the daemon nested at
# `Logi Options.app/Contents/Support/LogiMgrDaemon.app`, not the GUI. The
# daemon is what launchd runs, and it is what posts the synthetic keystrokes
# and triggers the system actions the trackball buttons are bound to in the
# Logi Options section below, so without this the button map is inert.
# Referenced by bundle ID because the path is nested inside another bundle.
for app (
"com.logitech.manager.daemon"
"/Applications/Amethyst.app"
"/Applications/MonitorControl.app"
); do
sudo tccutil --insert "${app}"
sudo tccutil --enable "${app}"
done
fi
###############################################################################
# General UI/UX #
###############################################################################
# Transform ' | "model" = <"MacBookAir8,1">' to 'MBA'
COMPUTER_MODEL_SHORTHAND=$(ioreg -c IOPlatformExpertDevice -d 2 -r | grep '"model" =' | python3 -c "print(''.join([c for c in input() if c.isupper()]))")
COMPUTER_NAME="$(whoami)-${COMPUTER_MODEL_SHORTHAND}"
# Set computer name (as done via System Settings → General → About)
sudo scutil --set ComputerName "${COMPUTER_NAME}"
sudo scutil --set HostName "${COMPUTER_NAME}"
sudo scutil --set LocalHostName "${COMPUTER_NAME}"
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName -string "${COMPUTER_NAME}"
# Remove default content
sudo rm -rf "${HOME}/Public/Drop Box"
rm -rf "${HOME}/Public/.com.apple.timemachine.supported"
rm -f "${HOME}/Desktop/SamsungPortableSSD.app"
# Disable the sound effects on boot
sudo nvram SystemAudioVolume=" "
# Enable ctrl+option+cmd to drag windows.
defaults write com.apple.universalaccess NSWindowShouldDragOnGesture -string "YES"
# Enable auto dark mode
defaults write NSGlobalDomain AppleInterfaceStyle -string "Dark"
defaults write NSGlobalDomain AppleInterfaceStyleSwitchesAutomatically -bool true
# Set highlight color to green
#defaults write NSGlobalDomain AppleHighlightColor -string "0.764700 0.976500 0.568600"
# Enable graphite appearance.
#defaults write NSGlobalDomain AppleAquaColorVariant -int 6
# Set sidebar icon size to medium
defaults write NSGlobalDomain NSTableViewDefaultSizeMode -int 2
# Always show scrollbars
defaults write NSGlobalDomain AppleShowScrollBars -string "Always"
# Possible values: `WhenScrolling`, `Automatic` and `Always`
# Disable the over-the-top focus ring animation
defaults write NSGlobalDomain NSUseAnimatedFocusRing -bool false
# Adjust toolbar title rollover delay
defaults write NSGlobalDomain NSToolbarTitleViewRolloverDelay -float 0
# Disable smooth scrolling
# (Uncomment if you’re on an older Mac that messes up the animation)
#defaults write NSGlobalDomain NSScrollAnimationEnabled -bool false
# Increase window resize speed for Cocoa applications
defaults write NSGlobalDomain NSWindowResizeTime -float 0.001
# Ask to keep changes when closing documents
defaults write NSGlobalDomain NSCloseAlwaysConfirmsChanges -bool true
# Don't keep recent items for Documents, Apps and Servers.
osascript << EOF
tell application "System Events"
tell appearance preferences
set recent documents limit to 5
set recent applications limit to 5
set recent servers limit to 5
end tell
end tell
EOF
# Expand save panel by default
defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true
# Expand print panel by default
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true
# Automatically quit printer app once the print jobs complete
defaults write com.apple.print.PrintingPrefs "Quit When Finished" -bool true
# Disable the “Are you sure you want to open this application?” dialog
defaults write com.apple.LaunchServices LSQuarantine -bool false
# Remove duplicates in the “Open With” menu.
# The old `-kill -r -domain local -domain system -domain user` incantation no
# longer works: `lsregister` answers "-kill option has been removed because it
# was dangerous and no longer useful" and exits non-zero, which aborts this
# script. `-domain` is gone from the usage too, replaced by `-all` taking a
# comma-separated domain list. `-gc` now covers what `-kill` was wanted for:
# it garbage-collects the stale entries that produce the duplicates.
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -gc -r -all local,system,user
# Display ASCII control characters using caret notation in standard text views
# Try e.g. `cd /tmp; unidecode "\x{0000}" > cc.txt; open -e cc.txt`
defaults write NSGlobalDomain NSTextShowsControlCharacters -bool true
# Keep all windows open from previous session.
defaults write com.apple.systempreferences NSQuitAlwaysKeepsWindows -bool true
# Disable automatic termination of inactive apps
defaults write NSGlobalDomain NSDisableAutomaticTermination -bool true
# Disable the crash reporter
defaults write com.apple.CrashReporter DialogType -string "none"
# Set Help Viewer windows to non-floating mode
defaults write com.apple.helpviewer DevMode -bool true
# Reveal IP address, hostname, OS version, etc. when clicking the clock
# in the login window
sudo defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo -string "HostName"
# Disable automatic capitalization as it’s annoying when typing code
defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false
# Disable smart dashes as they’re annoying when typing code
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false
# Disable automatic period substitution as it’s annoying when typing code
defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false
# Disable smart quotes as they’re annoying when typing code
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false
# Disable auto-correct
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false
# Set a custom wallpaper image. `DefaultDesktop.jpg` is already a symlink, and
# all wallpapers are in `/Library/Desktop Pictures/`. The default is `Wave.jpg`.
#rm -rf "${HOME}/Library/Application Support/Dock/desktoppicture.db"
#sudo rm -rf /System/Library/CoreServices/DefaultDesktop.jpg
#sudo ln -s /path/to/your/image /System/Library/CoreServices/DefaultDesktop.jpg
# Play user interface sound effects
defaults write -globalDomain "com.apple.sound.uiaudio.enabled" -int 0
# Play feedback when volume is changed
defaults write -globalDomain "com.apple.sound.beep.feedback" -int 0
##############################################################################
# Menubar #
##############################################################################
# Disable transparency in the menu bar and elsewhere on Yosemite
#defaults write com.apple.universalaccess reduceTransparency -bool true
# Enable input menu in menu bar.
defaults write com.apple.TextInputMenu visible -bool true
# Control Center owns the menu bar since Big Sur. The SystemUIServer
# menuExtras/dontAutoLoad arrays that used to live here were inert: five of the
# seven "Menu Extras/*.menu" bundles they named no longer ship, and
# SystemUIServer silently drops every entry whose bundle it cannot load.
#
# A module is placed with a single per-host integer. The three states below are
# read back from a menu bar arranged by hand, each one matched against what the
# bar actually shows: Sound at 18 puts the output device icon up, UserSwitcher
# at 18 the account icon, while Battery at 8 and ScreenMirroring at 2 are both
# absent from it.
#
# 2 hidden from the menu bar and from Control Center
# 8 in Control Center only
# 18 in the menu bar and in Control Center
#
# Run `python3 ./tools/audit_defaults.py --menubar ./macos-config.sh` to diff
# this block against the live system, so a change made in the UI can be
# replayed here.
# Menu bar.
defaults -currentHost write com.apple.controlcenter Sound -int 18
defaults -currentHost write com.apple.controlcenter UserSwitcher -int 18
defaults -currentHost write com.apple.controlcenter WiFi -int 18
# Control Center only.
defaults -currentHost write com.apple.controlcenter AccessibilityShortcuts -int 8
defaults -currentHost write com.apple.controlcenter AirDrop -int 8
defaults -currentHost write com.apple.controlcenter Battery -int 8
defaults -currentHost write com.apple.controlcenter Bluetooth -int 8
defaults -currentHost write com.apple.controlcenter Display -int 8
defaults -currentHost write com.apple.controlcenter FocusModes -int 8
defaults -currentHost write com.apple.controlcenter Hearing -int 8
defaults -currentHost write com.apple.controlcenter KeyboardBrightness -int 8
defaults -currentHost write com.apple.controlcenter MusicRecognition -int 8
defaults -currentHost write com.apple.controlcenter NowPlaying -int 8
defaults -currentHost write com.apple.controlcenter StageManager -int 8
defaults -currentHost write com.apple.controlcenter VoiceControl -int 8
defaults -currentHost write com.apple.controlcenter Weather -int 8
# Hidden everywhere.
defaults -currentHost write com.apple.controlcenter ScreenMirroring -int 2
# Items with no module code of their own are plain status items, keyed by the
# name AppKit files them under.
defaults write com.apple.controlcenter "NSStatusItem Visible BentoBox" -bool true
defaults write com.apple.controlcenter "NSStatusItem Visible FaceTime" -bool false
# Mirror the Live Activities of a nearby iPhone into the menu bar.
defaults write com.apple.controlcenter RemoteLiveActivitiesEnabled -bool true
# Spotlight and Siri each keep their menu bar icon in their own domain.
defaults -currentHost write com.apple.Spotlight MenuItemHidden -bool true
defaults write com.apple.Siri StatusMenuVisible -bool false
# Three keys macOS still stores here and no menu bar process reads any more,
# left behind by earlier releases. `Spotlight` and `VPN` were module codes
# before those two moved out of Control Center, and `AirplayRecieverEnabled` is
# the misspelling Apple shipped for a while alongside the corrected key set in
# the Security section. A `defaults delete` on an already absent key fails, so
# these have to tolerate their own success.
defaults -currentHost delete com.apple.controlcenter Spotlight || true
defaults -currentHost delete com.apple.controlcenter VPN || true
defaults -currentHost delete com.apple.controlcenter AirplayRecieverEnabled || true
# Menu bar clock. `ShowDate` is a three-state enum, not a boolean: 0 shows the
# date when the menu bar has room for it, 1 always, 2 never.
defaults write com.apple.menuextra.clock FlashDateSeparators -bool false
defaults write com.apple.menuextra.clock IsAnalog -bool false
defaults write com.apple.menuextra.clock Show24Hour -bool true
defaults write com.apple.menuextra.clock ShowDate -int 0
defaults write com.apple.menuextra.clock ShowDayOfWeek -bool true
defaults write com.apple.menuextra.clock ShowSeconds -bool false
defaults write com.apple.menuextra.clock TimeAnnouncementsEnabled -bool false
# Autohide dock and menubar.
#defaults write NSGlobalDomain _HIHideMenuBar -bool true
##############################################################################
# Security #
##############################################################################
# Also see: https://github.com/drduh/macOS-Security-and-Privacy-Guide
# The application firewall configuration moved out of
# /Library/Preferences/com.apple.alf in macOS 15: defaults writes there are
# silently ignored. socketfilterfw is the supported CLI. Firewall events now
# land in the unified log, and the old logging toggle is gone.
# Enable firewall (mSCP: system_settings_firewall_enable).
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
# Enable stealth mode (mSCP: system_settings_firewall_stealth_mode_enable).
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setstealthmode on
# Do not automatically allow built-in and downloaded signed software to
# receive incoming connections.
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsigned off
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setallowsignedapp off
# Apply configuration on all network interfaces.
# $ networksetup -listallnetworkservices
# An asterisk (*) denotes that a network service is disabled.
# Thunderbolt Ethernet Slot 1, Port 1
# *Thunderbolt Ethernet Slot 1, Port 2
# Wi-Fi
# iPhone USB
# Bluetooth PAN
# Thunderbolt Bridge
net_interfaces=$(networksetup -listallnetworkservices | awk '{gsub(/^*/,""); if(NR>1)print}')
for net_service (${(f)net_interfaces}); do
# Use Cloudflare's fast and privacy friendly DNS.
networksetup -setdnsservers "${net_service}" 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
# Clear out all search domains.
networksetup -setsearchdomains "${net_service}" "Empty"
# Setup 10G NIC.
if [ "${net_service}" = "Thunderbolt Ethernet Slot 1, Port 2" ]; then
networksetup -setMTU "${net_service}" 9000
fi
done
# Disable wifi captive portal
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.captive.control Active -bool false
# Both remote-access toggles below go through `systemsetup`, which needs Full
# Disk Access on its parent process and exits non-zero without it. Unguarded
# they abort the whole script under `set -e`, taking every hardening step that
# follows down with them: that is why only `com.apple.smbd`, disabled back when
# this block was still reachable, is pinned off on this machine. mSCP hits the
# same wall ("Requires supervision") and checks nothing but the `launchctl
# disable` state, so the guard belongs on the `systemsetup` call, which is a
# convenience for a host that has granted the access, and never on the
# `launchctl` line that carries the compliance and must still fail loudly.
# Disable remote apple events (mSCP: system_settings_rae_disable).
sudo systemsetup -setremoteappleevents off || true
sudo launchctl disable system/com.apple.AEServer
# Disable remote login (SSH) and pin the service off across upgrades
# (mSCP: system_settings_ssh_disable). `-f` skips the confirmation prompt.
sudo systemsetup -f -setremotelogin off || true
sudo launchctl disable system/com.openssh.sshd
# Explicitly disable the remaining sharing services. Most are already off by
# default, but pinning them keeps a known-good state across macOS upgrades.
# Screen sharing (CIS 2.4.3)
sudo launchctl disable system/com.apple.screensharing
# Remote management / Apple Remote Desktop (CIS 2.4.9)
sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -deactivate -stop
# File sharing over SMB (CIS 2.4.8)
sudo launchctl disable system/com.apple.smbd
# Printer sharing (CIS 2.4.4)
sudo cupsctl --no-share-printers
# DVD or CD sharing (CIS 2.4.6)
sudo launchctl disable system/com.apple.ODSAgent
# NFS server (CIS 4.5)
sudo launchctl disable system/com.apple.nfsd
# Apache HTTP server (CIS 4.4)
sudo launchctl disable system/org.apache.httpd
# Disable Internet Sharing. Off by default, this pins it; only a
# configuration profile can prevent re-enablement
# (mSCP: system_settings_internet_sharing_disable).
sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.nat NAT -dict Enabled -int 0
# Disable Bluetooth sharing (mSCP: system_settings_bluetooth_sharing_disable).
defaults -currentHost write com.apple.Bluetooth PrefKeyServicesEnabled -bool false
# Disable AirPlay receiver. Apple shipped a misspelled key for a while and both
# spellings had to be pinned: only the correct one is left in ControlCenter now
# (mSCP: system_settings_airplay_receiver_disable).
defaults -currentHost write com.apple.controlcenter AirplayReceiverEnabled -bool false
# Disable SMB guest access (mSCP: system_settings_guest_access_smb_disable).
sudo sysadminctl -smbGuestAccess off
# Disable the root account by pointing its shell at /usr/bin/false (CIS 5.6).
sudo dscl . -create /Users/root UserShell /usr/bin/false
# Disable Power Nap, so the machine stays asleep instead of waking to sync
# mail and updates (CIS 2.9).
sudo pmset -a powernap 0
# Disable wake-on modem
# XXX setwakeonmodem returns "Wake On Modem: Not supported on this machine." for now.
#sudo systemsetup -setwakeonmodem off
sudo pmset -a ring 0
# Disable wake-on LAN. Not every machine has the hardware: a VM answers "Wake
# On Network Access: Not supported on this machine" and exits non-zero, which
# is a statement about the hardware rather than a failure to act on.
sudo systemsetup -setwakeonnetworkaccess off || true
sudo pmset -a womp 0
# Display login window as name and password
sudo defaults write /Library/Preferences/com.apple.loginwindow SHOWFULLNAME -bool true
# Do not show password hints
sudo defaults write /Library/Preferences/com.apple.loginwindow RetriesUntilHint -int 0
# Remove password hints already stored on user records
# (mSCP: os_password_hint_remove).
for u ($(dscl . -list /Users UniqueID | awk '$2 > 500 {print $1}')); do
sudo dscl . -delete "/Users/${u}" hint &> /dev/null || true
done
# Disable guest account login
sudo defaults write /Library/Preferences/com.apple.loginwindow GuestEnabled -bool false
# Remove the Guest home folder (mSCP: os_guest_folder_removed).
sudo rm -rf /Users/Guest
# Disable automatic login
sudo defaults delete /Library/Preferences/com.apple.loginwindow autoLoginUser || true
# Unlocking a locked session requires the password of the signed-in user,
# not that of any admin (mSCP: os_unlock_active_user_session_disable). The
# Platform SSO variant of the rule does not apply to a personal machine.
sudo security -q authorizationdb write system.login.screensaver "authenticate-session-owner"
# Require an administrator password for the system-wide preference panes,
# and do not share their unlocked state between panes
# (mSCP: system_settings_system_wide_preferences_configure).
for section (
system.preferences
system.preferences.energysaver
system.preferences.network
system.preferences.printing
system.preferences.sharing
system.preferences.softwareupdate
system.preferences.startupdisk
system.preferences.timemachine
); do
authdb_plist="/tmp/${section}.plist"
sudo security -q authorizationdb read "${section}" > "${authdb_plist}"
for key_type_value (
"class string user"
"shared bool false"
"authenticate-user bool true"
"session-owner bool false"
"group string admin"
); do
parts=(${=key_type_value})
/usr/libexec/PlistBuddy -c "Set :${parts[1]} ${parts[3]}" "${authdb_plist}" 2> /dev/null \
|| /usr/libexec/PlistBuddy -c "Add :${parts[1]} ${parts[2]} ${parts[3]}" "${authdb_plist}"
done
sudo security -q authorizationdb write "${section}" < "${authdb_plist}"
rm -f "${authdb_plist}"
done
# A lost machine might be lucky and stumble upon a Good Samaritan.
sudo defaults write /Library/Preferences/com.apple.loginwindow LoginwindowText \
"Found this computer? Please contact me at lost@deldycke.net"
# Automatically lock the login keychain for inactivity after 6 hours.
security set-keychain-settings -t 21600 -l "${HOME}/Library/Keychains/login.keychain"
# Destroy FileVault key when going into standby mode, forcing a re-auth.
# Source: https://web.archive.org/web/20160114141929/https://training.apple.com/pdf/WP_FileVault2.pdf
sudo pmset destroyfvkeyonstandby 1
# Add sudo 2FA based on Touch ID. Source: https://twitter.com/cabel/status/931292107372838912
# sudo tee -a "/etc/pam.d/sudo" <<-EOF
# auth sufficient pam_tid.so
# EOF
# Enable FileVault (if not already enabled)
# This requires a user password, and outputs a recovery key that should be
# copied to a secure location. Both want someone at the keyboard, so the
# attempt is skipped without a terminal on stdin: unattended it can only fail,
# and it would take the rest of this script down with it.
if [[ -t 0 ]] && [[ $(sudo fdesetup status | head -1) == "FileVault is Off." ]]; then
sudo fdesetup enable -user $(whoami)
fi
# Disable automatic login when FileVault is enabled
#sudo defaults write /Library/Preferences/com.apple.loginwindow DisableFDEAutoLogin -bool true
# Disable Bonjour multicast advertisements (mSCP: os_bonjour_disable)
sudo defaults write /Library/Preferences/com.apple.mDNSResponder.plist NoMulticastAdvertisements -bool true
# Show location icon in menu bar when System Services request your location.
sudo defaults write /Library/Preferences/com.apple.locationmenu.plist ShowSystemServices -bool true
# Install certs
wget -O "${HOME}/NextDNS.cer" https://nextdns.io/ca
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${HOME}/NextDNS.cer"
rm -rfv "${HOME}/NextDNS.cer"
# Secure home folders from other local users, non-recursively as mSCP does
# (mSCP: os_home_folders_secure).
for home_dir (/Users/*(N/)); do
[[ "${home_dir:t}" == "Shared" ]] && continue
sudo chmod og-rwx "${home_dir}"
done
# Strip world-write from system support folders and system-wide apps
# (mSCP: os_world_writable_system_folder_configure /
# os_system_wide_applications_configure).
sudo command find /System/Volumes/Data/System -type d -perm -2 ! -path '*downloadDir*' ! -path '*locks*' -exec chmod o-w '{}' + 2> /dev/null || true
sudo command find /Applications -iname '*.app' -type d -perm -2 -exec chmod -R o-w '{}' + 2> /dev/null || true
# Keep system.log for 90 days. The application firewall now logs to the
# unified log: there is no appfirewall.log rotation to configure anymore.
sudo perl -p -i -e 's/rotate=seq compress file_max=5M all_max=50M/rotate=utc compress file_max=5M ttl=90/g' "/etc/asl.conf"
# Log authentication events for 90 days.
sudo perl -p -i -e 's/rotate=seq file_max=5M all_max=20M/rotate=utc file_max=5M ttl=90/g' "/etc/asl/com.apple.authd"
# Log installation events for a year (mSCP: os_install_log_retention_configure).
# The old format=bsd anchor is gone from the macOS 26 config, so replace the
# whole install.log line, mSCP-style, which also drops the all_max cap. Pin
# the BSD sed: Homebrew's GNU sed shadows it in PATH and parses -i differently.
sudo /usr/bin/sed -i '' "s/\* file \/var\/log\/install.log.*/\* file \/var\/log\/install.log format='\$\(\(Time\)\(JZ\)\) \$Host \$\(Sender\)\[\$\(PID\\)\]: \$Message' rotate=utc compress file_max=50M size_only ttl=365/g" /etc/asl/com.apple.install
# auditd is deprecated by Apple and ships disabled since macOS 14, without
# even a stub config: seed /etc/security/audit_control from the example and
# turn the service back on (mSCP: audit_auditd_enabled).
if [[ ! -e /etc/security/audit_control && -e /etc/security/audit_control.example ]]; then
sudo cp /etc/security/audit_control.example /etc/security/audit_control
fi
# Audit authentication, administrative, file deletion and permission change
# events on top of the login/logout defaults (mSCP: audit_flags_*).
sudo perl -p -i -e 's|^flags:.*|flags:lo,aa,ad,fd,fm,-all,^-fa,^-fc,^-cl|' /etc/security/audit_control
# Rotate audit trails at 10M and keep 30 days of them
# (mSCP: audit_retention_configure).
sudo perl -p -i -e 's|^filesz:.*|filesz:10M|' /etc/security/audit_control
sudo perl -p -i -e 's|^expire-after:.*|expire-after:30d|' /etc/security/audit_control
sudo launchctl enable system/com.apple.auditd
sudo launchctl bootstrap system /System/Library/LaunchDaemons/com.apple.auditd.plist || true
sudo audit -i || true
# Tighten audit config and trail ownership, modes and ACLs
# (mSCP: audit_control_* / audit_files_* / audit_folder*_configure /
# audit_acls_*).
sudo chown root:wheel /etc/security/audit_control
sudo chmod 440 /etc/security/audit_control
sudo chmod -N /etc/security/audit_control
if [[ -d /var/audit ]]; then
sudo chown root:wheel /var/audit
sudo chmod 700 /var/audit
sudo zsh -c 'chmod -RN /var/audit && chown root:wheel /var/audit/* && chmod 440 /var/audit/*' 2> /dev/null || true
fi
# Cap sudo credential caching at 5 minutes (the macOS default, pinned: CIS
# prefers 0 but that would prompt on every sudo line of this very script),
# keep per-tty timestamps and log allowed commands
# (mSCP: os_sudo_timeout_configure / os_sudoers_timestamp_type_configure /
# os_sudo_log_enforce).
sudo command find /etc/sudoers* -type f -exec /usr/bin/sed -i '' '/timestamp_timeout/d; /timestamp_type/d; /!tty_tickets/d; /!log_allowed/d' '{}' \;
sudo tee /etc/sudoers.d/mscp.tmp > /dev/null <<EOF
Defaults timestamp_timeout=5
Defaults log_allowed
EOF
sudo chmod 440 /etc/sudoers.d/mscp.tmp
# Validate before install: a broken sudoers.d file locks sudo out. The .tmp
# name is skipped by sudo (names with a dot are ignored) until the rename.
sudo visudo -c -f /etc/sudoers.d/mscp.tmp
sudo mv /etc/sudoers.d/mscp.tmp /etc/sudoers.d/mscp
# Activates Touch ID for sudo and make it persistent.
# See: https://sixcolors.com/post/2023/08/in-macos-sonoma-touch-id-for-sudo-can-survive-updates/
sudo cp /etc/pam.d/sudo_local.template /etc/pam.d/sudo_local
# Pin the BSD sed, like the asl edits above: with bare sed and no gnubin on
# PATH yet (fresh machine), BSD sed would eat the script as its -i suffix.
sudo /usr/bin/sed -i '' "s/#auth/auth/" /etc/pam.d/sudo_local
###############################################################################
# Privacy: telemetry and data sharing #
###############################################################################
# Do not auto-submit diagnostics and usage data to Apple, nor share crash
# data with app developers. This is the plist behind System Settings →
# Privacy & Security → Analytics & Improvements
# (mSCP: system_settings_diagnostics_reports_disable).
sudo defaults write "/Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist" AutoSubmit -bool false
sudo defaults write "/Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist" ThirdPartyDataSubmit -bool false
# Opt out of sharing Siri and dictation recordings with Apple, and of search
# queries data sharing (mSCP: system_settings_improve_siri_dictation_disable
# / system_settings_improve_search_disable).
defaults write com.apple.assistant.support 'Siri Data Sharing Opt-In Status' -int 2
defaults write com.apple.assistant.support 'Search Queries Data Sharing Status' -int 2
# Do not donate audio recordings to improve accessibility voice features
# (mSCP: system_settings_improve_assistive_voice_disable).
defaults write com.apple.Accessibility AXSAudioDonationSiriImprovementEnabled -bool false
# Disable Siri. Only the allowAssistant configuration profile key can
# prevent re-enablement (mSCP: system_settings_siri_disable).
defaults write com.apple.assistant.support 'Assistant Enabled' -bool false
# Opt out of Apple personalized advertising
# (mSCP: system_settings_personalized_advertising_disable).
defaults write com.apple.AdLib allowApplePersonalizedAdvertising -bool false
###############################################################################
# Privacy: metadata cache cleanup #
###############################################################################
# Wipe the local caches macOS keeps about what I type, preview and download.
# Adapted from the drduh guide and alichtman/stronghold, made idempotent and
# safe under `set -e`. Caches only: nothing is frozen, so macOS stays free to
# rebuild them as normal.
# Clear the keyboard / spelling / suggestion language models. macOS will
# repopulate them from future typing.
for dir (
"${HOME}/Library/LanguageModeling"
"${HOME}/Library/Spelling"
"${HOME}/Library/Suggestions"
); do
[[ -d "${dir}" ]] || continue
sudo find "${dir}" -mindepth 1 -delete || true
done
# Flush the QuickLook thumbnail cache, which retains previews (and their
# metadata) of files even from removed or encrypted volumes.
qlmanage -r cache &> /dev/null || true
ql_dir="${HOME}/Library/Application Support/Quick Look"
[[ -d "${ql_dir}" ]] && sudo find "${ql_dir}" -mindepth 1 -delete || true
# Clear Siri's local analytics database.
rm -fv "${HOME}/Library/Assistant/SiriAnalytics.db" || true
# Wipe the LaunchServices quarantine log (per-download source URLs and
# timestamps). LaunchServices repopulates it on the next download.
quarantine_db="${HOME}/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2"
[[ -f "${quarantine_db}" ]] && : > "${quarantine_db}" || true
###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories and input #
###############################################################################
# Set mouse and scrolling speed.
defaults write NSGlobalDomain com.apple.mouse.scaling -int 3
defaults write NSGlobalDomain com.apple.trackpad.scaling -int 3
defaults write NSGlobalDomain com.apple.scrollwheel.scaling -float 0.6875
# Trackpad: enable tap to click for this user and for the login screen
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true
defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true
defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
# Trackpad: right-click by tapping with two fingers
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadCornerSecondaryClick -int 2
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadRightClick -bool true
defaults -currentHost write NSGlobalDomain com.apple.trackpad.trackpadCornerClickBehavior -int 1
defaults -currentHost write NSGlobalDomain com.apple.trackpad.enableSecondaryClick -bool true
# Trackpad: swipe between pages with three fingers
defaults write NSGlobalDomain AppleEnableSwipeNavigateWithScrolls -bool true
defaults -currentHost write NSGlobalDomain com.apple.trackpad.threeFingerHorizSwipeGesture -int 1
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadThreeFingerHorizSwipeGesture -int 1
# Disable “natural” (Lion-style) scrolling
defaults write NSGlobalDomain com.apple.swipescrolldirection -bool false
# Enable full keyboard access for all controls
# (e.g. enable Tab in modal dialogs)
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
# Use scroll gesture with the Ctrl (^) modifier key to zoom
defaults write com.apple.universalaccess closeViewScrollWheelToggle -bool true
defaults write com.apple.universalaccess HIDScrollZoomModifierMask -int 262144
# Follow the keyboard focus while zoomed in
defaults write com.apple.universalaccess closeViewZoomFollowsFocus -bool true
# Disable press-and-hold for keys in favor of key repeat
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
# Set a blazingly fast keyboard repeat rate
defaults write NSGlobalDomain KeyRepeat -int 1
defaults write NSGlobalDomain InitialKeyRepeat -int 10
# Set language and text formats
# Note: if you’re in the US, replace `EUR` with `USD`, `Centimeters` with
# `Inches`, `en_GB` with `en_US`, and `true` with `false`.
defaults write NSGlobalDomain AppleLanguages -array "en" "fr"
defaults write NSGlobalDomain AppleLocale -string "en_GB@currency=EUR"
defaults write NSGlobalDomain AppleMeasurementUnits -string "Centimeters"
defaults write NSGlobalDomain AppleMetricUnits -bool true
# Show language menu in the top right corner of the boot screen
sudo defaults write /Library/Preferences/com.apple.loginwindow showInputMenu -bool true
# Set the timezone; see `sudo systemsetup -listtimezones` for other values
sudo systemsetup -settimezone "Europe/Paris" > /dev/null
sudo systemsetup -setnetworktimeserver "time.euro.apple.com"
sudo systemsetup -setusingnetworktime on
# Do not set timezone automatticaly depending on location.
sudo defaults write /Library/Preferences/com.apple.timezone.auto.plist Active -bool false
# The menu bar clock is configured in the Menubar section above. `DateFormat`
# used to be set here: macOS dropped it for a set of per-component keys, and a
# format string written to it is now ignored.
###############################################################################
# Logi Options #
###############################################################################
# `Logi Options.app` is end-of-life upstream, but its daemon still drives both
# MX Ergo trackballs, so the settings below are what keeps them identical.
#
# TODO: replace this whole stack with OpenLogi, which speaks HID++ directly,
# needs no account or telemetry, and keeps its config in a single TOML file that
# belongs in this repo instead of the reverse-engineered plists below:
# https://github.com/AprilNEA/OpenLogi
#
# Blocked on three upstream gaps, as of 2026-08-11. Re-evaluate when they close:
# - Device not detected at all, this exact model on Unifying:
# https://github.com/AprilNEA/OpenLogi/issues/367
# - Wheel tilt left/right (CIDs 0x5b/0x5d) not bindable, so both Desktop
# switches have nowhere to go. Two competing open PRs, one diverting at the
# HID++ layer (verified on an MX Ergo), one hooking horizontal scroll:
# https://github.com/AprilNEA/OpenLogi/pull/357
# https://github.com/AprilNEA/OpenLogi/pull/359
# - No Smart zoom action, and no keystroke can stand in for it, so page-up
# has no equivalent. Request closed as duplicate, folded into a zoom
# gesture feature:
# https://github.com/AprilNEA/OpenLogi/issues/428
# https://github.com/AprilNEA/OpenLogi/issues/360
#
# The other four assignments map cleanly today: wheel click to MissionControl,
# and the two keystroke buttons to CustomShortcut entries.
#
# Two domains are in play. `ffff` is app-global: mouse feel, update and
# telemetry behaviour, and no button assignments at all. The button map lives
# in a per-*model* domain named after the product ID.
#
# That model-level scoping is why the two physical trackballs behave the same
# without any per-device work: both units report the same pair of product IDs
# (`0006b01d` over Bluetooth, `406f` over the Unifying receiver) and Logi
# Options normalises on the Bluetooth one, so one button map covers both
# whatever the transport. Only pairing and Flow state is per-unit, kept under
# `unitIdSettings` keyed by unit ID and not reproducible from a script.
LOGI_DEVICE="com.logitech.manager.setting.0006b01d"
# The daemon holds these keys in memory and writes them back when it exits or
# when the device reconnects, so writing underneath a live daemon gets silently
# reverted. Stop it, write, then let launchd start it again.
launchctl bootout "gui/${UID}/com.logitech.manager.daemon" || true
defaults write com.logitech.manager.daemon com.logitech.trackpad.EnableHotKeys -bool true
defaults write com.logitech.manager.setting.ffff SSOOnboardingHasRun -bool true
defaults write com.logitech.manager.setting.ffff SSOAutobackups -bool false
defaults write com.logitech.manager.setting.ffff automaticCheckUpdates -bool true
defaults write com.logitech.manager.setting.ffff logCollectionEnabled -bool false
defaults write com.logitech.manager.setting.ffff lowBatteryOsd -bool true
defaults write com.logitech.manager.setting.ffff mouseDoubleClickSpeed -int 80
defaults write com.logitech.manager.setting.ffff mouseScrolling -bool true
defaults write com.logitech.manager.setting.ffff mouseScrollingInertia -int 1
# Pointer and scroll feel, per device rather than app-global.
defaults write "${LOGI_DEVICE}" deviceName -string "MX Ergo"
defaults write "${LOGI_DEVICE}" trackingSpeed -int 50
defaults write "${LOGI_DEVICE}" scrollingSpeed -int 61
defaults write "${LOGI_DEVICE}" scrollDirectionNatural -bool false
defaults write "${LOGI_DEVICE}" smoothScrolling -bool true
defaults write "${LOGI_DEVICE}" secondaryClick -bool true
defaults write "${LOGI_DEVICE}" secondaryClickValue -int 5
defaults write "${LOGI_DEVICE}" specialKeyGestures -bool true
defaults write "${LOGI_DEVICE}" DPISwitchPrecisionMode -bool false
# Button assignments, mirroring the screenshots in `assets/logitech-mx-ergo-*`.
#
# These MUST be written as XML plist literals. `defaults` parses an old-style
# literal (`{ currentAssignment = 150; }`) into a *string*, which the daemon
# ignores. `defaults read` prints that string exactly like the integer, so the
# breakage is invisible unless inspected with `plutil -p`.
#
# Keys are HID++ control IDs. `currentAssignment` is a task ID, except 73
# (`0x49`) which means "send a keystroke" and reads its key and modifiers from
# `assignmentData`. Both are HID usage codes: 224 Ctrl, 225 Shift, 226 Opt,
# 13 `j`, 44 Space.
# Wheel click: Mission Control.
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0x52" '<dict>
<key>name</key><string>MiddleButton</string>
<key>assignmentList</key><string>6b01d_MiddleButtonAssignmentList</string>
<key>currentAssignment</key><integer>150</integer>
</dict>'
# Page-down: Shift + Opt + Ctrl + J, the Amethyst window command.
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0x53" '<dict>
<key>name</key><string>BackAsButton4</string>
<key>assignmentList</key><string>6b01d_BackButtonAssignmentList</string>
<key>currentAssignment</key><integer>73</integer>
<key>assignmentData</key><dict>
<key>0x49</key><dict>
<key>name</key><string>keystroke</string>
<key>keystroke</key><integer>13</integer>
<key>modifiers</key><array>
<integer>225</integer>
<integer>226</integer>
<integer>224</integer>
</array>
</dict>
</dict>
</dict>'
# Page-up: Smart zoom.
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0x56" '<dict>
<key>name</key><string>ForwardAsButton5</string>
<key>assignmentList</key><string>6b01d_ForwardButtonAssignmentList</string>
<key>currentAssignment</key><integer>159</integer>
</dict>'
# Wheel tilt left: Desktop (left).
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0x5b" '<dict>
<key>name</key><string>LeftScrollAsAcPan</string>
<key>assignmentList</key><string>6b01d_LeftScrollAssignmentList</string>
<key>currentAssignment</key><integer>602</integer>
</dict>'
# Wheel tilt right: Desktop (right).
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0x5d" '<dict>
<key>name</key><string>RightScrollAsAcPan</string>
<key>assignmentList</key><string>6b01d_RightScrollAssignmentList</string>
<key>currentAssignment</key><integer>603</integer>
</dict>'
# Side thumb button: Shift + Opt + Space. Logi Options still calls this control
# `DPIChange` after its factory precision-mode role.
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0xed" '<dict>
<key>name</key><string>DPIChange</string>
<key>assignmentList</key><string>DPIChangeButtonAssignmentList</string>
<key>currentAssignment</key><integer>73</integer>
<key>assignmentData</key><dict>
<key>0x49</key><dict>
<key>name</key><string>keystroke</string>
<key>keystroke</key><integer>44</integer>
<key>modifiers</key><array>
<integer>225</integer>
<integer>226</integer>
</array>
</dict>
</dict>
</dict>'
# Virtual gesture button. Not exposed in the screenshots, pinned to whatever
# the live config carries so a re-run does not silently drop it.
defaults write "${LOGI_DEVICE}" controlIDPreferences -dict-add "0xd7" '<dict>
<key>name</key><string>VirtualGestureButton</string>
<key>currentAssignment</key><integer>156</integer>
</dict>'
launchctl bootstrap "gui/${UID}" \
/Library/LaunchAgents/com.logitech.manager.daemon.plist || true
###############################################################################
# Energy saving #
###############################################################################
# Turns on lid wakeup
sudo pmset -a lidwake 1
# Automatic restart on power loss
sudo pmset -a autorestart 1
# Restart automatically if the computer freezes
sudo systemsetup -setrestartfreeze on
# Sets displaysleep to 10 minutes
sudo pmset -a displaysleep 10
# Do not allow machine to sleep on charger
sudo pmset -c sleep 0
# Set machine sleep to 5 minutes on battery
sudo pmset -b sleep 5
# Set standby delay to default 1 hour
# See: https://www.ewal.net/2012/09/09/slow-wake-for-macbook-pro-retina/
sudo pmset -a standbydelay 3600
# Never go into computer sleep mode
#sudo systemsetup -setcomputersleep Off > /dev/null
# Hibernation mode
# 0: Disable hibernation (speeds up entering sleep mode)
# 3: Copy RAM to disk so the system state can still be restored in case of a
# power failure.
sudo pmset -a hibernatemode 3
# Remove the sleep image file to save disk space
#sudo rm /private/var/vm/sleepimage
# Create a zero-byte file instead…
#sudo touch /private/var/vm/sleepimage
# …and make sure it can’t be rewritten
#sudo chflags uchg /private/var/vm/sleepimage
###############################################################################
# Screen #
###############################################################################
# Save screenshots to the desktop
defaults write com.apple.screencapture location -string "${HOME}/Desktop"
# Save screenshots in PNG format (other options: BMP, GIF, JPG, PDF, TIFF)
defaults write com.apple.screencapture type -string "png"
# Disable shadow in screenshots
defaults write com.apple.screencapture disable-shadow -bool true
###############################################################################
# Nightlight #
###############################################################################
# Start night shift from sunset to sunrise. Night Shift needs a display and a
# location to derive sunset from, so `nightlight` exits non-zero on a headless
# machine.
nightlight schedule start || true
###############################################################################
# MonitorControl.app #
###############################################################################