ruby-jss 1.5.3 → 1.6.0b1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGES.md +25 -0
- data/THANKS.md +3 -2
- data/lib/jamf.rb +0 -1
- data/lib/jamf/api/base_classes/collection_resource.rb +5 -5
- data/lib/jamf/client.rb +3 -3
- data/lib/jamf/client/management_action.rb +2 -3
- data/lib/jamf/composer.rb +2 -2
- data/lib/jamf/utility.rb +35 -7
- data/lib/jss.rb +0 -1
- data/lib/jss/api_connection.rb +1 -0
- data/lib/jss/api_object/configuration_profile.rb +2 -2
- data/lib/jss/api_object/network_segment.rb +6 -5
- data/lib/jss/api_object/policy.rb +50 -0
- data/lib/jss/api_object/script.rb +242 -352
- data/lib/jss/api_object/user.rb +1 -1
- data/lib/jss/client/management_action.rb +1 -2
- data/lib/jss/composer.rb +2 -2
- data/lib/jss/utility.rb +116 -53
- data/lib/jss/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db33099b85c8a28905abb4885931b4782f169604fdda26458f0def90d9cec4cb
|
4
|
+
data.tar.gz: f004c3aa0aaed1934ccdf98dcce510af7f7c54e399d48692cccc6d9cffef011f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ceb6d36bade8f595556f4c6208b318187bb37f228ae183d8204190f82129c3eaeb3580cfc56277d45d16e84d6889c9220c7a6b2dc02c91c689b9246355280f1
|
7
|
+
data.tar.gz: afa31ca7c07c083b0ee1c255153cdfc02c423e72bdcb4421035b8debe87a365c232d049932441a1583671a5552d4519a1307c8f18ca8e236114a79e1d0c8f3e4
|
data/CHANGES.md
CHANGED
@@ -4,6 +4,31 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## \[1.6.0] - 2021-05-??
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
|
11
|
+
- Creating JSS::User's no longer requires a valid LDAP server. Many thanks to @aaron-mmt for filing and fixing this issue!
|
12
|
+
|
13
|
+
- HTTP 409 errors are handled more appropriately, and should report the actual error message from the server, e.g. 'Duplicate Primary MAC Address'
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- ruby-jss no longer uses the 'plist' gem due to a remote code execution security issue when using `Plist.parse_xml`. Plists are now handled by the CFPropertyList gem. The existing wrapper method `JSS.parse_plist` bas been updated to use the new gem, and a new wrapper method has been added to convert ruby data to XML plist: `JSS.xml_plist_from(data)`. All internal references to methods from the insecure 'plist' gem have been replaced with calls to those wrapper methods.
|
18
|
+
|
19
|
+
Many many thanks to actae0n of Blacksun Hackers Club for reporting this security issue and providing examples of how it could be exploited.
|
20
|
+
|
21
|
+
- In preparation for the removal of the 'runScript' command in the jamf binary, JSS::Script no longer uses it within the 'run' instance method. Instead, it just does what the jamf binary did: It creates a private temp folder, writes the script to disk in that temp folder, executes the script with any given params, then deletes the folder, returning the exit status and output from the script.
|
22
|
+
|
23
|
+
- Jamf::Script#run now takes parameters in the named params `p4:` through `p11:` for consistency with other parts of ruby-jss.
|
24
|
+
|
25
|
+
- Since Jamf Scripts can no longer be stored in a distribution point, which according to Jamf has been the case for a while, all code for dealing with them that way has been removed.
|
26
|
+
|
27
|
+
- JSS::NetworkSegment#include? now uses Range#cover? under the hood, rather than Range#include?, which can take a very very long time with large segments.
|
28
|
+
|
29
|
+
- JSS.expand_min_os has been updated to handle Apple's new version numbers for macOS. This method takes a string like '>=10.14.3' and expands it into a large array of greater OS versions and is used by the 'os_limitations' method of Packages and Scripts. For any range of versions that includes Big Sur, both '11.x.x' and '10.16' as included in the output, to catch machines that may have SYSTEM_VERSION_COMPAT set in their env.
|
30
|
+
|
31
|
+
|
7
32
|
## \[1.5.3] - 2020-12-28
|
8
33
|
|
9
34
|
### Fixed
|
data/THANKS.md
CHANGED
data/lib/jamf.rb
CHANGED
@@ -176,18 +176,18 @@ module Jamf
|
|
176
176
|
# those parameters will return the cached Array. Use `refresh: true` to
|
177
177
|
# re-request that Array from the server. Note that the cache is of the raw
|
178
178
|
# JSON Hash data. Using 'instantiate:' will still be slower as each item in
|
179
|
-
# the cache is instantiated. See 'Instantiation'
|
179
|
+
# the cache is instantiated. See 'Instantiation' above.
|
180
180
|
#
|
181
|
-
# Some other methods, e.g. .all_names, will generate or use this cached
|
182
|
-
# to derive their values.
|
181
|
+
# Some other class methods, e.g. .all_names, will generate or use this cached
|
182
|
+
# Array to derive their values.
|
183
183
|
#
|
184
184
|
# If any of the parameters paged:, sort:, or filter: are used, an API
|
185
185
|
# request is made every time, and no caches are used or stored.
|
186
186
|
#
|
187
187
|
#######
|
188
188
|
#
|
189
|
-
# @param sort [String, Array<String>] Server-side sorting criteria in the
|
190
|
-
# property:direction, where direction is 'asc' or 'desc'. Multiple
|
189
|
+
# @param sort [String, Array<String>] Server-side sorting criteria in the
|
190
|
+
# format: property:direction, where direction is 'asc' or 'desc'. Multiple
|
191
191
|
# properties are supported, either as separate strings in an Array, or
|
192
192
|
# a single string, comma separated.
|
193
193
|
#
|
data/lib/jamf/client.rb
CHANGED
@@ -179,7 +179,7 @@ module Jamf
|
|
179
179
|
#
|
180
180
|
def self.jamf_plist
|
181
181
|
return {} unless JAMF_PLIST.file?
|
182
|
-
|
182
|
+
Jamf.parse_plist JAMF_PLIST
|
183
183
|
end
|
184
184
|
|
185
185
|
# All the JAMF receipts on this client
|
@@ -232,7 +232,7 @@ module Jamf
|
|
232
232
|
#
|
233
233
|
def self.hardware_data
|
234
234
|
raw = `/usr/sbin/system_profiler SPHardwareDataType -xml 2>/dev/null`
|
235
|
-
|
235
|
+
Jamf.parse_plist(raw)[0]['_items'][0]
|
236
236
|
end
|
237
237
|
|
238
238
|
# Who's currently got an active GUI session? - might be
|
@@ -284,7 +284,7 @@ module Jamf
|
|
284
284
|
myudid = udid
|
285
285
|
nc_prefs_file = Pathname.new "#{home}/#{USER_PREFS_BYHOST_FOLDER}/com.apple.notificationcenterui.#{myudid}.plist"
|
286
286
|
return nil unless nc_prefs_file.readable?
|
287
|
-
|
287
|
+
Jamf.parse_plist(nc_prefs_file)['doNotDisturb']
|
288
288
|
end
|
289
289
|
|
290
290
|
# The home dir of the specified user, nil if
|
@@ -94,7 +94,7 @@ module JSS
|
|
94
94
|
#
|
95
95
|
def self.set_mgmt_action_ncprefs_flags(user, flags, hup: true)
|
96
96
|
plist = Pathname.new "/Users/#{user}/Library/Preferences/#{NCPREFS_DOMAIN}.plist"
|
97
|
-
prefs =
|
97
|
+
prefs = Jamf.parse_plist plist
|
98
98
|
mgmt_action_setting = prefs['apps'].select { |a| a['bundle-id'] == MGMT_ACTION_BUNDLE_ID }.first
|
99
99
|
if mgmt_action_setting
|
100
100
|
orig_flags = mgmt_action_setting['flags']
|
@@ -103,8 +103,7 @@ module JSS
|
|
103
103
|
orig_flags = flags
|
104
104
|
prefs['apps'] << { 'bundle-id' => MGMT_ACTION_BUNDLE_ID, 'flags' => flags }
|
105
105
|
end
|
106
|
-
|
107
|
-
plist.open('w') { |f| f.write prefs.to_plist }
|
106
|
+
plist.open('w') { |f| f.write Jamf.xml_plist_from(prefs) }
|
108
107
|
system HUP_NOTIF_CTR_CMD if hup
|
109
108
|
orig_flags
|
110
109
|
end
|
data/lib/jamf/composer.rb
CHANGED
@@ -126,7 +126,7 @@ module Jamf
|
|
126
126
|
###
|
127
127
|
comp_plist_out = Pathname.new "/tmp/#{PKG_BUNDLE_ID_PFX}-#{pkg_filename}.plist"
|
128
128
|
system "#{PKGBUILD} --analyze --root '#{root}' '#{comp_plist_out}'"
|
129
|
-
comp_plist =
|
129
|
+
comp_plist = Jamf.parse_plist comp_plist_out
|
130
130
|
|
131
131
|
### if the plist is empty, there are no bundles in the pkg
|
132
132
|
if comp_plist[0].nil?
|
@@ -141,7 +141,7 @@ module Jamf
|
|
141
141
|
bndl['BundleHasStrictIdentifier'] = false
|
142
142
|
end
|
143
143
|
### write out the edits
|
144
|
-
comp_plist_out.open('w') { |f| f.write comp_plist
|
144
|
+
comp_plist_out.open('w') { |f| f.write Jamf.xml_plist_from(comp_plist) }
|
145
145
|
comp_plist_arg = "--component-plist '#{comp_plist_out}'"
|
146
146
|
end
|
147
147
|
|
data/lib/jamf/utility.rb
CHANGED
@@ -187,19 +187,26 @@ module Jamf
|
|
187
187
|
{ stringform: valstr, arrayform: valarr }
|
188
188
|
end # to_s_and_a
|
189
189
|
|
190
|
-
# Parse a plist into a Ruby data structure.
|
191
|
-
#
|
192
|
-
#
|
190
|
+
# Parse a plist into a Ruby data structure. The plist parameter may be
|
191
|
+
# a String containing an XML plist, or a path to a plist file, or it may be
|
192
|
+
# a Pathname object pointing to a plist file. The plist files may be XML or
|
193
|
+
# binary.
|
193
194
|
#
|
194
195
|
# @param plist[Pathname, String] the plist XML, or the path to a plist file
|
195
196
|
#
|
197
|
+
# @param symbol_keys[Boolean] should any Hash keys in the result be converted
|
198
|
+
# into Symbols rather than remain as Strings?
|
199
|
+
#
|
196
200
|
# @return [Object] the parsed plist as a ruby hash,array, etc.
|
197
201
|
#
|
198
|
-
def self.parse_plist(plist)
|
202
|
+
def self.parse_plist(plist, symbol_keys: false)
|
203
|
+
require 'cfpropertylist'
|
204
|
+
|
199
205
|
# did we get a string of xml, or a string pathname?
|
200
206
|
case plist
|
201
207
|
when String
|
202
|
-
return
|
208
|
+
return CFPropertyList.native_types(CFPropertyList::List.new(data: plist).value, symbol_keys) if plist.include? '</plist>'
|
209
|
+
|
203
210
|
plist = Pathname.new plist
|
204
211
|
when Pathname
|
205
212
|
true
|
@@ -208,11 +215,32 @@ module Jamf
|
|
208
215
|
end # case plist
|
209
216
|
|
210
217
|
# if we're here, its a Pathname
|
211
|
-
raise
|
218
|
+
raise JSS::MissingDataError, "No such file: #{plist}" unless plist.file?
|
212
219
|
|
213
|
-
|
220
|
+
CFPropertyList.native_types(CFPropertyList::List.new(file: plist).value, symbol_keys)
|
214
221
|
end # parse_plist
|
215
222
|
|
223
|
+
# Convert any ruby data to an XML plist.
|
224
|
+
#
|
225
|
+
# NOTE: Binary data is tricky. Easiest way is to pass in a
|
226
|
+
# Pathname or IO object (anything that responds to `read` and
|
227
|
+
# returns a bytestring)
|
228
|
+
# and then the CFPropertyList.guess method will read it and
|
229
|
+
# convert it to a Plist <data> element with base64 encoded
|
230
|
+
# data.
|
231
|
+
# For more info, see CFPropertyList.guess
|
232
|
+
#
|
233
|
+
# @param data [Object] the data to be converted, usually a Hash
|
234
|
+
#
|
235
|
+
# @return [String] the object converted into an XML plist
|
236
|
+
#
|
237
|
+
def self.xml_plist_from(data)
|
238
|
+
require 'cfpropertylist'
|
239
|
+
plist = CFPropertyList::List.new
|
240
|
+
plist.value = CFPropertyList.guess(data, convert_unknown_to_string: true)
|
241
|
+
plist.to_str(CFPropertyList::List::FORMAT_XML)
|
242
|
+
end
|
243
|
+
|
216
244
|
# TODO: Sill needed in Jamf API?
|
217
245
|
#
|
218
246
|
# Converts anything that responds to #to_s to a Time, or nil
|
data/lib/jss.rb
CHANGED
data/lib/jss/api_connection.rb
CHANGED
@@ -922,6 +922,7 @@ module JSS
|
|
922
922
|
when 409
|
923
923
|
err = JSS::ConflictError
|
924
924
|
@last_http_response.body =~ /<p>(The server has not .*?)(<|$)/m
|
925
|
+
Regexp.last_match(1) || @last_http_response.body =~ %r{<p>Error: (.*?)</p>}
|
925
926
|
msg = Regexp.last_match(1)
|
926
927
|
when 400
|
927
928
|
err = JSS::BadRequestError
|
@@ -123,7 +123,7 @@ module JSS
|
|
123
123
|
#
|
124
124
|
# @return [Hash] the parsed payloads plist.
|
125
125
|
def parsed_payloads
|
126
|
-
|
126
|
+
JSS.parse_plist @payloads
|
127
127
|
end
|
128
128
|
|
129
129
|
# @return [Array<Hash>] the individual payloads from the payload Plist
|
@@ -151,7 +151,7 @@ module JSS
|
|
151
151
|
def payload_content=(new_content)
|
152
152
|
payload_plist_data = parsed_payloads
|
153
153
|
payload_plist_data['PayloadContent'] = new_content
|
154
|
-
@payloads =
|
154
|
+
@payloads = JSS.xml_plist_from new_content
|
155
155
|
@need_to_update = true
|
156
156
|
@update_payloads = true
|
157
157
|
end
|
@@ -435,9 +435,10 @@ module JSS
|
|
435
435
|
@starting_address <= thing.range.begin && @ending_address >= thing.range.end
|
436
436
|
else
|
437
437
|
thing = IPAddr.new thing.to_s
|
438
|
-
range.
|
438
|
+
range.cover? thing
|
439
439
|
end
|
440
440
|
end
|
441
|
+
alias cover? include?
|
441
442
|
|
442
443
|
### Does this network segment equal another?
|
443
444
|
### equality means the ranges are equal
|
@@ -459,7 +460,7 @@ module JSS
|
|
459
460
|
### @return [void]
|
460
461
|
###
|
461
462
|
def building=(newval)
|
462
|
-
new =
|
463
|
+
new =
|
463
464
|
if newval.to_s.empty?
|
464
465
|
JSS::BLANK
|
465
466
|
else
|
@@ -546,7 +547,7 @@ module JSS
|
|
546
547
|
### @return [void]
|
547
548
|
###
|
548
549
|
def netboot_server=(newval)
|
549
|
-
new =
|
550
|
+
new =
|
550
551
|
if newval.to_s.empty?
|
551
552
|
JSS::BLANK
|
552
553
|
else
|
@@ -555,7 +556,7 @@ module JSS
|
|
555
556
|
|
556
557
|
JSS::NetbootServer.map_all_ids_to(:name)[id]
|
557
558
|
end
|
558
|
-
|
559
|
+
|
559
560
|
@netboot_server = new
|
560
561
|
@need_to_update = true
|
561
562
|
end
|
@@ -567,7 +568,7 @@ module JSS
|
|
567
568
|
### @return [void]
|
568
569
|
###
|
569
570
|
def swu_server=(newval)
|
570
|
-
new =
|
571
|
+
new =
|
571
572
|
if newval.to_s.empty?
|
572
573
|
JSS::BLANK
|
573
574
|
else
|
@@ -287,6 +287,9 @@ module JSS
|
|
287
287
|
# How is the category stored in the API data?
|
288
288
|
CATEGORY_DATA_TYPE = Hash
|
289
289
|
|
290
|
+
# All valid script parameters
|
291
|
+
SCRIPT_PARAMETERS_AVAILABLE = %i[parameter4 parameter5 parameter6 parameter7 parameter8 parameter9 parameter10 parameter11].freeze
|
292
|
+
|
290
293
|
# Class Methods
|
291
294
|
######################
|
292
295
|
|
@@ -1485,6 +1488,53 @@ module JSS
|
|
1485
1488
|
removed
|
1486
1489
|
end
|
1487
1490
|
|
1491
|
+
# Set a script parameter
|
1492
|
+
#
|
1493
|
+
# @param identifier [Integer,String] identifier the id or name of a script in this policy
|
1494
|
+
#
|
1495
|
+
# @param opts [Hash] opts the options to alter for this script
|
1496
|
+
#
|
1497
|
+
# @option [String] parameter4: the value of the 4th parameter passed to the script. this
|
1498
|
+
# overrides the same parameter in the script object itself.
|
1499
|
+
#
|
1500
|
+
# @option [String] parameter5: the value of the 5th parameter passed to the script. this
|
1501
|
+
# overrides the same parameter in the script object itself.
|
1502
|
+
#
|
1503
|
+
# @option [String] parameter6: the value of the 6th parameter passed to the script. this
|
1504
|
+
# overrides the same parameter in the script object itself.
|
1505
|
+
#
|
1506
|
+
# @option [String] parameter7: the value of the 7th parameter passed to the script. this
|
1507
|
+
# overrides the same parameter in the script object itself.
|
1508
|
+
#
|
1509
|
+
# @option [String] parameter8: the value of the 8th parameter passed to the script. this
|
1510
|
+
# overrides the same parameter in the script object itself.
|
1511
|
+
#
|
1512
|
+
# @option [String] parameter9: the value of the 9th parameter passed to the script. this
|
1513
|
+
# overrides the same parameter in the script object itself.
|
1514
|
+
#
|
1515
|
+
# @option [String] parameter10: the value of the 10th parameter passed to the script. this
|
1516
|
+
# overrides the same parameter in the script object itself.
|
1517
|
+
#
|
1518
|
+
# @option [String] parameter11: the value of the 11th parameter passed to the script. this
|
1519
|
+
# overrides the same parameter in the script object itself.
|
1520
|
+
#
|
1521
|
+
# @return [Array] the scripts array
|
1522
|
+
#
|
1523
|
+
def set_script_parameters(identifier, **opts)
|
1524
|
+
id = JSS::Script.valid_id identifier, api: @api
|
1525
|
+
raise JSS::NoSuchItemError, "No script matches '#{identifier}'" unless id
|
1526
|
+
|
1527
|
+
script_data = @scripts.select { |s| s[:id] == id }[0]
|
1528
|
+
raise JSS::InvalidDataError, "Script #{id} is not configured. Use add_script method." unless script_data
|
1529
|
+
|
1530
|
+
opts.each do |parameter, value|
|
1531
|
+
script_data[parameter] = value if SCRIPT_PARAMETERS_AVAILABLE.include? parameter
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
@need_to_update = true
|
1535
|
+
@scripts
|
1536
|
+
end # end set_script_parameter
|
1537
|
+
|
1488
1538
|
###### Directory Bindings
|
1489
1539
|
|
1490
1540
|
# @return [Array] the id's of the directory_bindings handled by the policy
|
@@ -1,94 +1,91 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
29
|
+
# Module Constants
|
30
30
|
#####################################
|
31
31
|
|
32
|
-
|
32
|
+
# Module Variables
|
33
33
|
#####################################
|
34
34
|
|
35
|
-
|
35
|
+
# Module Methods
|
36
36
|
#####################################
|
37
37
|
|
38
|
-
|
38
|
+
# Classes
|
39
39
|
#####################################
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
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
|
-
|
63
|
+
# Class Methods
|
67
64
|
#####################################
|
68
65
|
|
69
|
-
|
66
|
+
# Class Constants
|
70
67
|
#####################################
|
71
68
|
|
72
|
-
|
69
|
+
# The base for REST resources of this class
|
73
70
|
RSRC_BASE = 'scripts'.freeze
|
74
71
|
|
75
|
-
|
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
|
-
|
79
|
-
|
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
|
-
|
79
|
+
# The script storage folder on the distribution point, if used
|
83
80
|
DIST_POINT_SCRIPTS_FOLDER = 'Scripts'.freeze
|
84
81
|
|
85
|
-
|
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
|
-
|
85
|
+
# which is default?
|
89
86
|
DEFAULT_PRIORITY = 'After'.freeze
|
90
87
|
|
91
|
-
|
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
|
-
|
103
|
+
# Attributes
|
107
104
|
#####################################
|
108
105
|
|
109
|
-
|
106
|
+
# @return [String] the file name of the script, if stored in a dist. point
|
110
107
|
attr_reader :filename
|
111
108
|
|
112
|
-
|
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
|
-
|
112
|
+
# @return [String] either 'Before' or 'After' or "At Reboot".
|
116
113
|
attr_reader :priority
|
117
114
|
|
118
|
-
|
115
|
+
# @return [String] the info field for this script
|
119
116
|
attr_reader :info
|
120
117
|
|
121
|
-
|
118
|
+
# @return [String] the notes field for this script
|
122
119
|
attr_reader :notes
|
123
120
|
|
124
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
217
|
+
# nil should be an empty array
|
212
218
|
new_val = [] if new_val.to_s.empty?
|
213
219
|
|
214
|
-
|
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
|
-
|
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
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
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
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
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
|
-
|
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
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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
|
-
|
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
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
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
|
-
|
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
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
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
|
-
|
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
|
-
|
481
|
-
|
482
|
-
|
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
|
-
|
521
|
-
|
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
|
-
|
524
|
-
|
405
|
+
# everything must be a string
|
406
|
+
params.map! &:to_s
|
525
407
|
|
526
|
-
|
527
|
-
|
408
|
+
# remove nils
|
409
|
+
params.compact!
|
528
410
|
|
529
|
-
|
411
|
+
# remove empty strings
|
412
|
+
params.delete_if &:empty?
|
530
413
|
|
531
|
-
|
414
|
+
return_value = []
|
532
415
|
|
533
|
-
|
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
|
-
|
425
|
+
cmd = [executable.to_s]
|
426
|
+
cmd += params
|
536
427
|
|
537
|
-
|
428
|
+
stdout_and_stderr_str, status = Open3.capture2e(*cmd)
|
538
429
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
end # begin/ensure
|
430
|
+
return_value << status.exitstatus
|
431
|
+
return_value << stdout_and_stderr_str
|
432
|
+
end # Dir.mktmpdirs
|
543
433
|
|
544
|
-
|
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
|
-
|
445
|
+
# Private Instance Methods
|
556
446
|
#####################################
|
557
447
|
|
558
448
|
private
|
559
449
|
|
560
|
-
|
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 =
|
472
|
+
scpt.add_element('script_contents_encoded').text = script_contents_encoded
|
583
473
|
|
584
474
|
doc.to_s
|
585
475
|
end # rest xml
|