ruby-jss 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +95 -0
  3. data/THANKS.md +3 -2
  4. data/lib/jamf.rb +18 -17
  5. data/lib/jamf/api/base_classes/collection_resource.rb +613 -0
  6. data/lib/jamf/api/{abstract_classes → base_classes}/json_object.rb +109 -101
  7. data/lib/jamf/api/{abstract_classes → base_classes}/prestage.rb +55 -30
  8. data/lib/jamf/api/{abstract_classes → base_classes}/resource.rb +10 -6
  9. data/lib/jamf/api/{abstract_classes → base_classes}/singleton_resource.rb +4 -3
  10. data/lib/jamf/api/connection.rb +13 -9
  11. data/lib/jamf/api/connection/api_error.rb +8 -8
  12. data/lib/jamf/api/connection/token.rb +16 -15
  13. data/lib/jamf/api/json_objects/device_enrollment_device.rb +14 -7
  14. data/lib/jamf/api/json_objects/{location.rb → device_enrollment_device_sync_state.rb} +27 -41
  15. data/lib/jamf/api/json_objects/device_enrollment_sync_status.rb +1 -1
  16. data/lib/jamf/api/json_objects/{attachment.rb → locale.rb} +14 -23
  17. data/lib/jamf/api/json_objects/md_prestage_name.rb +1 -1
  18. data/lib/jamf/api/json_objects/md_prestage_names.rb +2 -2
  19. data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +50 -1
  20. data/lib/jamf/api/json_objects/prestage_assignment.rb +2 -2
  21. data/lib/jamf/api/json_objects/prestage_location.rb +3 -3
  22. data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +7 -7
  23. data/lib/jamf/api/json_objects/prestage_scope.rb +1 -1
  24. data/lib/jamf/api/{resources/collection_resources → json_objects}/time_zone.rb +9 -23
  25. data/lib/jamf/api/mixins/{abstract.rb → base_class.rb} +34 -16
  26. data/lib/jamf/api/mixins/bulk_deletable.rb +27 -6
  27. data/lib/jamf/api/mixins/change_log.rb +201 -51
  28. data/lib/jamf/api/{resources/collection_resources/computer.rb → mixins/filterable.rb} +19 -17
  29. data/lib/jamf/api/mixins/pageable.rb +208 -0
  30. data/lib/jamf/api/{json_objects/installed_application.rb → mixins/sortable.rb} +33 -33
  31. data/lib/jamf/api/resources/collection_resources/building.rb +16 -9
  32. data/lib/jamf/api/resources/collection_resources/category.rb +5 -4
  33. data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +12 -5
  34. data/lib/jamf/api/resources/collection_resources/department.rb +0 -2
  35. data/lib/jamf/api/resources/collection_resources/device_enrollment.rb +10 -10
  36. data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +11 -3
  37. data/lib/jamf/api/resources/collection_resources/mobile_device_prestage.rb +25 -23
  38. data/lib/jamf/api/resources/collection_resources/script.rb +61 -25
  39. data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +15 -5
  40. data/lib/jamf/api/resources/singleton_resources/locales.rb +155 -0
  41. data/lib/jamf/api/resources/singleton_resources/time_zones.rb +213 -0
  42. data/lib/jamf/client.rb +3 -3
  43. data/lib/jamf/client/management_action.rb +2 -3
  44. data/lib/jamf/composer.rb +2 -2
  45. data/lib/jamf/utility.rb +35 -7
  46. data/lib/jamf/validate.rb +63 -24
  47. data/lib/jamf/version.rb +1 -1
  48. data/lib/jss.rb +2 -2
  49. data/lib/jss/api_connection.rb +114 -406
  50. data/lib/jss/api_object.rb +3 -19
  51. data/lib/jss/api_object/categorizable.rb +1 -1
  52. data/lib/jss/api_object/computer.rb +13 -0
  53. data/lib/jss/api_object/configuration_profile.rb +61 -5
  54. data/lib/jss/api_object/directory_binding_type.rb +66 -60
  55. data/lib/jss/api_object/directory_binding_type/active_directory.rb +71 -34
  56. data/lib/jss/api_object/directory_binding_type/admitmac.rb +536 -467
  57. data/lib/jss/api_object/directory_binding_type/centrify.rb +21 -7
  58. data/lib/jss/api_object/directory_binding_type/open_directory.rb +4 -4
  59. data/lib/jss/api_object/distribution_point.rb +2 -2
  60. data/lib/jss/api_object/dock_item.rb +102 -96
  61. data/lib/jss/api_object/extendable.rb +1 -1
  62. data/lib/jss/api_object/group.rb +33 -2
  63. data/lib/jss/api_object/network_segment.rb +45 -13
  64. data/lib/jss/api_object/patch_source.rb +10 -9
  65. data/lib/jss/api_object/policy.rb +155 -25
  66. data/lib/jss/api_object/printer.rb +10 -4
  67. data/lib/jss/api_object/scopable.rb +10 -15
  68. data/lib/jss/api_object/scopable/scope.rb +31 -30
  69. data/lib/jss/api_object/script.rb +242 -352
  70. data/lib/jss/api_object/user.rb +1 -1
  71. data/lib/jss/client/management_action.rb +1 -2
  72. data/lib/jss/composer.rb +2 -2
  73. data/lib/jss/exceptions.rb +3 -0
  74. data/lib/jss/server.rb +15 -0
  75. data/lib/jss/utility.rb +213 -45
  76. data/lib/jss/version.rb +1 -1
  77. metadata +46 -64
  78. data/lib/jamf/api/abstract_classes/advanced_search.rb +0 -86
  79. data/lib/jamf/api/abstract_classes/collection_resource.rb +0 -433
  80. data/lib/jamf/api/abstract_classes/generic_reference.rb +0 -145
  81. data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +0 -126
  82. data/lib/jamf/api/json_objects/account_prefs.rb +0 -79
  83. data/lib/jamf/api/json_objects/android_details.rb +0 -139
  84. data/lib/jamf/api/json_objects/appletv_details.rb +0 -110
  85. data/lib/jamf/api/json_objects/cellular_network.rb +0 -151
  86. data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +0 -67
  87. data/lib/jamf/api/json_objects/criterion.rb +0 -152
  88. data/lib/jamf/api/json_objects/extension_attribute_value.rb +0 -128
  89. data/lib/jamf/api/json_objects/installed_certificate.rb +0 -53
  90. data/lib/jamf/api/json_objects/installed_configuration_profile.rb +0 -67
  91. data/lib/jamf/api/json_objects/installed_ebook.rb +0 -58
  92. data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +0 -59
  93. data/lib/jamf/api/json_objects/ios_details.rb +0 -244
  94. data/lib/jamf/api/json_objects/mobile_device_details.rb +0 -219
  95. data/lib/jamf/api/json_objects/mobile_device_security.rb +0 -101
  96. data/lib/jamf/api/json_objects/purchasing_data.rb +0 -125
  97. data/lib/jamf/api/mixins/locatable.rb +0 -124
  98. data/lib/jamf/api/mixins/referable.rb +0 -92
  99. data/lib/jamf/api/resources/collection_resources/account.rb +0 -163
  100. data/lib/jamf/api/resources/collection_resources/advanced_mobile_device_search.rb +0 -52
  101. data/lib/jamf/api/resources/collection_resources/advanced_user_search.rb +0 -52
  102. data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +0 -45
  103. data/lib/jamf/api/resources/collection_resources/mobile_device.rb +0 -315
  104. data/lib/jamf/api/resources/collection_resources/site.rb +0 -77
  105. data/lib/jamf/api/resources/singleton_resources/authorization.rb +0 -88
  106. data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +0 -139
  107. data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +0 -95
