ruby-jss 1.4.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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