Script to find running process and run as user

mgoodall
New Contributor II

Hi All!

I am trying to run a script to check if our PaperCut User Client application is actually running.

I was using the below script on my machine and it returned the results as expected.

*#!/bin/sh
SERVICE=PCClient
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then
    echo "$SERVICE service running, everything is fine"
else
    echo "$SERVICE is not running"
fi*

But when I put this into JAMF as a policy to run the script, it falls over and returns this.

Script result: grep: Support/JAMF/tmp/Check: No such file or directory
grep: if: No such file or directory
grep: PCClient: No such file or directory
grep: is: No such file or directory
grep: running: No such file or directory
PCClient is not running

I assume this is because of where it is trying to run the file from. So I did some digging on here to try and find a script I could add to, to force it to run as the logged-in user.

I found the one below and tried to edit it to work, but it gets unexpected end of file, and cannot work out why (i am new to mac and scripting so apologies if it's an obvious oversight!)

#!/bin/bash

loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

if [[ "$loggedInUser" != "root" ]] || [[ "$loggedInUID" -ne 0 ]]; then

cat << EOF > /private/tmp/script.sh
#!/bin/bash
service=PCClient
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then
    echo "$SERVICE service running, everything is fine"
else
    echo "$SERVICE is not running"

exit 0
EOF 

else
    echo "No user logged in. Can't run as user, so exiting"
    exit 0
fi

if [ -e /private/tmp/script.sh ]; then
    /bin/chmod +x /private/tmp/script.sh
    /bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/private/tmp/script.sh"
    sleep 2
    echo "Cleaning up..."
    /bin/rm -f "/private/tmp/script.sh"
else
    echo "Oops! Couldn't find the script to run. Something went wrong!"
    exit 1
fi

All help gratefully received.

Matt

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

Hey @mgoodall When launchctl list is run as root as it would be from a Jamf policy, you get any processes that are typically being run in a root context. When you run the same command as a user, whether an admin or standard account, you get a list of user level launchd jobs. Essentially it's the difference between LaunchDaemons and LaunchAgents. I don't use the PaperCut agent, but my guess is the process runs in the user space, meaning it's run as a LaunchAgent.
Given this, you have to adjust your commands to tell your script to run the launchctl list command as the logged in user. You could try using the same syntax you mentioned previously, such as `su "$currentuser" -c "launchctl list | grep 'biz.papercut.pcng.client.'" to see if it works.

Another method I like to use is the launchctl asuser syntax.

#!/bin/sh

logged_in_user=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ {print $3}')
logged_in_uid=$(id -u "$logged_in_user")

result=$(/bin/launchctl asuser "$logged_in_uid" sudo -iu "$logged_in_user" /bin/launchctl list | grep "biz.papercut.pcng.client.")

<rest of your script here>

View solution in original post

14 REPLIES 14

mgoodall
New Contributor II

So I found that I had an unwanted space at the end of EOF, which I removed.

The CAT command is now creating the script.sh file as expected but it then errors and removes it (as expected)

mgoodall@Matts-MacBook-Pro ~ % /Users/mgoodall/Documents/LinuxScripts/test4.sh
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]] [-e pattern] [-f file] [--binary-files=value] [--color=when] [--context[=num]] [--directories=action] [--label] [--line-buffered] [--null] [pattern] [file ...] is not running
Cleaning up...

Ive got a copy of the script.sh file that it creates and it looks like it's removing the tag for the variable $SERVICE.. and putting in grep -v /Users/mgoodall etc rather than grep $SERVICE

Below is what is being output to the script.sh file

#!/bin/bash
SERVICE=PCClient
if ps ax | grep -v grep | grep -v /Users/mgoodall/Documents/LinuxScripts/test4.sh | grep  | grep  > /dev/null
then
    echo " service running, everything is fine"
else
    echo " is not running"

exit 0

And below is what I was expecting it to output to the script.sh file.

#!/bin/sh
SERVICE=PCClient
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then echo "$SERVICE service running, everything is fine"
else echo "$SERVICE is not running"
fi

What am i missing here?

mgoodall
New Contributor II

Ok, so I got the script to work.. but it still fails when created in JAMF as a policy with the same error as my first post.

I have also tried to create it as an extension attribute so that it can be seen when looking at the device in JAMF, but I don't seem to be getting any results back.

What's the best way to implement this?

#!/bin/bash

loggedInUser=$(stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

if [[ "$loggedInUser" != "root" ]] || [[ "$loggedInUID" -ne 0 ]]; then

cat << EOF > /private/tmp/script.sh
#!/bin/bash
#SERVICE=PCClient
if ps ax | grep -v grep | grep -v $0 | grep PCClient > /dev/null
then
    echo "PCClient service running, everything is fine"
else
    echo "PCClient is not running"

exit 0
fi
EOF

else
    echo "No user logged in. Can't run as user, so exiting"
    exit 0
fi

if [ -e /private/tmp/script.sh ]; then
    /bin/chmod +x /private/tmp/script.sh
    /bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/private/tmp/script.sh"
    sleep 2
    echo "Cleaning up..."
   /bin/rm -f "/private/tmp/script.sh"
else
    echo "Oops! Couldn't find the script to run. Something went wrong!"
    exit 1;
fi

skeenan07
New Contributor III

The script below is based off of the first script in your original post. I tested it by looking for BBEdit and it worked. (Adding the c option to the ps command will only display the executable name, so you don't need the two grep -v commands.)

#!/bin/bash
currentUser=$(stat -f%Su /dev/console)
SERVICE=PCClient
if [[ $(sudo -u "$currentUser" ps acx | grep $SERVICE) ]]; then 
    echo "$SERVICE service running, everything is fine"
else
    echo "$SERVICE is not running"
fi

Also, when you add code to a post, you can wrap it in ``` to make it easier to read.

mgoodall
New Contributor II

Thanks so much for your response and for helping with my code.

I found that this actually won't work due to the service name.. but I found an alternative that works fine from my PC.

#!/bin/bash

#RUN LAUNCHCTL TO CHECK FOR PAPERCUT PROCESS
result=$(launchctl list | grep biz.papercut.pcng.client.14444)

if [[ "$result" == *biz.papercut.pcng.client.14444* ]] ; then
echo "PaperCut Client is running"
exit 0

 else
#RUN PCClient.app
open -a /Applications/PCClient.app
#currentuser=`stat -f "%Su" /dev/console`
#su "$currentuser" -c "open -a /Applications/PCClient.app"
sleep 10

#START CHECK AGAIN FOR PAPERCUT PROCESS
result=$(launchctl list | grep biz.papercut.pcng.client.14444)
if [[ "$result" == *biz.papercut.pcng.client.14444* ]] ; then

 echo "PaperCut Client is running"

 else
    echo "AGHH SOMETHING IS BROKEN"
exit 1
fi
fi

The issue I am having is that when I put this as a script into JAMF and it runs, I get back "Script result: The application /Applications/PCClient.app cannot be opened for an unexpected reason, error=Error Domain=NSOSStatusErrorDomain Code=-10826 "kLSNoLaunchPermissionErr: User doesn't have permission to launch the app (managed networks)" UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2508, NSUnderlyingError=0x7fae4bd0fe50 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x7fae4bd10610 {Error Domain=OSLaunchdErrorDomain Code=125 "Domain does not support specified action" UserInfo={NSLocalizedFailureReason=Domain does not support specified action}}}}}

However, if u run this script, which checks a different location, I get results back that it was successful.. still using the open -a command, which I have tested as a standard user, and it works.

The

#currentuser=`stat -f "%Su" /dev/console`
#su "$currentuser" -c "open -a /Applications/PCClient.app"

was added only to see if forcing it to run as the current user would fix it.. it didn't.

This is to basically check that the PaperCut UserClient is running and if it's not, tell it to open.

Once it is opened I am then using an extension attribute to display the time and date that it was last opened. This app is to run when the user logs in but like most places people don't reboot or shutdown very often.

Also, the app, if not connected to the corporate network will time out and close... so I need to have a script to tell it to open if it's not open or when they return to the site, they cannot print..

HELP!

mgoodall
New Contributor II

So, i found an error in what i was looking for in LaunchCTL List..

#!/bin/sh
result=$(launchctl list | grep biz.papercut.pcng.client.14444)

the 14444 changes on each machine, so i changed the script to looking for everthing else including the last . as the other service that appers in the list is not active and is there all the time.

It again works on my machine and if I echo the results variable I get a result when the app is open and nothing when the app is closed.. GREAT making progress!

NO! on every machine the script is set to run I am getting a failure.. which is how I feel after a day of trying to get this to work!

mm2270
Legendary Contributor III

Hey @mgoodall When launchctl list is run as root as it would be from a Jamf policy, you get any processes that are typically being run in a root context. When you run the same command as a user, whether an admin or standard account, you get a list of user level launchd jobs. Essentially it's the difference between LaunchDaemons and LaunchAgents. I don't use the PaperCut agent, but my guess is the process runs in the user space, meaning it's run as a LaunchAgent.
Given this, you have to adjust your commands to tell your script to run the launchctl list command as the logged in user. You could try using the same syntax you mentioned previously, such as `su "$currentuser" -c "launchctl list | grep 'biz.papercut.pcng.client.'" to see if it works.

Another method I like to use is the launchctl asuser syntax.

#!/bin/sh

logged_in_user=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ {print $3}')
logged_in_uid=$(id -u "$logged_in_user")

result=$(/bin/launchctl asuser "$logged_in_uid" sudo -iu "$logged_in_user" /bin/launchctl list | grep "biz.papercut.pcng.client.")

<rest of your script here>

mgoodall
New Contributor II

Hi @mm2270

Thanks, makes perfect sense just after hours of looking i must have gone blind!

Tested and working.. Thank you for your help!

Matt

mgoodall
New Contributor II

So this is my final script

#!/bin/bash

#RUN LAUNCHCTL TO CHECK FOR PAPERCUT PROCESS
logged_in_user=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ {print $3}')
logged_in_uid=$(id -u "$logged_in_user")

result=$(/bin/launchctl asuser "$logged_in_uid" sudo -iu "$logged_in_user" /bin/launchctl list | grep "biz.papercut.pcng.client.")

if [[ "$result" == *biz.papercut.pcng.client.* ]] ; then
echo "PaperCut Client is running"
exit 0

 else
#RUN PCClient.app
open -a /Applications/PCClient.app
sleep 10

#START CHECK AGAIN FOR PAPERCUT PROCESS
result=$(/bin/launchctl asuser "$logged_in_uid" sudo -iu "$logged_in_user" /bin/launchctl list | grep "biz.papercut.pcng.client.")
if [[ "$result" == *biz.papercut.pcng.client.* ]] ; then

 echo "PaperCut Client is running"

 else
    echo "AGHH SOMETHING IS BROKEN"
exit 1
fi
fi

Which in 99% of cases is working.

What I am finding is that on some machines, ive narrowed it down to High Serria when the script is run, i am getting the following error.

LSOpenURLsWithRole( ) failed for the applicaiton /Applications/PCClient.app with error -610

Is this because the part of the script that is telling the app to open

open -a /Applications/PCClient.app

is also being run as root and not as the logged-in user? How would i script it to run as the logged-in user?

skeenan07
New Contributor III

I use the following to open an app as the user:

currentUser=$(stat -f%Su /dev/console)
sudo -u "$currentUser" open -a /Applications/PCClient.app

daniel_ross
Contributor III

@skeenan07 could you use this to run something like the below text?

currentUser=$(stat -f%Su /dev/console)
"$currentUser" diskutil resetUserPermissions / `id -u`

Also apologies in advance as I'm still new to learning scripting.

tlarkin
Honored Contributor

You can also use Python ObjC Bridge to leverage macOS APIs like NSWorkspace, example:

>>> from AppKit import NSWorkspace
>>> procs = []
>>> workspace = NSWorkspace.sharedWorkspace()
>>> running_apps = workspace.runningApplications()
>>> for app in running_apps:
...     procs.append(app.localizedName())
... 
>>> print(procs)

This will grab every localized name of every process running in the current user space

skeenan07
New Contributor III

@daniel_ross To run a command as the user, you'll need to use sudo. For the command you've mentioned, it would look like the following:

currentUser=$(stat -f%Su /dev/console)
sudo -u "$currentUser" diskutil resetUserPermissions / $(id -u)

Also, note that I've changed the `id -u` to $(id -u).

fredmin
New Contributor III

 

While I needed a solution to run as Root and not the end user, I used this post as a starting point and put my own spin on it.  Posting my snippet of code that it may be helpful to someone in the future.

This has worked very consistently for me.

 

## Variables
PCClientPID=$(ps -ax | grep PCClient | grep -v grep | awk '{print $1}')

## kill PCClient process if running
if (test -z $PCClientPID); then
	echo "PCClient not running";
elif (test -n $PCClientPID); then
	kill $PCClientPID
fi

 

tlarkin
Honored Contributor

Another great way to do this is with the `NSRunningApplication` API and you can access it via pyobjc bridge.  Example:

>>> from Cocoa import NSRunningApplication
>>> 
>>> app = NSRunningApplication.runningApplicationsWithBundleIdentifier_("com.brave.Browser")
>>> if app:
...     print("app is running")
... else:
...     print("app is not running")
... 
app is running

 

You can feed this API the bundle ID of the app and it will return `True` or `False` if it is running or not