@@ -1,94 +1,91 @@
1
- ### Copyright 2020 Pixar
2
-
3
- ###
4
- ### Licensed under the Apache License, Version 2.0 (the "Apache License")
5
- ### with the following modification; you may not use this file except in
6
- ### compliance with the Apache License and the following modification to it:
7
- ### Section 6. Trademarks. is deleted and replaced with:
8
- ###
9
- ### 6. Trademarks. This License does not grant permission to use the trade
10
- ### names, trademarks, service marks, or product names of the Licensor
11
- ### and its affiliates, except as required to comply with Section 4(c) of
12
- ### the License and to reproduce the content of the NOTICE file.
13
- ###
14
- ### You may obtain a copy of the Apache License at
15
- ###
16
- ### http://www.apache.org/licenses/LICENSE-2.0
17
- ###
18
- ### Unless required by applicable law or agreed to in writing, software
19
- ### distributed under the Apache License with the above modification is
20
- ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
- ### KIND, either express or implied. See the Apache License for the specific
22
- ### language governing permissions and limitations under the Apache License.
23
- ###
24
- ###
25
-
26
- ###
1
+ # Copyright 2020 Pixar
2
+
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "Apache License")
5
+ # with the following modification; you may not use this file except in
6
+ # compliance with the Apache License and the following modification to it:
7
+ # Section 6. Trademarks. is deleted and replaced with:
8
+ #
9
+ # 6. Trademarks. This License does not grant permission to use the trade
10
+ # names, trademarks, service marks, or product names of the Licensor
11
+ # and its affiliates, except as required to comply with Section 4(c) of
12
+ # the License and to reproduce the content of the NOTICE file.
13
+ #
14
+ # You may obtain a copy of the Apache License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the Apache License with the above modification is
20
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21
+ # KIND, either express or implied. See the Apache License for the specific
22
+ # language governing permissions and limitations under the Apache License.
23
+ #
24
+ #
25
+
26
+ #
27
27
  module JSS
28
28
 
29
- ### Module Constants
29
+ # Module Constants
30
30
  #####################################
31
31
 
32
- ### Module Variables
32
+ # Module Variables
33
33
  #####################################
