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
@@ -849,11 +849,7 @@ module JSS
849
849
  raise ArgumentError, 'Missing searchterm or fetch key'
850
850
  end
851
851
 
852
- begin
853
- return new fetch_rsrc: fetch_rsrc, api: api
854
- rescue RestClient::NotFound
855
- raise JSS::NoSuchItemError, "No #{self::RSRC_OBJECT_KEY} found #{err_detail}" unless fetch_rsrc
856
- end
852
+ new fetch_rsrc: fetch_rsrc, api: api
857
853
  end # fetch
858
854
 
859
855
  # Fetch the mostly- or fully-raw JSON or XML data for an object of this
@@ -895,8 +891,6 @@ module JSS
895
891
  return data if format == :json || as_string
896
892
 
897
893
  REXML::Document.new(data)
898
- rescue RestClient::NotFound
899
- raise JSS::NoSuchItemError, "No #{self} with id #{id}"
900
894
  end
901
895
 
902
896
  # PUT some raw XML to the API for a given id in this subclass.
@@ -925,8 +919,6 @@ module JSS
925
919
  validate_not_metaclass(self)
926
920
  rsrc = "#{self::RSRC_BASE}/id/#{id}"
927
921
  REXML::Document.new(api.put_rsrc rsrc, xml.to_s)
928
- rescue RestClient::NotFound
929
- raise JSS::NoSuchItemError, "No #{self} with id #{id}"
930
922
  end
931
923
 
932
924
  # POST some raw XML to the API for a given id in this subclass.
@@ -1223,14 +1215,8 @@ module JSS
1223
1215
  #
1224
1216
  def delete
1225
1217
  return unless @in_jss
1226
- begin
1227
- @api.delete_rsrc @rest_rsrc
1228
- rescue RestClient::NotFound, RestClient::ResourceNotFound
1229
- # over slow connections (?) or more likely
1230
- # split-tunnel VPN connections, sometimes the thing gets deleted
1231
- # the call gets a 404 anyway
1232
- nil
1233
- end
1218
+
1219
+ @api.delete_rsrc @rest_rsrc
1234
1220
 
1235
1221
  @rest_rsrc = "#{self.class::RSRC_BASE}/name/#{CGI.escape @name.to_s}"
1236
1222
  @id = nil
@@ -1433,8 +1419,6 @@ module JSS
1433
1419
  end
1434
1420
 
1435
1421
  raw_json[args[:rsrc_object_key]]
1436
- rescue RestClient::ResourceNotFound
1437
- raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found matching resource #{rsrc}"
1438
1422
  end
1439
1423
 
1440
1424
  # Start examining the @init_data recieved from the API
@@ -198,7 +198,7 @@ module JSS
198
198
 
199
199
  if cat.is_a? String
200
200
  @category_name = cat
201
- @category_id = JSS::Category.category_id_from_name @category_name
201
+ @category_id = JSS::Category.category_id_from_name @category_name, api: @api
202
202
  else
203
203
  @category_name = cat[:name]
204
204
  @category_id = cat[:id]
@@ -1046,6 +1046,19 @@ module JSS
1046
1046
  @need_to_update = true
1047
1047
  end
1048
1048
 
1049
+ # flush the logs for this computer in a given policy
1050
+ # @see JSS::Policy.flush_logs
1051
+ #
1052
+ def flush_policy_logs(policy, older_than: 0, period: :days)
1053
+ JSS::Policy.flush_logs(
1054
+ policy,
1055
+ older_than: older_than,
1056
+ period: period,
1057
+ computers: [@id],
1058
+ api: @api
1059
+ )
1060
+ end
1061
+
1049
1062
  def barcode1=(new_val)
1050
1063
  new_val = new_val.strip
1051
1064
  return nil if @barcode1 == new_val
@@ -23,7 +23,6 @@
23
23
  #
24
24
  #
25
25
 
26
- #
27
26
  module JSS
28
27
 
29
28
  # Classes
@@ -56,6 +55,11 @@ module JSS
56
55
  # which DISTRIBUTION_METHODS means we're in self service?
57
56
  SELF_SERVICE_DIST_METHOD = 'Make Available in Self Service'.freeze
58
57
 
58
+ # when a change is made, which in-scope machines should get
59
+ # the changed profile?
60
+ REDEPLOY_NEWLY_ASSIGNED = 'Newly Assigned'.freeze
61
+ REDEPLOY_ALL = 'All'.freeze
62
+
59
63
  # Our SelfService deploys profiles
60
64
  SELF_SERVICE_PAYLOAD = :profile
61
65
 
