So führen Sie ein Skript mit cron oder launchd für das Gastbenutzerkonto in El Capitan aus

Ich konnte keine Möglichkeit finden, während der Anmeldung ein Skript für das Gastkonto auszuführen, das jede Minute ausgeführt wird. Sie sagen, dass die Verwendung des Cron-Daemons veraltet ist, also sieht es so aus, als würde ich launchd mit .plist-Dateien verwenden.

Szenario: Ich habe einen öffentlichen iMac. Ich möchte der Allgemeinheit erlauben, das Gastkonto zu verwenden, und alle halbe Stunde eine Abmeldung erzwingen. Ich habe ein Ruby-Skript geschrieben, um die Anmeldezeit zu überprüfen und die verbleibende Zeit herauszufinden. Ich kann mit osascript alle 10 Minuten eine Bannerbenachrichtigung anzeigen und mich dann von meinem Konto abmelden lassen. Das Problem ist, wenn ich versuche, es für das Gastkonto zu implementieren, funktioniert es nicht.

Das Problem ist, wenn ich die .plist-Datei in /Library/LaunchDaemons platziere, da sie nach der Anmeldung und auch als Root ausgeführt wird. Das Ausführen als root ist wichtig, da ich das Privileg haben kann, Prozesse herunterzufahren, wenn die Zeit abläuft. Ich brauche es, um einmal pro Minute auszuführen. Dies ist die aktuelle Plist-Datei, die funktioniert, wenn ich mich als mein eigener Benutzername "Besitzer", aber nicht als Gast anmelde. Verwenden von org.user.plist

Meine ursprüngliche .plist-Datei sah ungefähr so ​​​​aus

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>Label</key> 
        <string>org.user</string> 
    <key>Program</key> 
        <string>/usr/local/bin/notify-custom</string> 
    <key>RunAtLoad</key> 
        <true/> 
</dict> 
</plist>

Update 1 (Noch keine Lösung) .plist-Datei, die alle 10 Sekunden für Gast und meinen Benutzernamen ausgeführt wird

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
        <string>org.user</string>
    <key>ProgramArguments</key>
        <string>/usr/local/bin/notify-custom</string>
    <key>WatchPaths</key>
        <array>        
            <string>/Users/Guest/Library</string>
            <string>/Users/owner/Library</string>
        <array>
    </integer>
</dict>
</plist>

Als Test, um sicherzustellen, dass das osascript-Benachrichtigungsbanner erscheint, habe ich diesen Code in /usr/local/bin/notify-custom

#/bin/bash

#Using whoami would have shown me logged in as root under LaunchDaemon .plist
loggedinUser=`finger | awk 'NR==3{print $1}'`
#I need to manually run terminal and type sudo as guest for nextline to work
sudo -u $loggedinUser /usr/bin/osascript -e 'display notification "Test" with title "Banner Notification"'

Lösung ist unten.