34
34
 
35
- ### Module Methods
35
+ # Module Methods
36
36
  #####################################
37
37
 
38
- ### Classes
38
+ # Classes
39
39
  #####################################
40
40
 
41
- ### A Script in the JSS.
42
- ###
43
- ### As of Casper 9.4, the script contents as stored in the database are
44
- ### accessible via the API
45
- ###
46
- ### This class will save the script contents back to the database with
47
- ### the {#create} or {#update} methods
48
- ###
49
- ### If your scripts are stored on the master distribution point instead of
50
- ### the database, you can use {#upload_master_file} to save it to the server,
51
- ### and {#delete_master_file} to delete it from the server.
52
- ###
53
- ### Use the {#run} method to run the script on the local machine via the 'jamf runScript' command
54
- ###
55
- ### @see JSS::APIObject
56
- ###
41
+ # A Script in the JSS.
42
+ #
43
+ # As of Casper 9.4, the script contents as stored in the database are
44
+ # accessible via the API
45
+ #
46
+ # According to Jamf as of early 2021, it has been some years now since
47
+ # its been possible to store script contents on a dist. point - they
48
+ # are all always in the database.
49
+ #
50
+ # Use the {#run} method to run the script on the local machine.
51
+ #
52
+ # @see JSS::APIObject
53
+ #
57
54
  class Script < JSS::APIObject
58
55
 
59
- ### Mix-Ins
56
+ # Mix-Ins
60
57
  #####################################
61
58
 
62
59
  include JSS::Creatable
63
60
  include JSS::Updatable
64
61
  include JSS::Categorizable
65
62
 
66
- ### Class Methods
63
+ # Class Methods
67
64
  #####################################
68
65
 
69
- ### Class Constants
66
+ # Class Constants
70
67
  #####################################
71
68
 
72
- ### The base for REST resources of this class
69
+ # The base for REST resources of this class
73
70
  RSRC_BASE = 'scripts'.freeze
74
71
 
75
- ### the hash key used for the JSON list output of all objects in the JSS
72
+ # the hash key used for the JSON list output of all objects in the JSS
76
73
  RSRC_LIST_KEY = :scripts
77
74
 
78
- ### The hash key used for the JSON object output.
79
- ### It's also used in various error messages
75
+ # The hash key used for the JSON object output.
76
+ # It's also used in various error messages
80
77
  RSRC_OBJECT_KEY = :script
81
78
 
82
- ### The script storage folder on the distribution point, if used
79
+ # The script storage folder on the distribution point, if used
83
80
  DIST_POINT_SCRIPTS_FOLDER = 'Scripts'.freeze
84
81
 
85
- ### Priority to use for running the script in relation to other actions during imaging
82
+ # Priority to use for running the script in relation to other actions during imaging
86
83
  PRIORITIES = ['Before', 'After', 'At Reboot'].freeze
87
84
 
88
- ### which is default?
85
+ # which is default?
89
86
  DEFAULT_PRIORITY = 'After'.freeze
90
87
 
91
- ### The keys used in the @parameters Hash
88
+ # The keys used in the @parameters Hash
92
89
  PARAMETER_KEYS = [:parameter4, :parameter5, :parameter6, :parameter7, :parameter8, :parameter9, :parameter10, :parameter11].freeze
93
90
 
94
91
  # the object type for this object in
@@ -103,34 +100,39 @@ module JSS
103
100
  CATEGORY_DATA_TYPE = String
104
101
 
105
102
 
106
- ### Attributes
103
+ # Attributes
107
104
  #####################################
108
105
 
109
- ### @return [String] the file name of the script, if stored in a dist. point
106
+ # @return [String] the file name of the script, if stored in a dist. point
110
107
  attr_reader :filename
111
108
 
112
- ### @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
109
+ # @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
113
110
  attr_reader :os_requirements
114
111
 
115
- ### @return [String] either 'Before' or 'After' or "At Reboot".
112
+ # @return [String] either 'Before' or 'After' or "At Reboot".
116
113
  attr_reader :priority
117
114
 
118
- ### @return [String] the info field for this script
115
+ # @return [String] the info field for this script
119
116
  attr_reader :info
120
117
 
121
- ### @return [String] the notes field for this script
118
+ # @return [String] the notes field for this script
122
119
  attr_reader :notes
123
120
 
124
- ### @return [Hash] script parameters 4-11. Parameters 1-3 are predefined as target drive, computer name, and username
121
+ # @return [Hash] descriptions of parameters 4-11. Parameters 1-3 are predefined as target drive, computer name, and username
125
122
  attr_reader :parameters
123
+ alias parameter_labels parameters
124
+ alias parameter_descriptions parameters
126
125
 
127
- ### @return {String] the actual code for this script, if it's stored in the database.
126
+ # @return {String] the actual code for this script, if it's stored in the database.
128
127
  attr_reader :script_contents
129
128
 