@@ -68,7 +72,6 @@ module JSS
68
72
  # How is the category stored in the API data?
69
73
  CATEGORY_DATA_TYPE = Hash
70
74
 
71
-
72
75
  # Attributes
73
76
  ###################################
74
77
 
@@ -78,7 +81,11 @@ module JSS
78
81
  # @return [String] the uuid of this profile. NOT Updatable
79
82
  attr_reader :uuid
80
83
 
81
- # @return [Boolean] Should this profile be redeployed when an inventory update happens?
84
+ # @return [String] When a change is made to the profile, which scoped machines
85
+ # should get the changes? This will always contain REDEPLOY_NEWLY_ASSIGNED
86
+ # when fetched, but can be set to REDEPLOY_ALL via the redeploy_to_all:
87
+ # parameter to #update & #save. After the update is complete, it reverts
88
+ # to REDEPLOY_NEWLY_ASSIGNED
82
89
  attr_reader :redeploy_on_update
83
90
 
84
91
  # @return [String] the plist containing the payloads for this profile. NOT Updatable
@@ -116,7 +123,7 @@ module JSS
116
123
  #
117
124
  # @return [Hash] the parsed payloads plist.
118
125
  def parsed_payloads
119
- Plist.parse_xml @payloads
126
+ JSS.parse_plist @payloads
120
127
  end
121
128
 
122
129
  # @return [Array<Hash>] the individual payloads from the payload Plist
@@ -125,12 +132,58 @@ module JSS
125
132
  parsed_payloads['PayloadContent']
126
133
  end
127
134
 
135
+ # @param new_content [Array<Hash>] replace the payload content entirely.
136
+ #
137
+ # The 'payload' of a config profile is an XML Plist. The top-level key
138
+ # of that plist 'PayloadContent' contains an Array of Dicts, each one being
139
+ # a part of the payload for the profile.
140
+ #
141
+ # When replacing the PayloadContent Array, using this method, provide a
142
+ # *ruby* Array full of *ruby* hashes, and they will be converted to a
143
+ # Plist and embedded into the API XML appropriately.
144
+ #
145
+ # WARNING: This is experimental! Editing the Plist Payload of a Config
146
+ # profile may break the profile. Make sure you test on a fake profile
147
+ # before using this method in production.
148
+ #
149
+ # @return [void]
150
+ #
151
+ def payload_content=(new_content)
152
+ payload_plist_data = parsed_payloads
153
+ payload_plist_data['PayloadContent'] = new_content
154
+ @payloads = JSS.xml_plist_from new_content
155
+ @need_to_update = true
156
+ @update_payloads = true
157
+ end
158
+
128
159
  # @return [Array<String>] the PayloadType of each payload (e.g. com.apple.caldav.account)
129
160
  #
130
161
  def payload_types
131
162
  payload_content.map { |p| p['PayloadType'] }
132
163
  end
133
164
 
165
+ # clear flag after updating
166
+ def update(redeploy_to_all: false)
167
+ @redeploy_on_update = redeploy_to_all ? REDEPLOY_ALL : REDEPLOY_NEWLY_ASSIGNED
168
+ super()
169
+ # always reset to newly assigned
170
+ @redeploy_on_update = REDEPLOY_NEWLY_ASSIGNED
171
+ @update_payloads = nil
172
+ end
173
+
174
+ # wrapper with param
175
+ def save(redeploy_to_all: false)
176
+ if @in_jss
177
+ raise JSS::UnsupportedError, 'Updating this object in the JSS is currently not supported by ruby-jss' unless updatable?
178
+
179
+ update redeploy_to_all: redeploy_to_all
180
+ else
181
+ raise JSS::UnsupportedError, 'Creating this object in the JSS is currently not supported by ruby-jss' unless creatable?
182
+
183
+ create
184
+ end
185
+ end
186
+
134
187
  # Private Instance Methods
135
188
  ###################################
136
189
  private
@@ -142,7 +195,10 @@ module JSS
142
195
  gen = obj.add_element('general')
143
196
  gen.add_element('description').text = @description
144
197
  gen.add_element('redeploy_on_update').text = @redeploy_on_update
145
-
198
+ if @update_payloads
199
+ payloads_plist_xml = JSS.escape_xml(@payloads.gsub(/^\t*/, '').gsub(">\n", '>'))
200
+ gen.add_element('payloads').text = payloads_plist_xml
201
+ end
146
202
  obj << @scope.scope_xml
147
203
  add_self_service_xml doc
148
204
  add_category_to_xml doc
@@ -25,66 +25,72 @@
25
25
 
26
26
  module JSS
27
27
 
