Class: Jamf::Script

Inherits:
APIObject show all
Includes:
Categorizable, Creatable, Updatable
Defined in:
lib/jamf/api/classic/api_objects/script.rb

Overview

A Script in the JSS.

As of Casper 9.4, the script contents as stored in the database are accessible via the API

According to Jamf as of early 2021, it has been some years now since its been possible to store script contents on a dist. point - they are all always in the database.

Use the #run method to run the script on the local machine.

See Also:

Constant Summary collapse

RSRC_BASE =

The base for REST resources of this class

'scripts'.freeze
RSRC_LIST_KEY =

the hash key used for the JSON list output of all objects in the JSS

:scripts
RSRC_OBJECT_KEY =

The hash key used for the JSON object output. It’s also used in various error messages

:script
DIST_POINT_SCRIPTS_FOLDER =

The script storage folder on the distribution point, if used

'Scripts'.freeze
PRIORITIES =

Priority to use for running the script in relation to other actions during imaging

['Before', 'After', 'At Reboot'].freeze
DEFAULT_PRIORITY =

which is default?

'After'.freeze
PARAMETER_KEYS =

The keys used in the @parameters Hash

%i[parameter4 parameter5 parameter6 parameter7 parameter8 parameter9 parameter10 parameter11].freeze
OBJECT_HISTORY_OBJECT_TYPE =

the object type for this object in the object history table. See APIObject#add_object_history_entry

91
CATEGORY_SUBSET =

Where is the Category in the API JSON?

:top
CATEGORY_DATA_TYPE =

How is the category stored in the API data?

String

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**args) ⇒ Script

Constructor



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/jamf/api/classic/api_objects/script.rb', line 115

def initialize(**args)
  super

  @filename = @init_data[:filename] || @name
  @info = @init_data[:info]
  @notes = @init_data[:notes]
  @os_requirements = @init_data[:os_requirements] ? JSS.to_s_and_a(@init_data[:os_requirements])[:arrayform] : []
  @parameters = @init_data[:parameters] || {}
  @priority = @init_data[:priority] || DEFAULT_PRIORITY
  @script_contents = @init_data[:script_contents]
  @script_contents_encoded = @init_data[:script_contents_encoded]
  return unless @script_contents && @script_contents_encoded.to_s.empty?

  @script_contents_encoded = Base64.encode64 @script_contents
end

Instance Attribute Details

#filenameString

Returns the file name of the script, if stored in a dist. point.

Returns:

  • (String)

    the file name of the script, if stored in a dist. point



87
88
89
# File 'lib/jamf/api/classic/api_objects/script.rb', line 87

def filename
  @filename
end

#infoString

Returns the info field for this script.

Returns:

  • (String)

    the info field for this script



96
97
98
# File 'lib/jamf/api/classic/api_objects/script.rb', line 96

def info
  @info
end

#need_to_updateBoolean (readonly) Originally defined in module Updatable

Returns do we have unsaved changes?.

Returns:

  • (Boolean)

    do we have unsaved changes?

#notesString

Returns the notes field for this script.

Returns:

  • (String)

    the notes field for this script



99
100
101
# File 'lib/jamf/api/classic/api_objects/script.rb', line 99

def notes
  @notes
end

#os_requirementsArray<String> Also known as: oses

Returns the OS versions this can be installed onto. For all minor versions, the format is 10.5.x.

Returns:

  • (Array<String>)

    the OS versions this can be installed onto. For all minor versions, the format is 10.5.x



90
91
92
# File 'lib/jamf/api/classic/api_objects/script.rb', line 90

def os_requirements
  @os_requirements
end

#parametersHash Also known as: parameter_labels, parameter_descriptions

Returns descriptions of parameters 4-11. Parameters 1-3 are predefined as target drive, computer name, and username.

Returns:

  • (Hash)

    descriptions of parameters 4-11. Parameters 1-3 are predefined as target drive, computer name, and username



102
103
104
# File 'lib/jamf/api/classic/api_objects/script.rb', line 102

def parameters
  @parameters
end

#priorityString

Returns either ‘Before’ or ‘After’ or “At Reboot”.

Returns:

  • (String)

    either ‘Before’ or ‘After’ or “At Reboot”.



93
94
95
# File 'lib/jamf/api/classic/api_objects/script.rb', line 93

def priority
  @priority
end

#script_contentsString Also known as: code, contents

Returns the actual code for this script, if it’s stored in the database.

Returns:

  • (String)

    the actual code for this script, if it’s stored in the database.



107
108
109
# File 'lib/jamf/api/classic/api_objects/script.rb', line 107

def script_contents
  @script_contents
end

#script_contents_encodedString (readonly)

Returns the code for this script, Base64-encoded.

Returns:

  • (String)

    the code for this script, Base64-encoded



110
111
112
# File 'lib/jamf/api/classic/api_objects/script.rb', line 110

def script_contents_encoded
  @script_contents_encoded
end

Instance Method Details

#category=(new_cat) ⇒ void Originally defined in module Categorizable

This method returns an undefined value.

Change the category of this object. Any of the NON_CATEGORIES values will unset the category

Parameters:

  • new_cat (Integer, String)

    The new category

Raises:

#category_assigned?Boolean Also known as: categorized? Originally defined in module Categorizable

Does this object have a category assigned?

Returns:

  • (Boolean)

    Does this object have a category assigned?

#category_idInteger Originally defined in module Categorizable

The id of the category for this object.

Returns:

  • (Integer)

    The id of the category for this object.

#category_nameString Also known as: category Originally defined in module Categorizable

The name of the category for this object. For backward compatibility, this is aliased to just ‘category’