130
- ### Constructor
129
+ # @return [String] the code for this script, Base64-encoded
130
+ attr_reader :script_contents_encoded
131
+
132
+ # Constructor
131
133
  #####################################
132
134
 
133
- ###
135
+ #
134
136
  def initialize(args = {})
135
137
  super
136
138
 
@@ -141,19 +143,23 @@ module JSS
141
143
  @parameters = @init_data[:parameters] ? @init_data[:parameters] : {}
142
144
  @priority = @init_data[:priority] || DEFAULT_PRIORITY
143
145
  @script_contents = @init_data[:script_contents]
146
+ @script_contents_encoded = @init_data[:script_contents_encoded]
147
+ if @script_contents && @script_contents_encoded.to_s.empty?
148
+ @script_contents_encoded = Base64.encode64 @script_contents
149
+ end
144
150
  end # initialize
145
151
 
146
- ### Change the script filename
147
- ###
148
- ### Setting it to nil will make it match the script name
149
- ###
150
- ### @param new_val[String,Nil] the new filename
151
- ###
152
- ### @return [void]
153
- ###
154
- ### @note This method does NOT change the filename on the distribution point
155
- ### if that's where you store your scripts.
156
- ###
152
+ # Change the script filename
153
+ #
154
+ # Setting it to nil will make it match the script name
155
+ #
156
+ # @param new_val[String,Nil] the new filename
157
+ #
158
+ # @return [void]
159
+ #
160
+ # @note This method does NOT change the filename on the distribution point
161
+ # if that's where you store your scripts.
162
+ #
157
163
  def filename=(new_val)
158
164
  new_val = nil if new_val == ''
159
165
  new_val = @name unless new_val
@@ -164,14 +170,14 @@ module JSS
164
170
  @need_to_update = true
165
171
  end # filename=
166
172
 
167
- ### Change the script's display name
168
- ###
169
- ### If the filename is the same as the name, the filename will be changed also
170
- ###
171
- ### @param new_val[String] the new display name
172
- ###
173
- ### @return [void]
174
- ###
173
+ # Change the script's display name
174
+ #
175
+ # If the filename is the same as the name, the filename will be changed also
176
+ #
177
+ # @param new_val[String] the new display name
178
+ #
179
+ # @return [void]
180
+ #
175
181
  def name=(new_val)
176
182
  new_val = new_val.to_s
177
183
  return if new_val == @name
@@ -179,39 +185,39 @@ module JSS
179
185
  raise JSS::MissingDataError, "Name can't be empty" if new_val.empty?
180
186
  raise JSS::AlreadyExistsError, "A script already exists with the name '#{new_val}'" if JSS::Script.all_names.include? new_val
181
187
 
182
- ### if the filename matches the name, change that too.
188
+ # if the filename matches the name, change that too.
183
189
  @filename = new_val if @filename == @name
184
190
  @name = new_val
185
191
 
186
- ### if our REST resource is based on the name, update that too
192
+ # if our REST resource is based on the name, update that too
187
193
  @rest_rsrc = "#{RSRC_BASE}/name/#{CGI.escape @name.to_s}" if @rest_rsrc.include? '/name/'
188
194
  @need_to_update = true
189
195
  end # name=
190
196
 
191
- ### Change the os_requirements
192
- ###
193
- ### Minumum OS's can be specified as a string using the notation ">=10.6.7"
194
- ### See the {JSS.expand_min_os} method for details.
195
- ###
196
- ### @param new_val[String, Array<String>] the new os requirements as a comma-separted String or an Array of Strings
197
- ###
198
- ### @return [void]
199
- ###
200
- ### @example String value
201
- ### myscript.os_requirements "10.5, 10.5.3, 10.6.x"
202
- ###
203
- ### @example Array value
204
- ### ok_oses = ['10.5', '10.5.3', '10.6.x']
205
- ### myscript.os_requirements ok_oses
206
- ###
207
- ### @example Minimum OS
208
- ### myscript.os_requirements ">=10.7.5"
209
- ###
197
+ # Change the os_requirements
198
+ #
199
+ # Minumum OS's can be specified as a string using the notation ">=10.6.7"
200
+ # See the {JSS.expand_min_os} method for details.
201
+ #
202
+ # @param new_val[String, Array<String>] the new os requirements as a comma-separted String or an Array of Strings
203
+ #
204
+ # @return [void]
205
+ #
206
+ # @example String value
207
+ # myscript.os_requirements "10.5, 10.5.3, 10.6.x"
208
+ #
209
+ # @example Array value
210
+ # ok_oses = ['10.5', '10.5.3', '10.6.x']
211
+ # myscript.os_requirements ok_oses
212
+ #
213
+ # @example Minimum OS
214
+ # myscript.os_requirements ">=10.7.5"
215
+ #
210
216
  def os_requirements=(new_val)
211
- ### nil should be an empty array
217
+ # nil should be an empty array
212
218
  new_val = [] if new_val.to_s.empty?
213
219
 