Die angezeigte .plist-Datei konnte möglicherweise nicht geladen werden, da weder ein Program- noch ein ProgramArguments-Schlüssel angegeben ist.
Tut mir leid, dass ich weiß, dass ich vergessen habe, diesen Abschnitt einzufügen. Siehe Überarbeitung oben. (Ich denke, vielleicht sollte ich versuchen, stattdessen den Schlüssel ProgramArguments zu verwenden, gefolgt von nur einem einzigen Array-Element, das der Programmname ist, da es kein anderes Argument benötigt.)
Was ist notify-customund ist es eine Binärdatei oder ein Skript, und wenn letzteres, was ist der Inhalt des Skripts?
Es ist ein Ruby-Skript. Es ist bei der Arbeit. Werde es morgen hier posten, wenn du denkst, dass es hilft.
Ich habe gerade mit meiner eigenen .plist-Datei getestet, die im Besitz von rootin der wheelGruppe mit 0644Berechtigungen ist, /Library/LaunchAgentsund sie lief, wenn sie als Gast angemeldet war. Mit Ausnahme der Zeichenfolge für die Programmtaste war der Rest der Datei gleich. Es funktionierte wie erwartet. Ich schaue mir auch die anderen LaunchAgents am selben Ort an und überprüfe im Aktivitätsmonitor, dass ihre Prozesse ebenfalls gestartet wurden. Ohne zu wissen, was es notify-customist und was es enthält, kann ich im Moment nicht viel anderes anbieten, als zu sagen, dass .plist-Dateien /Library/LaunchAgentsim Gastkonto in Arbeit sind.
Auch die .plist-Dateien hatten keine erweiterten Attribute. Ich programmiere nicht in Ruby, daher hilft mir das Skript nicht, die Situation zu debuggen.
Hmmm, ich habe nur nach dem Banner gesucht, das in meinem Ruby-Skript angezeigt wird. Ich habe Ruby verwendet, da es Variablen zwischen der Shell übergab und eine einfachere Manipulation und Subtraktion von Zeichenfolgen zu Zeit ermöglichte, da ich es nicht allein durch die Shell zum Laufen bringen konnte. Welche Art von Skript haben Sie verwendet, um mit dem Gastkonto zu interagieren? Haben Sie eine Probe?
@Michael Bitte ändern Sie die Grundfrage nicht zu sehr! Fügen Sie besser einen Update-Bereich hinzu, stellen Sie eine zweite Frage oder fordern Sie weitere Erläuterungen an. In Ihrem Beispiel haben Sie die Plist so geändert, dass meine Antwort keinen Sinn ergibt, da Sie sie teilweise in Ihre (aktualisierte) Frage integriert haben.
@Michael Übrigens, um ein Passwort ohne Passwort sudo shutdownfür einen Gastbenutzer zu aktivieren, der die Datei /etc/sudoers ändert, sollte funktionieren!
@klanomath. Das tut mir leid. Du hast Recht. Ich dachte über meinen Fehler nach, die ursprüngliche Frage zu ändern, nachdem ich das Update eingereicht hatte. Ich wollte klarstellen, dass die Verwendung der .plist als Daemon, der als Root ausgeführt wird, Osascript nicht startet. Ich bin mir nicht sicher, warum ich die sudoers-Datei ändern möchte, da der Daemon als Root ausgeführt wird und keine zusätzlichen Berechtigungen für die Verwendung des sudo-Befehls benötigen sollte. Sinn ergeben?
OK, ich habe es mit Ihrer Idee zur Verwendung der Sudoers-Datei zum Laufen gebracht. Bei dieser Methode musste ich die Plist-Datei in den LaunchAgents-Ordner einfügen, damit sie die Berechtigungen des angemeldeten Benutzers erhält. Ich habe versucht, die erste Antwort unten zu erhöhen, da dies offensichtlich machte, dass ich ein Problem mit meiner oben erwähnten ursprünglichen Plist-Datei hatte, aber ich habe nicht genügend Punkte auf Stackexchange, um dies zu tun.
Ich schlage Folgendes vor: Schreiben Sie Ihre Frage um: ursprüngliche Frage; update1 basierend auf answer1 funktioniert halbwegs; Update2 basierend auf Antwort1 oder 2 noch ein kleiner Fehler. Wenn Sie alles wie gewünscht zum Laufen gebracht haben, posten Sie eine separate Antwort (basierend auf Ihren und / oder anderen Recherchen) auf Ihre eigene Frage - aber bitte beantworten Sie nicht Ihre eigene Frage in der Frage.

Antworten (2)

Meiner Meinung nach sollte Folgendes funktionieren - es funktioniert in meiner VM! - gestartet als /Library/LaunchDaemons/org.user.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.user</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/touch</string>
        <string>-f</string>
        <string>/Users/Guest/Desktop/test.txt</string>
    </array>
    <key>UserName</key>
    <string>Guest</string>
    <key>GroupName</key>
    <string>_guest</string>
    <key>InitGroups</key>
    <true/>
    <key>WatchPaths</key>
    <array>
        <string>/Users/Guest/Library</string>
    </array>
</dict>
</plist>

Als Beispielaufgabe verwende ich /usr/bin/touch -f /Users/Guest/Desktop/test.txt.

Der Clou dabei ist, dass nach einem Logout der komplette Inhalt des Guest-Ordners gelöscht wird. Nachdem sich ein neuer Gast anmeldet, wird der gesamte Inhalt von Grund auf neu erstellt. Sobald der Ordner /Users/Guest/Library angelegt ist, touch ...wird der Beispieltask ( ) aufgrund des WatchPaths-Schlüssels gestartet.