28
- # Module for containing the different types of DirectoryBindings stored within the JSS
29
- module DirectoryBindingType
30
-
31
- # Module Variables
32
- #####################################
33
-
34
- # Module Methods
35
- #####################################
36
- def should_update
37
- @need_to_update = true
38
- end
39
-
40
- def set_type_settings(settings)
41
- @type_settings = settings
42
- @type_settings.container = self
43
- end
44
-
45
- # Classes
46
- #####################################
47
-
48
- # A generic binding type class that sets common variables, methods, and constructors
49
- # for all the different directory binding types.
50
- #
51
- # @author Tyler Morgan
52
- class DirectoryBindingType
53
- # Mix-Ins
54
- #####################################
55
-
56
- # Class Methods
57
- #####################################
58
-
59
- # Class Constants
60
- #####################################
61
-
62
- # The different network protocols supported.
63
- NETWORK_PROTOCOL = {
64
- afp: "AFP",
65
- smb: "SMB"
66
- }.freeze
67
-
68
-
69
- # The different home folder types.
70
- HOME_FOLDER_TYPE = {
71
- network: "Network",
72
- local: "Local",
73
- either: "Either",
74
- mobile: "Mobile"
75
- }.freeze
76
-
77
- # Attributes
78
- #####################################
79
-
80
- # This is used to properly handle updating the containing object.
81
- attr_accessor :container
82
- end
28
+ # Module for containing the different types of DirectoryBindings stored within the JSS
29
+ module DirectoryBindingType
30
+
31
+ # Module Variables
32
+ #####################################
33
+
34
+ # Module Methods
35
+ #####################################
36
+ def should_update
37
+ @need_to_update = true
38
+ end
39
+
40
+ def set_type_settings(settings)
41
+ @type_settings = settings
42
+ @type_settings.container = self
43
+ end
44
+
45
+ # Classes
46
+ #####################################
47
+
48
+ # A generic binding type class that sets common variables, methods, and constructors
49
+ # for all the different directory binding types.
50
+ #
51
+ # @author Tyler Morgan
52
+ class DirectoryBindingType
53
+
54
+
55
+ # Mix-Ins
56
+ #####################################
57
+
58
+ # Class Methods
59
+ #####################################
60
+
61
+ # Class Constants
62
+ #####################################
63
+
64
+ # The different network protocols supported.
65
+ NETWORK_PROTOCOL = {
66
+ afp: 'AFP',
67
+ smb: 'SMB'
68
+ }.freeze
69
+
70
+ # The different home folder types.
71
+ HOME_FOLDER_TYPE = {
72
+ network: 'Network',
73
+ local: 'Local',
74
+ either: 'Either',
75
+ mobile: 'Mobile'
76
+ }.freeze
77
+
78
+ # Attributes
79
+ #####################################
80
+
81
+ # This is used to properly handle updating the containing object.
82
+ attr_accessor :container
83
+
84
+
85
+ end
86
+
87
+
83
88
  end
89
+
84
90
  end
85
91
 
86
- require "jss/api_object/directory_binding_type/active_directory"
87
- require "jss/api_object/directory_binding_type/open_directory"
88
- require "jss/api_object/directory_binding_type/admitmac"
89
- require "jss/api_object/directory_binding_type/centrify"
90
- require "jss/api_object/directory_binding_type/powerbroker_identity_services"
92
+ require 'jss/api_object/directory_binding_type/active_directory'
93
+ require 'jss/api_object/directory_binding_type/open_directory'
94
+ require 'jss/api_object/directory_binding_type/admitmac'
95
+ require 'jss/api_object/directory_binding_type/centrify'
96
+ require 'jss/api_object/directory_binding_type/powerbroker_identity_services'
@@ -259,11 +259,17 @@ module JSS
259
259
  # @return [void]
260
260
  def default_shell=(newvalue)
261
261
 
262
- # Data Check
263
- raise JSS::InvalidDataError, "default_shell must be a string." unless newvalue.is_a? String
262
+ new =
263
+ if newvalue.to_s.empty?
264
+ JSS::BLANK
265
+ else
266
+ # Data Check
267
+ raise JSS::InvalidDataError, "default_shell must be a string." unless newvalue.is_a? String
268
+ newvalue
269
+ end
264
270
 
265
271
  # Update Value
266
- @default_shell = newvalue
272
+ @default_shell = new
267
273
 
268
274
  # Set the object to needing to be updated.
269
275
  self.container&.should_update
@@ -280,12 +286,17 @@ module JSS
280
286
  #
281
287
  # @return [void]
282
288
  def uid=(newvalue)