214
- ### if any value starts with >=, expand it
220
+ # if any value starts with >=, expand it
215
221
  case new_val
216
222
  when String
217
223
  new_val = JSS.expand_min_os(new_val) if new_val =~ /^>=/
@@ -223,17 +229,17 @@ module JSS
223
229
  raise JSS::InvalidDataError, 'os_requirements must be a String or an Array of strings'
224
230
  end # case
225
231
 
226
- ### get the array version
232
+ # get the array version
227
233
  @os_requirements = JSS.to_s_and_a(new_val)[:arrayform]
228
234
  @need_to_update = true
229
235
  end # os_requirements=
230
236
 
231
- ### Change the priority of this script
232
- ###
233
- ### @param new_val[Integer] the new priority, which must be one of {PRIORITIES}
234
- ###
235
- ### @return [void]
236
- ###
237
+ # Change the priority of this script
238
+ #
239
+ # @param new_val[Integer] the new priority, which must be one of {PRIORITIES}
240
+ #
241
+ # @return [void]
242
+ #
237
243
  def priority=(new_val)
238
244
  return nil if new_val == @priority
239
245
  new_val = DEFAULT_PRIORITY if new_val.nil? || (new_val == '')
@@ -242,47 +248,47 @@ module JSS
242
248
  @need_to_update = true
243
249
  end # priority=
244
250
 
245
- ### Change the info field
246
- ###
247
- ### @param new_val[String] the new info
248
- ###
249
- ### @return [void]
250
- ###
251
+ # Change the info field
252
+ #
253
+ # @param new_val[String] the new info
254
+ #
255
+ # @return [void]
256
+ #
251
257
  def info=(new_val)
252
258
  return nil if new_val == @info
253
- ### line breaks should be \r
259
+ # line breaks should be \r
254
260
  new_val = new_val.to_s.tr("\n", "\r")
255
261
  @info = new_val
256
262
  @need_to_update = true
257
263
  end # info=
258
264
 
259
- ### Change the notes field
260
- ###
261
- ### @param new_val[String] the new notes
262
- ###
263
- ### @return [void]
264
- ###
265
+ # Change the notes field
266
+ #
267
+ # @param new_val[String] the new notes
268
+ #
269
+ # @return [void]
270
+ #
265
271
  def notes=(new_val)
266
272
  return nil if new_val == @notes
267
- ### line breaks should be \r
273
+ # line breaks should be \r
268
274
  new_val = new_val.to_s.tr("\n", "\r")
269
275
  @notes = new_val
270
276
  @need_to_update = true
271
277
  end # notes=
272
278
 
273
- ### Replace all the script parameters at once.
274
- ###
275
- ### This will replace the entire set with the hash provided.
276
- ###
277
- ### @param new_val[Hash] the Hash keys must exist in {PARAMETER_KEYS}
278
- ###
279
- ### @return [void]
280
- ###
279
+ # Replace all the script parameters at once.
280
+ #
281
+ # This will replace the entire set with the hash provided.
282
+ #
283
+ # @param new_val[Hash] the Hash keys must exist in {PARAMETER_KEYS}
284
+ #
285
+ # @return [void]
286
+ #
281
287
  def parameters=(new_val)
282
288
  return nil if new_val == @parameters
283
289
  new_val = {} if new_val.nil? || (new_val == '')
284
290
 
285
- ### check the values
291
+ # check the values
286
292
  raise JSS::InvalidDataError, ':parameters must be a Hash with keys :parameter4 thru :parameter11' unless \
287
293
  new_val.is_a?(Hash) && ((new_val.keys & PARAMETER_KEYS) == new_val.keys)
288
294
  new_val.each do |_k, v|
@@ -293,14 +299,14 @@ module JSS
293
299
  @need_to_update = true
294
300
  end # parameters=
295
301
 
296
- ### Change one of the stored parameters
297
- ###
298
- ### @param param_num[Integer] which param are we setting? must be 4..11
299
- ###
300
- ### @param new_val[String] the new value for the parameter
301
- ###
302
- ### @return [void]
303
- ###
302
+ # Change one of the stored parameters
303
+ #
304
+ # @param param_num[Integer] which param are we setting? must be 4..11
305
+ #
306
+ # @param new_val[String] the new value for the parameter
307
+ #
308
+ # @return [void]
309
+ #
304
310
  def set_parameter(param_num, new_val)
305
311
  raise JSS::NoSuchItemError, 'Parameter numbers must be from 4-11' unless (4..11).cover? param_num
306
312
  pkey = "parameter#{param_num}".to_sym
@@ -309,21 +315,23 @@ module JSS
309
315
  @parameters[pkey] = new_val
310
316
  @need_to_update = true
311
317
  end
