Class: Jamf::Client

Inherits:
Object show all
Extended by:
JamfBinary, JamfHelper, ManagementAction
Defined in:
lib/jamf/client.rb,
lib/jamf/client/jamf_binary.rb,
lib/jamf/client/jamf_helper.rb,
lib/jamf/client/management_action.rb

Overview

jamf client computer

Defined Under Namespace

Modules: JamfBinary, JamfHelper, ManagementAction

Constant Summary collapse

JAMF_PLIST =

The Pathname to the preferences plist used by the jamf binary

Pathname.new '/Library/Preferences/com.jamfsoftware.jamf.plist'
JAMF_SUPPORT_FOLDER =

The Pathname to the JAMF support folder

Pathname.new '/Library/Application Support/JAMF'
RECEIPTS_FOLDER =

The JAMF receipts folder, where package installs are tracked.

JAMF_SUPPORT_FOLDER + 'Receipts'
DOWNLOADS_FOLDER =

The JAMF downloads folder

JAMF_SUPPORT_FOLDER + 'Downloads'
SUPPORT_BIN_FOLDER =

The bin folder inside the Jamf support folder

JAMF_SUPPORT_FOLDER + 'bin'
CONSOLE_USERS_SCUTIL_CMD =

This command gives raw info about console users

'echo "show State:/Users/ConsoleUser" | /usr/sbin/scutil'.freeze
ROOT_USER =

ignore console user = root (loginwindow)

'root'.freeze
LOGINWINDOW_USER =

ignore primary console user loginwindow

'loginwindow'.freeze
SELF_SERVICE_EXECUTABLE_END =

The end of the path to the Self Service Executable. Used to figure out who's running Self Service.app

'/Self Service.app/Contents/MacOS/Self Service'.freeze
PS_USER_COMM =

the ps command used to figure out who's running Self Service

'ps -A -o user,comm'.freeze
USER_PREFS_BYHOST_FOLDER =

the path to a users byhost folder from home

'Library/Preferences/ByHost/'.freeze

Class Method Summary collapse

Class Method Details

.build_jamf_command(command, args) ⇒ Object Originally defined in module JamfBinary

.console_userObject

alias for primary_console_user



244
245
246
# File 'lib/jamf/client.rb', line 244

def self.console_user
  primary_console_user
end

.console_usersArray<String>

Who's currently got an active GUI session? - might be more than one if Fast User Switching is in use.

Returns:

  • (Array<String>)

    The current users with GUI sessions



224
225
226
227
228
229
# File 'lib/jamf/client.rb', line 224

def self.console_users
  output = `#{CONSOLE_USERS_SCUTIL_CMD}`
  userlines = output.lines.select { |l| l =~ /SessionUserNameKey\s*:/ }
  userlines.map! { |ul| ul.split(':').last.strip }
  userlines.reject { |un| un == ROOT_USER }
end

.do_not_disturb?(user = nil) ⇒ Boolean?

Returns Is 'Do Not Disturb' enabled for the user? nil if unknown/not-applicable.

Parameters:

  • user (String, nil) (defaults to: nil)

    The user to query, the current user if nil.

Returns:

  • (Boolean, nil)

    Is 'Do Not Disturb' enabled for the user? nil if unknown/not-applicable



263
264
265
266
267
268
269
# File 'lib/jamf/client.rb', line 263

def self.do_not_disturb?(user = nil)
  home = user ? homedir(user) : Dir.home
  myudid = udid
  nc_prefs_file = Pathname.new "#{home}/#{USER_PREFS_BYHOST_FOLDER}/com.apple.notificationcenterui.#{myudid}.plist"
  return nil unless nc_prefs_file.readable?
  JSS.parse_plist(nc_prefs_file)['doNotDisturb']
end

.execute_jamf(cmd, verbose) ⇒ Object Originally defined in module JamfBinary

.force_alertsObject Originally defined in module ManagementAction

Skipping all the force-alerts stuff until we figure out cleaner ways to do it in 10.13+ The plan is to be able to make the NotificationCenter notification be an 'alert' (which stays visible til the user clicks) or a 'banner' (which vanishes in a few seconds), regardless of the user's setting in the NC prefs.

.hardware_dataHash

The parsed HardwareDataType output from system_profiler

Returns:

  • (Hash)

    the HardwareDataType data from the system_profiler command