Returns:

  • (String)

    The name of the category for this object.

#category_objectJamf::Category Originally defined in module Categorizable

The Jamf::Category instance for this object’s category

Returns:

  • (Jamf::Category)

    The Jamf::Category instance for this object’s category

#clone(new_name, api: nil, cnx: nil) ⇒ APIObject Originally defined in module Creatable

make a clone of this API object, with a new name. The class must be creatable

Parameters:

  • name (String)

    the name for the new object

  • cnx (Jamf::Connection) (defaults to: nil)

    the API in which to create the object Defaults to the API used to instantiate this object

Returns:

  • (APIObject)

    An unsaved clone of this APIObject with the given name

Raises:

#evaluate_new_category(new_cat) ⇒ Array<String, Integer> Originally defined in module Categorizable

Given a category name or id, return the name and id TODO: use APIObject.exist? and/or APIObject.valid_id

Parameters:

  • new_cat (String, Integer)

    The name or id of a possible category

Returns:

  • (Array<String, Integer>)

    The matching name and id, which may be nil.

#name=(new_val) ⇒ void

This method returns an undefined value.

Change the script’s display name

If the filename is the same as the name, the filename will be changed also

Parameters:

  • new_val (String)

    the new display name

Raises:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/jamf/api/classic/api_objects/script.rb', line 160

def name=(new_val)
  new_val = new_val.to_s
  return if new_val == @name

  raise Jamf::MissingDataError, "Name can't be empty" if new_val.empty?
  raise Jamf::AlreadyExistsError, "A script already exists with the name '#{new_val}'" if Jamf::Script.all_names.include? new_val

  # if the filename matches the name, change that too.
  @filename = new_val if @filename == @name
  @name = new_val

  # if our REST resource is based on the name, update that too
  @rest_rsrc = "#{RSRC_BASE}/name/#{CGI.escape @name.to_s}" if @rest_rsrc.include? '/name/'
  @need_to_update = true
end

#run(**opts) ⇒ Array<(Integer,String)>

Run this script on the current machine.

If the script code is available in the #script_contents attribute, then that code is saved to a tmp file, and executed. The tmp file is deleted immediately after running

After the script runs, this method returns a two-item Array.

  • the first item is an Integer, the exit status of the script itself (0 means success)

  • the second item is a String, the output (stdout + stderr) of the script.

The exit status of the jamf binary process will be available as a Process::Status object in $? immediately after running.

Parameters:

  • opts (Hash)

    the options for running the script

Options Hash (**opts):

  • :target (String, Pathname)

    the ‘target drive’, passed to the script as the first commandline option. Defaults to ‘/’

  • :computer_name (String)

    the name of the computer, passed to the script as the second commandline option. Defaults to the name of the current machine

  • :username (String)

    the username to be passed to the script as the third commandline option. Defaults to the current console user.

  • :p4..:p11 (String)

    the values to be passed as the 4th - 11th commandline params Script params 1, 2, & 3 are the target:, computer_name: and username: params

  • :show_output (Boolean)

    should the output (stdout + stderr) be copied to stdout in realtime, as well as returned?

Returns:

  • (Array<(Integer,String)>)

    the exit status and stdout+stderr of the script

Raises:



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
# File 'lib/jamf/api/classic/api_objects/script.rb', line 375

def run(**opts)
  raise Jamf::MissingDataError, 'script_contents does not start with #!' unless @script_contents.to_s.start_with? '#!'

  opts[:target] ||= '/'
  opts[:computer_name] ||= Jamf::Client.run_jamf('getComputerName')[/>(.*?)</, 1]
  opts[:username] ||= Jamf::Client.console_user

  params = [opts[:target], opts[:computer_name], opts[:username]]
  params << opts[:p4]
  params << opts[:p5]
  params << opts[:p6]
  params << opts[:p7]
  params << opts[:p8]
  params << opts[:p9]
  params << opts[:p10]
  params << opts[:p11]

  # everything must be a string
  params.map!(&:to_s)

  # remove nils
  params.compact!

  # remove empty strings
  params.delete_if(&:empty?)

  return_value = []

  # Save and run the script from a private temp dir
  # which will be deleted when finished
  require 'tmpdir'
  Dir.mktmpdir do |dir|
    executable = Pathname.new "#{dir}/#{@name}"
    executable.jss_touch
    executable.chmod 0o700
    executable.jss_save @script_contents

    cmd = [executable.to_s]
    cmd += params

    stdout_and_stderr_str, status = Open3.capture2e(*cmd)

    return_value << status.exitstatus
    return_value << stdout_and_stderr_str
  end # Dir.mktmpdirs

  return_value
end

#set_parameter(param_num, new_val) ⇒ void Also known as: set_parameter_label, set_parameter_description

This method returns an undefined value.

Change one of the stored parameters

Parameters:

  • param_num (Integer)

    which param are we setting? must be 4..11

  • new_val (String)

    the new value for the parameter

Raises:



295
296
297
298
299
300
301
302
303
304
# File 'lib/jamf/api/classic/api_objects/script.rb', line 295

def set_parameter(param_num, new_val)
  raise Jamf::NoSuchItemError, 'Parameter numbers must be from 4-11' unless (4..11).cover? param_num

  pkey = "parameter#{param_num}".to_sym
  raise Jamf::InvalidDataError, 'parameter values must be strings or nil' unless new_val.nil? || new_val.is_a?(String)
  return nil if new_val == @parameters[pkey]

  @parameters[pkey] = new_val
  @need_to_update = true
end

#unset_categoryvoid Originally defined in module Categorizable

This method returns an undefined value.

Set the category to nothing