312
-
313
- ### Change the executable code of this script.
314
- ###
315
- ### If the arg is a Pathname instance, or a String starting with "/"
316
- ### Then the arg is assumed to be a file from which to read the code.
317
- ###
318
- ### Otherwise it should be a String with the code itself, and it must start with '#!"
319
- ###
320
- ### After doing this, use {#create} or {#update} to write it to the database or
321
- ### use {#upload_master_file} to save it to the master dist. point.
322
- ###
323
- ### @param new_val[String,Pathname] the new script contents or a path to a file containing it.
324
- ###
325
- ### @return [void]
326
- ###
318
+ alias set_parameter_label set_parameter
319
+ alias set_parameter_description set_parameter
320
+
321
+ # Change the executable code of this script.
322
+ #
323
+ # If the arg is a Pathname instance, or a String starting with "/"
324
+ # Then the arg is assumed to be a file from which to read the code.
325
+ #
326
+ # Otherwise it should be a String with the code itself, and it must start with '#!"
327
+ #
328
+ # After doing this, use {#create} or {#update} to write it to the database or
329
+ # use {#upload_master_file} to save it to the master dist. point.
330
+ #
331
+ # @param new_val[String,Pathname] the new script contents or a path to a file containing it.
332
+ #
333
+ # @return [void]
334
+ #
327
335
  def script_contents=(new_val)
328
336
  new_code = case new_val
329
337
  when String
@@ -341,207 +349,89 @@ module JSS
341
349
  raise JSS::InvalidDataError, "Script contents must start with '#!'" unless new_code.start_with? '#!'
342
350
 
343
351
  @script_contents = new_code
352
+ @script_contents_encoded = Base64.encode64 @script_contents
344
353
  @need_to_update = true
345
354
  end
346
355
 
347
- ### Save the @script_contents for this script to a file on the Master Distribution point.
348
- ###
349
- ### If you'll be uploading several files you can specify unmount as false, and do it manually when all
350
- ### are finished.
351
- ###
352
- ### use {#script_contents=} to set the script_contents from a String or Pathname
353
- ###
354
- ### @param rw_pw[String] the password for the read/write account on the master Distribution Point
355
- ###
356
- ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
357
- ###
358
- ### @return [void]
359
- ###
360
- def upload_master_file(rw_pw, unmount = true)
361
- raise JSS::MissingDataError, 'No code specified. Use #code= first.' if @script_contents.nil? || @script_contents.empty?
362
-
363
- mdp = JSS::DistributionPoint.master_distribution_point
364
- raise JSS::InvaldDatatError, 'Incorrect password for read-write access to master distribution point.' unless mdp.check_pw :rw, rw_pw
365
-
366
- destination = mdp.mount(rw_pw, :rw) + "#{DIST_POINT_SCRIPTS_FOLDER}/#{@filename}"
367
- destination.save @script_contents
368
- mdp.unmount if unmount
369
- end # upload
370
-
371
- ### Delete the filename from the master distribution point, if it exists.
372
- ###
373
- ### If you'll be uploading several files you can specify unmount as false, and do it manually when all
374
- ### are finished.
375
- ###
376
- ### @param rw_pw[String] the password for the read/write account on the master Distribution Point
377
- ###
378
- ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
379
- ###
380
- ### @return [Boolean] was the file deleted?
381
- ###
382
- def delete_master_file(rw_pw, unmount = true)
383
- file = JSS::DistributionPoint.master_distribution_point.mount(rw_pw, :rw) + "#{DIST_POINT_SCRIPTS_FOLDER}/#{@filename}"
384
- if file.exist?
385
- file.delete
386
- did_it = true
387
- else
388
- did_it = false
389
- end # if exists
390
- JSS::DistributionPoint.master_distribution_point.unmount if unmount
391
- did_it
392
- end
393
-
394
- ### Run this script on the current machine using the "jamf runScript" command.
395
- ###
396
- ### If the script code is available in the {#script_contents} attribute, then that
397
- ### code is saved to a tmp file, and executed. Otherwise, the script is assumed
398
- ### to be stored on the distribution point.
399
- ###
400
- ### If the dist. point has http downloads enabled, then the URL is used as the path with the
401
- ### 'jamf runScript' command.
402
- ###
403
- ### If http is not an option, the dist.point is mounted, and the script copied locally before running.
404
- ### In this case the options must include :ro_pw => 'somepass'
405
- ### to provide the read-only password for mounting the distribution point. If :unmount => true
406
- ### is provided, the dist. point will be unmounted immediately after copying
407
- ### the script locally. Otherwise it will remain mounted, in case there's further need of it.
408
- ###
409
- ### Any local on-disk copies of the script are removed after running.
410
- ###
411
- ### After the script runs, this method returns a two-item Array.
412
- ### - the first item is an Integer, the exit status of the script itself (0 means success)
413
- ### - the second item is a String, the output (stdout + stderr) of the jamf binary, which will include
414
- ### the script output.
415
- ### The exit status of the jamf binary process will be available as a Process::Status object
416
- ### in $? immediately after running.
417
- ###
418
- ### @param opts[Hash] the options for running the script
419
- ###
420
- ### @option opts :target[String,Pathname] the 'target drive', passed to the script as the first commandline option.
421
- ### Defaults to '/'
422
- ###
423
- ### @option opts :computer_name[String] the name of the computer, passed to the script as the second commandline
424
- ### option. Defaults to the name of the current machine
425
- ###
426
- ### @option opts :username[String] the username to be passed to the script as the third commandline option.
427
- ###
428
- ### @option opts :p1..:p8[String] the values to be passed as the 4th - 11th commandline options, overriding
429
- ### those defined with the script in the JSS
430
- ###
431
- ### @option opts :ro_pw[String] the read-only password for mounting the distribution point, if needed
432
- ###
433
- ### @option opts :unmount[Boolean} should the dist. point be unmounted when finished, if we mounted it?
434
- ###
435
- ### @option opts :verbose[Boolean] should the 'jamf runScript' command be verbose?
436
- ###
437
- ### @option opts :show_output[Boolean] should the output (stdout + stderr) of 'jamf runScript' be copied to
438
- ### stdout in realtime, as well as returned?
439
- ###
440
- ### @return [Array<(Integer,String)>] the exit status of the *script* and stdout+stderr of 'jamf runScript'.
441
- ### The exit status of the jamf binary will be available in $? immediately after running.
442
- ###
443
- ### *NOTE* In the WEB UI and API, the definable parameters are numbered 4-11, since 1, 2, & 3 are the
444
- ### target drive, computer name, and user name respectively. However, the jamf binary refers to them as
445
- ### p1-p8, and that's how they are expected as options to #run. So if :p1=> "new param" is given as an
446
- ### aption to #run, it will override any value that the API provided in @parameters[:parameter4]
447
- ###
356
+ # Run this script on the current machine.
357
+ #
358
+ # If the script code is available in the {#script_contents} attribute, then that
359
+ # code is saved to a tmp file, and executed. The tmp file is deleted immediately
360
+ # after running
361
+ #
362
+ # After the script runs, this method returns a two-item Array.
363
+ # - the first item is an Integer, the exit status of the script itself (0 means success)
364
+ # - the second item is a String, the output (stdout + stderr) of the script.
365
+ #
366
+ # The exit status of the jamf binary process will be available as a Process::Status object
367
+ # in $? immediately after running.
368
+ #
369
+ # @param opts[Hash] the options for running the script
370
+ #
371
+ # @option opts :target[String,Pathname] the 'target drive', passed to the script as the first commandline option.
372
+ # Defaults to '/'
373
+ #
374
+ # @option opts :computer_name[String] the name of the computer, passed to the script as the second commandline
375
+ # option. Defaults to the name of the current machine
376
+ #
377
+ # @option opts :username[String] the username to be passed to the script as the third commandline option.
378
+ # Defaults to the current console user.
379
+ #
380
+ # @option opts :p4..:p11[String] the values to be passed as the 4th - 11th commandline params
381
+ # Script params 1, 2, & 3 are the target:, computer_name: and username: params
382
+ #
383
+ # @option opts :show_output[Boolean] should the output (stdout + stderr) be copied to
384
+ # stdout in realtime, as well as returned?
385
+ #
386
+ # @return [Array<(Integer,String)>] the exit status and stdout+stderr of the script
387
+ #
448
388
  def run(opts = {})