214
215
216
217
# File 'lib/jamf/client.rb', line 214

def self.hardware_data
  raw = `/usr/sbin/system_profiler SPHardwareDataType -xml 2>/dev/null`
  JSS.parse_plist(raw)[0]['_items'][0]
end

.homedir(user) ⇒ Pathname?

The home dir of the specified user, nil if no homedir in local dscl.

Parameters:

  • user (String)

    the user whose homedir to look up

Returns:

  • (Pathname, nil)

    The user's homedir or nil if no such user



278
279
280
281
# File 'lib/jamf/client.rb', line 278

def self.homedir(user)
  dir = `/usr/bin/dscl . -read /Users/#{user} NFSHomeDirectory 2>/dev/null`.chomp.split(': ').last
  dir ? Pathname.new(dir) : nil
end

.installed?Boolean

Is the jamf binary installed?

Returns:

  • (Boolean)

    is the jamf binary installed?



103
104
105
# File 'lib/jamf/client.rb', line 103

def self.installed?
  JAMF_BINARY.executable?
end

.jamf_helper(window_type = :hud, **opts) ⇒ Integer Originally defined in module JamfHelper

Note:

the -startlaunchd and -kill options are not available in this implementation, since they don't work at the moment (casper 9.4). -startlaunchd seems to be required to NOT use launchd, and when it's ommited, an error is generated about the launchd plist permissions being incorrect.

A wrapper for the jamfHelper command, which can display a window on the client machine.

The first parameter must be a symbol defining what kind of window to display. The options are

  • :hud - creates an Apple “Heads Up Display” style window

  • :utility or :util - creates an Apple “Utility” style window

  • :fs or :full_screen or :fullscreen - creates a full screen window that restricts all user input WARNING: Remote access must be used to unlock machines in this mode

The remaining options Hash can contain any of the options listed. See below for descriptions.

The value returned is the Integer exitstatus/stdout (both are the same) of the jamfHelper command. The meanings of those integers are:

  • 0 - Button 1 was clicked

  • 1 - The Jamf Helper was unable to launch

  • 2 - Button 2 was clicked

  • 3 - Process was started as a launchd task

  • XX1 - Button 1 was clicked with a value of XX seconds selected in the drop-down

  • XX2 - Button 2 was clicked with a value of XX seconds selected in the drop-down

  • 239 - The exit button was clicked

  • 240 - The “ProductVersion” in sw_vers did not return 10.5.X, 10.6.X or 10.7.X

  • 243 - The window timed-out with no buttons on the screen

  • 250 - Bad “-windowType”

  • 254 - Cancel button was select with delay option present

  • 255 - No “-windowType”

If the :abandon_process option is given, the integer returned is the Process ID of the abondoned process running jamfHelper.

See also /Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -help

Parameters:

  • window_type (Symbol) (defaults to: :hud)

    The type of window to display

  • opts (Hash)

    the options for the window

