Class: JSS::Script

Inherits:
APIObject show all
Includes:
Creatable, Updatable
Defined in:
lib/jss-api/api_object/script.rb,
lib/jss-api.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

This class will save the script contents back to the database with the Creatable#create or Updatable#update methods

If your scripts are stored on the master distribution point instead of the database, you can use #upload_master_file to save it to the server, and #delete_master_file to delete it from the server.

Use the #run method to run the script on the local machine via the ‘jamf runScript’ command

See Also:

Constant Summary collapse

RSRC_BASE =

The base for REST resources of this class

"scripts"
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
VALID_DATA_KEYS =

these keys, as well as :id and :name, are present in valid API JSON data for this class

[:parameters, :filename, :os_requirements ]
DIST_POINT_SCRIPTS_FOLDER =

The script storage folder on the distribution point, if used

"Scripts"
PRIORITIES =

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

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

which is default?

"After"
PARAMETER_KEYS =

The keys used in the @parameters Hash

[:parameter4, :parameter5, :parameter6,:parameter7, :parameter8, :parameter9, :parameter10, :parameter11]

Constants included from Updatable

Updatable::UPDATABLE

Constants included from Creatable

Creatable::CREATABLE

Constants inherited from APIObject

APIObject::DEFAULT_LOOKUP_KEYS, APIObject::REQUIRED_DATA_KEYS

Instance Attribute Summary collapse

Attributes included from Updatable

#need_to_update

Attributes inherited from APIObject

#id, #in_jss, #name, #rest_rsrc

Instance Method Summary collapse

Methods included from Updatable

#update

Methods included from Creatable

#create

Methods inherited from APIObject

all, all_ids, all_names, #delete, get_name, map_all_ids_to, #save, xml_list

Constructor Details

#initialize(args = {}) ⇒ Script

Returns a new instance of Script.



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/jss-api/api_object/script.rb', line 139

def initialize (args = {})
  super

  @category = JSS::APIObject.get_name(@init_data[:category])
  @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] ? @init_data[:parameters] : {}
  @priority = @init_data[:priority] || DEFAULT_PRIORITY
  @script_contents =  @init_data[:script_contents]

end

Instance Attribute Details

#categoryString

Returns the category of this script, stored in the JSS as the id number from the categories table.

Returns:

  • (String)

    the category of this script, stored in the JSS as the id number from the categories table



123
124
125
# File 'lib/jss-api/api_object/script.rb', line 123

def category
  @category
end

#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



108
109
110
# File 'lib/jss-api/api_object/script.rb', line 108

def filename
  @filename
end

#infoString

Returns the info field for this script.

Returns:

  • (String)

    the info field for this script



117
118
119
# File 'lib/jss-api/api_object/script.rb', line 117

def info
  @info
end

#notesString

Returns the notes field for this script.

Returns:

  • (String)

    the notes field for this script



120
121
122
# File 'lib/jss-api/api_object/script.rb', line 120

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



111
112
113
# File 'lib/jss-api/api_object/script.rb', line 111

def os_requirements
  @os_requirements
end

#parametersHash

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

Returns:

  • (Hash)

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



126
127
128
# File 'lib/jss-api/api_object/script.rb', line 126

def parameters
  @parameters
end

#priorityString

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

Returns:

  • (String)

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



114
115
116
# File 'lib/jss-api/api_object/script.rb', line 114

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.



129
130
131
# File 'lib/jss-api/api_object/script.rb', line 129

def script_contents
  @script_contents
end

Instance Method Details

#delete_master_file(rw_pw, unmount = true) ⇒ Boolean

Delete the filename from the master distribution point, if it exists.

If you’ll be uploading several files you can specify unmount as false, and do it manually when all are finished.

Parameters:

  • rw_pw (String)

    the password for the read/write account on the master Distribution Point

  • unmount (Boolean) (defaults to: true)

    whether or not ot unount the distribution point when finished.

Returns:

  • (Boolean)

    was the file deleted?



417
418
419
420
421
422
423
424
425
426
427
# File 'lib/jss-api/api_object/script.rb', line 417