449
- opts[:target] ||= '/'
450
- opts[:p1] ||= @parameters[:parameter4]
451
- opts[:p2] ||= @parameters[:parameter5]
452
- opts[:p3] ||= @parameters[:parameter6]
453
- opts[:p4] ||= @parameters[:parameter7]
454
- opts[:p5] ||= @parameters[:parameter8]
455
- opts[:p6] ||= @parameters[:parameter9]
456
- opts[:p7] ||= @parameters[:parameter10]
457
- opts[:p8] ||= @parameters[:parameter11]
458
-
459
- dp_mount_pt = nil
460
- delete_exec = false
461
-
462
- begin
463
-
464
- # do we have the code already? if so, save it out and make it executable
465
- if @script_contents && !@script_contents.empty?
466
-
467
- script_path = JSS::Client::DOWNLOADS_FOLDER
468
-
469
- executable = script_path + @filename
470
-
471
- executable.jss_touch
472
- executable.chmod 0o700
473
- executable.jss_save @script_contents
474
- delete_exec = true
475
-
476
- # otherwise, get it from the dist. point
477
- else
478
- dist_point = JSS::DistributionPoint.my_distribution_point api: @api
389
+ raise JSS::MissingDataError, 'script_contents does not start with #!' unless @script_contents.to_s.start_with? '#!'
479
390
 