Options Hash (**opts):

  • :window_position (Symbol, nil)

    one of [ nil, :ul, :ll. :ur, :lr ] Positions window in the upper right, upper left, lower right or lower left of the user's screen If no input is given, the window defaults to the center of the screen

  • :title (String)

    Sets the window's title to the specified string

  • :heading (String)

    Sets the heading of the window to the specified string

  • :align_heading (Symbol)

    one of [:right, :left, :center, :justified, :natural] Aligns the heading to the specified alignment

  • :description (String)

    Sets the main contents of the window to the specified string

  • :align_description (Symbol)

    one of [:right, :left, :center, :justified, :natural] Aligns the description to the specified alignment

  • :icon (String, Pathname)

    Sets the windows image field to the image located at the specified path

  • :icon_size (Integer)

    Changes the image frame to the specified pixel size

  • :full_screen_icon (any value)

    Scales the “icon” to the full size of the window. Note: Only available in full screen mode

  • :button1 (String)

    Creates a button with the specified label

  • :button2 (String)

    Creates a second button with the specified label

  • :default_button (Integer)

    either 1 or 2 Sets the default button of the window to the specified button. The Default Button will respond to “return”

  • :cancel_button (Integer)

    either 1 or 2 Sets the cancel button of the window to the specified button. The Cancel Button will respond to “escape”

  • :timeout (Integer)

    Causes the window to timeout after the specified amount of seconds Note: The timeout will cause the default button, button 1 or button 2 to be selected (in that order)

  • :show_delay_options (String, Array<Integer>)

    A String of comma-separated Integers, or an Array of Integers. Enables the “Delay Options Mode”. The window will display a dropdown with the values passed through the string

  • :countdown (any value)

    Displays a string notifying the user when the window will time out

  • :align_countdown (Symbol)

    one of [:right, :left, :center, :justified, :natural] Aligns the countdown to the specified alignment

  • :lock_hud (Boolean)

    Removes the ability to exit the HUD by selecting the close button

  • :abandon_process (Boolean)

    Abandon the jamfHelper process so that your code can exit. This is mostly used so that a policy can finish while a dialog is waiting (possibly forever) for user response. When true, the returned value is the process id of the abandoned jamfHelper process.

  • :output_file (String, Pathname)

    Save the output of jamfHelper (the exit code) into this file. This is useful when using abandon_process. The output file can be examined later to see what happened. If this option is not provided, no output is saved.

  • :arg_string (String)

    The jamfHelper commandline args as a single String, the way you'd specify them in a shell. This is appended to any Ruby options provided when calling the method. So calling:

    Jamf::Client.jamf_helper :hud, title: 'This is a title', arg_string: '-heading "this is a heading"'
    

    will run

    jamfHelper -windowType hud -title 'this is a title' -heading "this is a heading"
    

    When using this, be careful not to specify the windowType, since it's generated by the first, required, parameter of this method.

Returns:

  • (Integer)

    the exit status of the jamfHelper command. See above.

Raises:

.jamf_plistHash

The contents of the JAMF plist

an empty hash if not

Returns:

  • (Hash)

    the parsed contents of the JAMF_PLIST if it exists,



161
162
163
164
# File 'lib/jamf/client.rb', line 161

def self.jamf_plist
  return {} unless JAMF_PLIST.file?
  JSS.parse_plist JAMF_PLIST
end

.jamf_versionString?

What version of the jamf binary is installed?

Returns:

  • (String, nil)

    the version of the jamf binary installed on this client, nil if not installed



111
112
113
# File 'lib/jamf/client.rb', line 111

def self.jamf_version
  installed? ? run_jamf(:version).chomp.split('=')[1] : nil
end

.jss_available?Boolean

Is the JSS available right now?

Returns:

  • (Boolean)

    is the JSS available now?



179
180
181
182
# File 'lib/jamf/client.rb', line 179

def self.jss_available?
  run_jamf :checkJSSConnection, '-retry 1'
  $CHILD_STATUS.exitstatus.zero?
end

.jss_portInteger

The port number for JSS connections for this client

Returns:

  • (Integer)

    the port to the JSS for this client



151
152
153
154
# File 'lib/jamf/client.rb', line 151

def self.jss_port
  jss_url
  @port
end

.jss_protocolString

The protocol for JSS connections for this client

Returns:

  • (String)

    the protocol to the JSS for this client, “http” or “https”



142
143
144
145
# File 'lib/jamf/client.rb', line 142

def self.jss_protocol
  jss_url
  @protocol
end

.jss_recordJamf::Computer?

The Jamf::Computer object for this computer

Returns:

  • (Jamf::Computer, nil)

    The JSS record for this computer, nil if not in the JSS



188
189
190
191
192
# File 'lib/jamf/client.rb', line 188

def self.jss_record
  Jamf::Computer.fetch udid: udid
rescue Jamf::NoSuchItemError
  nil
end

.jss_serverString

The JSS server hostname for this client

Returns:

  • (String)

    the JSS server for this client



133
134
135
136
# File 'lib/jamf/client.rb', line 133

def self.jss_server
  jss_url
  @server
end

.jss_urlString

the URL to the jss for this client

Returns:

  • (String)

    the url to the JSS for this client



119
120
121
122
123
124
125
126
127
# File 'lib/jamf/client.rb', line 119