283
-
284
- # Data Check
285
- raise JSS::InvalidDataError, "uid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
289
+ new =
290
+ if newvalue.to_s.empty?
291
+ JSS::BLANK
292
+ else
293
+ # Data Check
294
+ raise JSS::InvalidDataError, "uid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
295
+ newvalue
296
+ end
286
297
 
287
298
  # Update Value
288
- @uid = newvalue
299
+ @uid = new
289
300
 
290
301
  # Set the object to needing to be updated.
291
302
  self.container&.should_update
@@ -302,12 +313,17 @@ module JSS
302
313
  #
303
314
  # @return [void]
304
315
  def forest=(newvalue)
305
-
306
- # Data Check
307
- raise JSS::InvalidDataError, "forest must be a string." unless newvalue.is_a? String
308
-
316
+ new =
317
+ if newvalue.to_s.empty?
318
+ JSS::BLANK
319
+ else
320
+ # Data Check
321
+ raise JSS::InvalidDataError, "forest must be a string." unless newvalue.is_a? String
322
+ newvalue
323
+ end
324
+
309
325
  # Update Value
310
- @forest = newvalue
326
+ @forest = new
311
327
 
312
328
  # Set the object to needing to be updated.
313
329
  self.container&.should_update
@@ -323,12 +339,17 @@ module JSS
323
339
  #
324
340
  # @return [void]
325
341
  def user_gid=(newvalue)
326
-
327
- # Data Check
328
- raise JSS::InvalidDataError, "user_gid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
342
+ new =
343
+ if newvalue.to_s.empty?
344
+ JSS::BLANK
345
+ else
346
+ # Data Check
347
+ raise JSS::InvalidDataError, "user_gid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
348
+ newvalue
349
+ end
329
350
 
330
351
  # Update Value
331
- @user_gid = newvalue
352
+ @user_gid = new
332
353
 
333
354
  # Set the object to needing to be updated.
334
355
  self.container&.should_update
@@ -345,12 +366,17 @@ module JSS
345
366
  #
346
367
  # @return [void]
347
368
  def gid=(newvalue)
348
-
349
- # Data Check
350
- raise JSS::InvalidDataError, "gid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
351
-
369
+ new =
370
+ if newvalue.to_s.empty?
371
+ JSS::BLANK
372
+ else
373
+ # Data Check
374
+ raise JSS::InvalidDataError, "gid must be either an integer or a string." unless (newvalue.is_a? Integer || newvalue.is_a?(String))
375
+ newvalue
376
+ end
377
+
352
378
  # Update Value
353
- @gid = newvalue
379
+ @gid = new
354
380
 
355
381
  # Set the object to needing to be updated.
356
382
  self.container&.should_update
@@ -389,12 +415,17 @@ module JSS
389
415
  #
390
416
  # @return [void]
391
417
  def preferred_domain=(newvalue)
392
-
393
- # Data Check
394
- raise JSS::InvalidDataError, "preferred_domain must be a string." unless newvalue.is_a? String
418
+ new =
419
+ if newvalue.to_s.empty?
420
+ JSS::BLANK
421
+ else
422
+ # Data Check
423
+ raise JSS::InvalidDataError, "preferred_domain must be a string." unless newvalue.is_a? String
424
+ newvalue
425
+ end
395
426
 
396
427
  # Update Value
397
- @preferred_domain = newvalue
428
+ @preferred_domain = new
398
429
 
399
430
  # Set the object to needing to be updated.
400
431
  self.container&.should_update
@@ -411,16 +442,22 @@ module JSS
411
442
  #
412
443
  # @return [void]
413
444
  def admin_groups=(newvalue)
414
-
415
- # Data Check
416
- raise JSS::InvalidDataError, "admin_groups must be either a string or an array of strings." unless (newvalue.is_a? String || newvalue.is_a?(Array))
417
-
445
+ new =
446
+ if newvalue.to_s.empty?
447
+ JSS::BLANK
448
+ else
449
+ # Data Check
450
+ raise JSS::InvalidDataError, "admin_groups must be either a string or an array of strings." unless (newvalue.is_a? String || newvalue.is_a?(Array))
451
+
452
+ if newvalue.is_a? Array
453
+ newvalue.join ","
454
+ else
455
+ newvalue
456
+ end
457
+ end
458
+
418
459
  # Update Value
419
- if newvalue.is_a? Array
420
- @admin_groups = newvalue.join ","
421
- else
422
- @admin_groups = newvalue
423
- end
460
+ @admin_groups = new
424
461
 
425
462
  # Set the object to needing to be updated.
426
463
  self.container&.should_update