480
- ### how do we access our dist. point?
481
- if dist_point.http_downloads_enabled
482
- script_path = dist_point.http_url + "/#{DIST_POINT_SCRIPTS_FOLDER}/"
483
-
484
- else
485
- dp_mount_pt = dist_point.mount opts[:ro_pw]
486
-
487
- script_path = (dp_mount_pt + DIST_POINT_SCRIPTS_FOLDER)
488
-
489
- end # if http enabled
490
-
491
- end # if @script_contents and (not @script_contents.empty?)
492
-
493
- # build the command as an array.
494
- command_arry = ['-script', @filename, '-path', script_path.to_s]
495
-
496
- command_arry << '-target'
497
- command_arry << opts[:target].to_s
498
-
499
- command_arry << '-computerName' if opts[:computer_name]
500
- command_arry << opts[:computer_name] if opts[:computer_name]
501
-
502
- command_arry << '-username' if opts[:username]
503
- command_arry << opts[:username] if opts[:username]
504
-
505
- command_arry << '-p1' if opts[:p1]
506
- command_arry << opts[:p1] if opts[:p1]
507
-
508
- command_arry << '-p2' if opts[:p2]
509
- command_arry << opts[:p2] if opts[:p2]
510
-
511
- command_arry << '-p3' if opts[:p3]
512
- command_arry << opts[:p3] if opts[:p3]
513
-
514
- command_arry << '-p4' if opts[:p4]
515
- command_arry << opts[:p4] if opts[:p4]
516
-
517
- command_arry << '-p5' if opts[:p5]
518
- command_arry << opts[:p5] if opts[:p5]
391
+ opts[:target] ||= '/'
392
+ opts[:computer_name] ||= JSS::Client.run_jamf('getComputerName')[/>(.)</, 1]
393
+ opts[:username] ||= JSS::Client.console_user
519
394
 
520
- command_arry << '-p6' if opts[:p6]
521
- command_arry << opts[:p6] if opts[:p6]
395
+ params = [opts[:target], opts[:computer_name], opts[:username]]
396
+ params << opts[:p4]
397
+ params << opts[:p5]
398
+ params << opts[:p6]
399
+ params << opts[:p7]
400
+ params << opts[:p8]
401
+ params << opts[:p9]
402
+ params << opts[:p10]
403
+ params << opts[:p11]
522
404
 
523
- command_arry << '-p7' if opts[:p7]
524
- command_arry << opts[:p7] if opts[:p7]
405
+ # everything must be a string
406
+ params.map! &:to_s
525
407
 
526
- command_arry << '-p8' if opts[:p8]
527
- command_arry << opts[:p8] if opts[:p8]
408
+ # remove nils
409
+ params.compact!
528
410
 
529
- command_arry << '-verbose' if opts[:verbose]
411
+ # remove empty strings
412
+ params.delete_if &:empty?
530
413
 
531
- command = command_arry.shelljoin
414
+ return_value = []
532
415
 
533
- jamf_output = JSS::Client.run_jamf 'runScript', command, opts[:show_output]
416
+ # Save and run the script from a private temp dir
417
+ # which will be deleted when finished
418
+ require 'tmpdir'
419
+ Dir.mktmpdir do |dir|
420
+ executable = Pathname.new "#{dir}/#{@name}"
421
+ executable.jss_touch
422
+ executable.chmod 0o700
423
+ executable.jss_save @script_contents
534
424
 
535
- jamf_output =~ /^.*Script exit code: (\d+)(\D|$)/
425
+ cmd = [executable.to_s]
426
+ cmd += params
536
427
 
537
- script_exitstatus = Regexp.last_match(1).to_i
428
+ stdout_and_stderr_str, status = Open3.capture2e(*cmd)
538
429
 
539
- ensure
540
- executable.delete if delete_exec && executable.exist?
541
- dist_point.unmount if dp_mount_pt && dp_mount_pt.mountpoint? && opts[:unmount]
542
- end # begin/ensure
430
+ return_value << status.exitstatus
431
+ return_value << stdout_and_stderr_str
432
+ end # Dir.mktmpdirs
543
433
 
544
- [script_exitstatus, jamf_output]
434
+ return_value
545
435
  end # def run
546
436
 
547
437
  # aliases under their methods seem to confuse the YARD documenter, so I'm putting them all here.
@@ -552,13 +442,13 @@ module JSS
552
442
  alias contents script_contents
553
443
  alias contents= script_contents=
554
444
 
555
- ### Private Instance Methods
445
+ # Private Instance Methods
556
446
  #####################################
557
447
 
558
448
  private
559
449
 
560
- ### Return the xml for creating or updating this script in the JSS
561
- ###
450
+ # Return the xml for creating or updating this script in the JSS
451
+ #
562
452
  def rest_xml
563
453
  doc = REXML::Document.new
564
454
  scpt = doc.add_element 'script'
@@ -579,7 +469,7 @@ module JSS
579
469
  PARAMETER_KEYS.each { |p| pars.add_element(p.to_s).text = @parameters[p] }
580
470
  end
581
471
 
582
- scpt.add_element('script_contents_encoded').text = Base64.encode64(@script_contents)
472
+ scpt.add_element('script_contents_encoded').text = script_contents_encoded
583
473
 
584
474
  doc.to_s
585
475
  end # rest xml