def self.jss_url
  @url = jamf_plist['jss_url']
  return nil if @url.nil?
  @url =~ %r{(https?)://(.+):(\d+)/}
  @protocol = Regexp.last_match(1)
  @server = Regexp.last_match(2)
  @port = Regexp.last_match(3)
  @url
end

.management_action(msg, title: nil, subtitle: nil, delay: 0) ⇒ Object Also known as: nc_notify Originally defined in module ManagementAction

class Methods

.my_ip_addressString

Get the current IP address as a String.

This handy code doesn't acutally make a UDP connection, it just starts to set up the connection, then uses that to get the local IP.

Lifted gratefully from coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/

Returns:

  • (String)

    the current IP address.



85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/jamf/client.rb', line 85

def self.my_ip_address
  # turn off reverse DNS resolution temporarily
  # @note the 'socket' library has already been required by 'rest-client'
  orig = Socket.do_not_reverse_lookup
  Socket.do_not_reverse_lookup = true

  UDPSocket.open do |s|
    s.connect '192.168.0.0', 1
    s.addr.last
  end
ensure
  Socket.do_not_reverse_lookup = orig
end

.primary_console_userString?

Which console user is using the primary GUI console? Returns nil if the primary GUI console is at the login window.

Returns:

  • (String, nil)

    The login name of the user is using the primary GUI console, or nil if at the login window.



237
238
239
240
241
# File 'lib/jamf/client.rb', line 237

def self.primary_console_user
  `#{CONSOLE_USERS_SCUTIL_CMD}` =~ /^\s*Name : (\S+)$/
  user = Regexp.last_match(1)
  user == LOGINWINDOW_USER ? nil : user
end

.receiptsArray<Pathname>

All the JAMF receipts on this client

Returns:

  • (Array<Pathname>)

    an array of Pathnames for all regular files in the jamf receipts folder

Raises:



170
171
172
173
# File 'lib/jamf/client.rb', line 170

def self.receipts
  raise Jamf::NoSuchItemError, "The JAMF Receipts folder doesn't exist on this computer." unless RECEIPTS_FOLDER.exist?
  RECEIPTS_FOLDER.children.select(&:file?)
end

.restore_alerts(orig_flags) ⇒ Object Originally defined in module ManagementAction

.run_jamf(command, args = nil, verbose = false) ⇒ String Originally defined in module JamfBinary

Note:

Most jamf commands require superuser/root privileges.

Run an arbitrary jamf binary command.

The details of the Process::Status for the jamf binary process can be captured from $CHILD_STATUS immediately after calling. (See Process::Status)

Examples:

These two are equivalent:

  Jamf::Client.run_jamf "recon", "-assetTag 12345 -department 'IT Support'"

  Jamf::Client.run_jamf :recon, ['-assetTag', '12345', '-department', 'IT Support'"]

Parameters:

  • command (String, Symbol)

    the jamf binary command to run The command is the single jamf command that comes after the/usr/bin/jamf.

  • args (String, Array) (defaults to: nil)

    the arguments passed to the jamf command. This is to be passed to Kernel.` (backtick), after being combined with the jamf binary and the jamf command

  • verbose (Boolean) (defaults to: false)

    Should the stdout & stderr of the jamf binary be sent to the current stdout in realtime, as well as returned as a string?

Returns:

  • (String)

    the stdout & stderr of the jamf binary.

Raises:

.self_service_usersArray<String>

Who's currently running Self Service.app? - might be more than one if Fast User Switching is in use.

Returns:

  • (Array<String>)

    The current users running Self Service.app



253
254
255
256
# File 'lib/jamf/client.rb', line 253

def self.self_service_users
  ss_userlines = `#{PS_USER_COMM}`.lines.select { |l| l.include? SELF_SERVICE_EXECUTABLE_END }
  ss_userlines.map { |ssl| ssl.split(' ').first }
end

.serial_numberString

The serial number for this computer via system_profiler

Returns:

  • (String)

    the serial number for this computer



206
207
208
# File 'lib/jamf/client.rb', line 206

def self.serial_number
  hardware_data['serial_number']
end

.set_mgmt_action_ncprefs_flags(user, flags, hup: true) ⇒ Integer Originally defined in module ManagementAction

set the NotificationCenter option flags for a user flags = an integer.

Doesn't seem to work in 10.13, so ignore this for now.

Returns:

  • (Integer)

    the original flags, or given flags if no originals.

.udidString

The UUID for this computer via system_profiler

Returns:

  • (String)

    the UUID/UDID for this computer



198
199
200
# File 'lib/jamf/client.rb', line 198

def self.udid
  hardware_data['platform_UUID']
end