def delete_master_file(rw_pw, unmount = true)
  file = JSS::DistributionPoint.master_distribution_point.mount(rw_pw, :rw) + "#{DIST_POINT_SCRIPTS_FOLDER}/#{@filename}"
  if file.exist?
    file.delete
    did_it = true
  else
    did_it = false
  end # if exists
  JSS::DistributionPoint.master_distribution_point.unmount if unmount
  return did_it
end

#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:



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/jss-api/api_object/script.rb', line 185

def name= (new_val)
  return nil if new_val == @name
  new_val = nil if new_val == ''
  raise JSS::MissingDataError, "Name can't be empty" unless new_val
  raise JSS::AlreadyExistsError, "A #{RSRC_OBJECT_KEY} already exists with the name '#{args[:name]}'" if JSS.send(LIST_METHOD).values.include?

  ### if the filename is the same, keep it the same
  @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/#{URI.escape @name}" if @rest_rsrc.include? '/name/'
  @need_to_update = true
end

#run(opts = {}) ⇒ Array<(Integer,String)>

Run this script on the current machine using the “jamf runScript” command.

If the script code is available in the #script_contents attribute, then that code is saved to a tmp file, and executed. Otherwise, the script is assumed to be stored on the distribution point.

If the dist. point has http downloads enabled, then the URL is used as the path with the ‘jamf runScript’ command.

If http is not an option, the dist.point is mounted, and the script copied locally before running. In this case the options must include :ro_pw => ‘somepass’ to provide the read-only password for mounting the distribution point. If :unmount => true is provided, the dist. point will be unmounted immediately after copying the script locally. Otherwise it will remain mounted, in case there’s further need of it.

Any local on-disk copies of the script are removed 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 jamf binary, which will include the script output.

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

NOTE In the WEB UI and API, the definable parameters are numbered 4-11, since 1, 2, & 3 are the target drive, computer name, and user name respectively. However, the jamf binary refers to them as p1-p8, and that’s how they are expected as options to #run. So if :p1=> “new param” is given as an aption to #run, it will override any value that the API provided in @parameters

Parameters:

  • opts (Hash) (defaults to: {})

    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.

  • :p1..:p8 (String)

    the values to be passed as the 4th - 11th commandline options, overriding those defined with the script in the JSS

  • :ro_pw (String)

    the read-only password for mounting the distribution point, if needed

  • :unmount (Boolean)

    should the dist. point be unmounted when finished, if we mounted it?

  • :verbose (Boolean)

    should the ‘jamf runScript’ command be verbose?

  • :show_output (Boolean)

    should the output (stdout + stderr) of ‘jamf runScript’ be copied to stdout in realtime, as well as returned?

Returns:

  • (Array<(Integer,String)>)

    the exit status of the script and stdout+stderr of ‘jamf runScript’. The exit status of the jamf binary will be available in $? immediately after running.



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
# File 'lib/jss-api/api_object/script.rb', line 485