Da die Aufgabe/das Skript/die App als Gast ausgeführt werden muss, können Sie keine Startagenten verwenden, da der Pfad /Users/Guest/Library/LaunchAgents/ einfach nicht existiert.

Verwenden Sie stattdessen einen Launch-Daemon und führen Sie ihn als Guest/_guest aus . Ihr Ruby-Skript /usr/local/bin/notify-custom muss weltweit lesbar/ausführbar sein? Natürlich.


Ich habe auch versucht, die Aufgabe alle 60 Sekunden auszuführen - was ordnungsgemäß funktioniert, aber nach dem Abmelden des Gastes einige Fehler auslöst. Wahrscheinlich ist es besser, das Ganze im Ruby-Skript zu implementieren. Abhängig von Ihrem Skript kann Ihr Kilometerstand jedoch variieren.

Wenn Sie zwei verschiedene Aufgaben ausführen müssen (z. B. mit Ruby alle 10 Minuten ein Banner anzeigen und einen Timer zum Erzwingen der Abmeldung nach 30 Minuten), ist es wahrscheinlich besser, zwei verschiedene Start-Daemons zu erstellen.

Sie sagten: „ Da die Aufgabe/das Skript/die App als Gast ausgeführt werden muss, können Sie keine Startagenten verwenden, da der Pfad /Users/Guest/Library/LaunchAgents/ einfach nicht existiert.“ und obwohl das trotzdem wahr ist, meine . plist lief problemlos innerhalb des Gastkontos, wenn es von /Library/LaunchAgentsund ohne die Verwendung des WatchPaths Schlüssels ausgeführt wurde, ebenso wie andere LaunchAgents vom selben Standort aus.
@user3439894 Hmm Ich bin sehr gespannt auf Benachrichtigungsbenutzer ... ;-)
@ user3439894 Ein zusätzliches Problem bei der Verwendung eines Startagenten besteht darin, dass der Agent/das Skript auch ausgeführt wird, wenn er sich als normaler Benutzer anmeldet - was wahrscheinlich unerwünscht ist.
Auf der Maschine, auf der ich dies getestet habe, habe ich 3 LaunchAgents in /Library/LaunchAgents, den, den ich für diesen Test erstellt habe, und 2 vorhandene, die von Anwendungen hinzugefügt wurden, die auf dem System ausgeführt werden, z. B. Little Snitch. Daher sehe ich im Allgemeinen kein Problem bei der Verwendung eines LaunchAgents, um Aktionen im Gastkonto durchzuführen. Allerdings kann es sicherlich davon abhängen, was genau man zu tun versucht, was die Verwendung eines LaunchAgents in /Library/LaunchAgentsdiesem Anwendungsfall-Szenario möglicherweise nicht ideal macht. Ich kann mich nur an meine Tests halten und es hat bei mir so funktioniert, wie ich es getestet habe. Ich weiß nicht, was ich noch sagen kann.

Gelöst. Daran arbeite ich schon eine Weile. Meine Lösung tut endlich das, was ich brauche, und das heißt, sie startet während der Anmeldung für den Benutzer Gast (und als Option habe ich sie auch für mich selbst, den Benutzer iMac1, gestartet, nur um die Anmeldezeit anzuzeigen). Ich habe keine einfache Möglichkeit gesehen, die Datei org.user.plist in /Users/Guest/Library/LaunchAgents abzulegen, die sie theoretisch gestartet hätte, wenn sich der Gast angemeldet hätte, und der Grund, warum ich diese Situation aufgegeben habe, ist dieser Ordner wird erst nach der Anmeldung erstellt.

Ich habe meine .plist-Datei in /Library/LaunchAgents/ abgelegt, die für jeden Benutzer ausgeführt wird. Das ist in Ordnung, da mein Code den Guest-Benutzer unterscheidet und Maßnahmen ergreift (in diesem Fall nach der festgelegten Zeit abmelden).

Die endgültige .plist-Datei:

<?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">
<plist version="1.0">
<dict>
    <key>Label</key>
        <string>org.user</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/notify-custom</string>
    </array>
    <key>RunAtLoad</key>
        <true/>
    <key>StartInterval</key>
        <integer>60</integer>
</dict>
</plist>

Beachten Sie, dass ich einen RunAtLoad-Schlüssel hinzugefügt habe, da das Skript ohne ihn ausgeführt wurde, aber eine Minute gewartet hat, um sein erstes Ereignis auszulösen. Wenn ich stattdessen den WatchPaths-Schlüssel verwenden würde, wie @klanomath in seinem Kommentar bemerkte, würde das Skript alle 10 Sekunden ausgeführt, da ihre Aktivitäten regelmäßig in diesem Ordner stattfinden müssen. Ich wollte nur, dass es vorerst alle 60 Sekunden läuft. Ich kann diesen Timer später ändern, wenn ich die gesamte Prozedur mit einigen farbenfroheren Warndialogen aufräume, die in Python geschrieben sind.

Hier ist der Ruby-Code in /usr/local/bin/notify-custom, der bei jeder Benutzeranmeldung ausgeführt wird:

#!/usr/bin/ruby -w

require 'time'
require 'FileUtils'

loggedinUser=`finger|awk 'END{print $1}'`.strip
getloginTime=`finger|awk 'END{print}'|cut -c49-53`
getnowTime=`date|awk 'NR==1{print $4}'`[0..4]
loginTime=(Time.parse(getloginTime).to_i)
nowTime=(Time.parse(getnowTime).to_i)
diffSec=(nowTime-loginTime)
diffMin=(diffSec/60)
timeRemain=30-diffMin

#To see some console output while debugging
puts "getloginTime      =#{getloginTime}"
puts "getnowTime        =#{getnowTime}"
puts "loginTime=#{loginTime}"
puts "nowTime  =#{nowTime}"
puts "timeRemain=#{timeRemain}"

if loggedinUser == "Guest"
        open("/Users/#{loggedinUser}/Desktop/30 Minutes Max Use Per Day",'a'){|f| f.puts "With this new iMac, you are limited to a maximum of 1/2 hour use per day"}
        if timeRemain < 0
            `/usr/bin/osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/Earth Horizon.jpg"'`
            `/usr/bin/osascript -e 'display notification "SHUTTING DOWN! Now= #{getnowTime}   LoggedInAt=#{getloginTime}   TimeRemain=#{timeRemain}" with title "Guest SHUTTING DOWN" sound name "Glass"'`
            `/usr/bin/osascript -e 'tell app "Terminal" to do script "sudo shutdown -h now"'`
        else
            `/usr/bin/osascript -e 'display notification "Now= #{getnowTime}     TimeRemain=#{timeRemain}" with title "#{loggedinUser} TIME LOGGED IN= #{getloginTime}" subtitle "User= #{loggedinUser}"'`
        end
else
        `/usr/bin/osascript -e 'display notification "Now= #{getnowTime}     TimeRemain=#{timeRemain}" with title "#{loggedinUser} TIME LOGGED IN= #{getloginTime}" subtitle "User= #{loggedinUser}"'`
end

Beachten Sie erneut, dass, wenn Sie stattdessen die LaunchDaemons verwenden, diese unter dem System-Root-Konto ausgeführt werden, während die Agenten auf dem angemeldeten Benutzerkonto ausgeführt werden. Mit der zweiten Option musste ich dem Gastbenutzer die Berechtigung erteilen, sudo shutdown wie unten erwähnt @klanomath auszuführen. Dazu wurde der Befehl $sudo visudo ausgeführt und am Ende der Datei Folgendes hinzugefügt:

Guest ALL=NOPASSWD: /sbin/shutdown

Außerdem wollte ich nur das Gastkonto auf der Anmeldeseite anzeigen, also habe ich mein Konto mit diesem Befehl auf diesem Bildschirm ausgeblendet:

sudo dscl . create /Users/hiddenuser IsHidden 1

und wenn Sie Ihre Meinung ändern, können Sie es zurückbringen mit:

sudo dscl . create /Users/hiddenuser IsHidden 0

Danke @klanomath und @user3439894