def run( opts = {} )

  opts[:target] ||= "/"
  opts[:p1] ||= @parameters[:parameter4]
  opts[:p2] ||= @parameters[:parameter5]
  opts[:p3] ||= @parameters[:parameter6]
  opts[:p4] ||= @parameters[:parameter7]
  opts[:p5] ||= @parameters[:parameter8]
  opts[:p6] ||= @parameters[:parameter9]
  opts[:p7] ||= @parameters[:parameter10]
  opts[:p8] ||= @parameters[:parameter11]

  dp_mount_pt = nil
  delete_exec = false

  begin

    # do we have the code already? if so, save it out and make it executable
    if @script_contents and (not @script_contents.empty?)

      script_path = JSS::Client::DOWNLOADS_FOLDER

      executable = script_path + @filename

      executable.jss_touch
      executable.chmod 0700
      executable.jss_save @script_contents
      delete_exec = true

    # otherwise, get it from the dist. point
    else
      dist_point = JSS::DistributionPoint.my_distribution_point

      ### how do we access our dist. point?
      if dist_point.http_downloads_enabled
        script_path = dist_point.http_url + "/#{DIST_POINT_SCRIPTS_FOLDER}/"

      else
        dp_mount_pt = dist_point.mount opts[:ro_pw]

        script_path = (dp_mount_pt + DIST_POINT_SCRIPTS_FOLDER)

      end # if http enabled

    end # if @script_contents and (not @script_contents.empty?)


    # build the command as an array.
    command_arry = ["-script", @filename, '-path', script_path.to_s]

    command_arry << "-target"
    command_arry << opts[:target].to_s

    command_arry << "-computerName" if opts[:computer_name]
    command_arry << opts[:computer_name] if opts[:computer_name]

    command_arry << "-username" if opts[:username]
    command_arry << opts[:username] if opts[:username]

    command_arry << "-p1" if opts[:p1]
    command_arry << opts[:p1] if opts[:p1]

    command_arry << "-p2" if opts[:p2]
    command_arry << opts[:p2] if opts[:p2]

    command_arry << "-p3" if opts[:p3]
    command_arry << opts[:p3] if opts[:p3]

    command_arry << "-p4" if opts[:p4]
    command_arry << opts[:p4] if opts[:p4]

    command_arry << "-p5" if opts[:p5]
    command_arry << opts[:p5] if opts[:p5]

    command_arry << "-p6" if opts[:p6]
    command_arry << opts[:p6] if opts[:p6]

    command_arry << "-p7" if opts[:p7]
    command_arry << opts[:p7] if opts[:p7]

    command_arry << "-p8" if opts[:p8]
    command_arry << opts[:p8] if opts[:p8]

    command_arry << "-verbose" if opts[:verbose]

    command = command_arry.shelljoin

    jamf_output =  JSS::Client.run_jamf "runScript", command, opts[:show_output]

    jamf_output =~ /^.*Script exit code: (\d+)(\D|$)/

    script_exitstatus = $1.to_i

  ensure
    executable.delete if delete_exec and executable.exist?
    dist_point.unmount if (dp_mount_pt and dp_mount_pt.mountpoint? and opts[:unmount])
  end # begin/ensure

  return [script_exitstatus, jamf_output]

end

#set_parameter(param_num, new_val) ⇒ void

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:



335
336
337
338
339
340
341
342
# File 'lib/jss-api/api_object/script.rb', line 335

def set_parameter (param_num, new_val)
  raise JSS::NoSuchItemError, "Parameter numbers must be from 4-11" unless (4..11).include? param_num
  pkey = "parameter#{param_num}".to_sym
  raise JSS::InvalidDataError, "parameter values must be strings or nil" unless new_val.nil? or new_val.kind_of? String
  return nil if new_val == @parameters[pkey]
  @parameters[pkey] = new_val
  @need_to_update = true
end

#upload_master_file(rw_pw, unmount = true) ⇒ void

This method returns an undefined value.

Save the @script_contents for this script to a file on the Master Distribution point.

If you’ll be uploading several files you can specify unmount as false, and do it manually when all are finished.

use #script_contents= to set the script_contents from a String or Pathname

Parameters:

  • rw_pw (String)

    the password for the read/write account on the master Distribution Point

  • unmount (Boolean) (defaults to: true)

    whether or not ot unount the distribution point when finished.

Raises:



394
395
396
397
398
399
400
401
402
403
# File 'lib/jss-api/api_object/script.rb', line 394

def upload_master_file( rw_pw, unmount = true)
  raise JSS::MissingDataError, "No code specified. Use #code= first." if @script_contents.nil? or @script_contents.empty?

  mdp = JSS::DistributionPoint.master_distribution_point
  raise JSS::InvaldDatatError, "Incorrect password for read-write access to master distribution point." unless mdp.check_pw :rw, rw_pw

  destination = mdp.mount(rw_pw, :rw) + "#{DIST_POINT_SCRIPTS_FOLDER}/#{@filename}"
  destination.save @script_contents
  mdp.unmount if unmount
end