nexpose_sccm 0.4.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.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/MIT-LICENSE +21 -0
- data/README.md +212 -0
- data/bin/encrypt_settings.rb +135 -0
- data/bin/nexpose_sccm +69 -0
- data/bin/vuln_ids.csv +7 -0
- data/conf/logging.yml +8 -0
- data/conf/nexpose.yml +8 -0
- data/conf/postgres.yml +8 -0
- data/conf/queries.yml +87 -0
- data/conf/sccm.yml +30 -0
- data/conf/secret.yml +4 -0
- data/lib/nexpose_sccm.rb +294 -0
- data/lib/nexpose_sccm/collection.rb +42 -0
- data/lib/nexpose_sccm/connection.rb +165 -0
- data/lib/nexpose_sccm/data_source.rb +67 -0
- data/lib/nexpose_sccm/deployment_package.rb +37 -0
- data/lib/nexpose_sccm/device.rb +11 -0
- data/lib/nexpose_sccm/helpers/nexpose_helper.rb +65 -0
- data/lib/nexpose_sccm/helpers/pg_helper.rb +26 -0
- data/lib/nexpose_sccm/powershell.rb +111 -0
- data/lib/nexpose_sccm/remediation_item.rb +5 -0
- data/lib/nexpose_sccm/software_update_group.rb +54 -0
- data/lib/nexpose_sccm/utilities/nx_logger.rb +171 -0
- data/lib/nexpose_sccm/utilities/utility_config.rb +59 -0
- data/lib/nexpose_sccm/version.rb +5 -0
- data/lib/nexpose_sccm/wql.rb +35 -0
- data/nexpose_sccm.gemspec +35 -0
- metadata +128 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module NexposeSCCM
|
2
|
+
class Collection
|
3
|
+
attr_reader :name, :collection_id, :member_count
|
4
|
+
attr_accessor :current_members, :members
|
5
|
+
|
6
|
+
def initialize(name, collection_id=nil, member_count=0)
|
7
|
+
@name = name
|
8
|
+
@collection_id = collection_id
|
9
|
+
@member_count = member_count
|
10
|
+
@current_members = Set.new
|
11
|
+
@members = Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def save(conn)
|
15
|
+
if @collection_id.nil?
|
16
|
+
NexposeSCCM.logger.info("Creating collection #{@name} prior to populating")
|
17
|
+
Powershell.run(conn.conn, :create_collection, conn.location, @name)
|
18
|
+
|
19
|
+
@collection_id = conn.get_collection_id_by_name(@name)
|
20
|
+
end
|
21
|
+
|
22
|
+
#Devices to be added
|
23
|
+
NexposeSCCM.logger.debug("Adding #{(@members - @current_members).length} devices to #{@name} collection")
|
24
|
+
(@members - @current_members).each do |member|
|
25
|
+
Powershell.run(conn.conn,
|
26
|
+
:add_device_to_collection,
|
27
|
+
conn.location,
|
28
|
+
@collection_id,
|
29
|
+
member.resource_id)
|
30
|
+
end
|
31
|
+
#Devices to be removed
|
32
|
+
NexposeSCCM.logger.debug("Removing #{(@current_members - @members).length} devices from #{@name} collection")
|
33
|
+
(@current_members - @members).each do |member|
|
34
|
+
Powershell.run(conn.conn,
|
35
|
+
:remove_device_from_collection,
|
36
|
+
conn.location,
|
37
|
+
@collection_id,
|
38
|
+
member.resource_id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'winrm'
|
2
|
+
require_relative 'collection'
|
3
|
+
require_relative 'device'
|
4
|
+
require_relative 'powershell'
|
5
|
+
require_relative 'software_update_group'
|
6
|
+
require_relative 'wql'
|
7
|
+
|
8
|
+
module NexposeSCCM
|
9
|
+
# Connection object to interact with SCCM and SCCM utilities
|
10
|
+
#
|
11
|
+
# * *Args* :
|
12
|
+
# - +protocol+ - A String identifying HTTP or HTTPS for the SCCM web service
|
13
|
+
# - +host+ - A String identifying the target host SCCM is running on
|
14
|
+
# - +port+ - A String identifying port for the SCCM web service
|
15
|
+
# - +path+ - A String identifying the URL path for the SCCM web service
|
16
|
+
# - +location+ - A String identifying the SCCM location for running PS commands on filesystem
|
17
|
+
# - +user+ - A String identifying username for the SCCM web service
|
18
|
+
# - +pass+ - A String identifying the password for the SCCM web service
|
19
|
+
# - +namespace+ - A String identifying the namespace for the SCCM server
|
20
|
+
# - +staging+ - A String identifying the directory to keep downloaded content updates for SCCM
|
21
|
+
#
|
22
|
+
class Connection
|
23
|
+
attr_reader :conn, :host, :namespace, :location, :staging
|
24
|
+
|
25
|
+
def initialize(protocol='http', host='localhost', port=5985, path='wsman', location=nil, user=nil, pass=nil,
|
26
|
+
namespace=nil, staging=nil, no_ssl_peer_verification=false, ssl_peer_fingerprint=nil)
|
27
|
+
@endpoint = "#{protocol}://#{host}:#{port}/#{path}"
|
28
|
+
@user = user
|
29
|
+
@password = pass
|
30
|
+
@namespace = namespace
|
31
|
+
@host = host
|
32
|
+
@location = location
|
33
|
+
@staging = staging.nil? ? nil : staging.chomp("\\")
|
34
|
+
@no_ssl_peer_verification = no_ssl_peer_verification
|
35
|
+
@ssl_peer_fingerprint = ssl_peer_fingerprint
|
36
|
+
end
|
37
|
+
|
38
|
+
def login
|
39
|
+
NexposeSCCM.logger.info("Logging into SCCM via WINRM: #{@endpoint}")
|
40
|
+
@conn = WinRM::Connection.new(endpoint: @endpoint,
|
41
|
+
user: @user,
|
42
|
+
password: @password,
|
43
|
+
no_ssl_peer_verification: @no_ssl_peer_verification,
|
44
|
+
ssl_peer_fingerprint: @ssl_peer_fingerprint)
|
45
|
+
#get_info
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_info
|
49
|
+
begin
|
50
|
+
results = Powershell.run(@conn, :get_sccm_info)
|
51
|
+
info_match = ['Version','Full Version','CU Level']
|
52
|
+
results.each do |result|
|
53
|
+
if info_match.any?{|word| result.include?(word)}
|
54
|
+
NexposeSCCM.logger.info("SCCM #{result.strip.gsub(/\s+/, ' ')}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
rescue Exception=>e
|
58
|
+
NexposeSCCM.logger.error("Unable to retrieve SCCM version details: #{e}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_ci_id(ldn)
|
63
|
+
NexposeSCCM.logger.debug("Getting CI IDs for solution: #{ldn}")
|
64
|
+
ci_ids = []
|
65
|
+
results = Wql.run(@conn, @namespace, :get_ci_ids, ldn)
|
66
|
+
results.each do |r|
|
67
|
+
ci_ids.push(r[:ci_id]) unless ci_ids.include?(r[:ci_id])
|
68
|
+
end
|
69
|
+
ci_ids
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_software_update_groups
|
73
|
+
NexposeSCCM.logger.debug('Getting names and CI IDs for all Rapid7 Software Update Groups')
|
74
|
+
groups = []
|
75
|
+
results = Wql.run(@conn, @namespace, :get_sups)
|
76
|
+
results = results.map {|r| {:ci_id => r[:ci_id], :name => r[:localized_display_name], :description => r[:localized_description]}}
|
77
|
+
results.each do |r|
|
78
|
+
sup = SoftwareUpdateGroup.new(r[:name], r[:description], nil, r[:ci_id])
|
79
|
+
groups.push(sup)
|
80
|
+
end
|
81
|
+
groups
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_collection_id_by_name(collection_name)
|
85
|
+
results = Wql.run(@conn, @namespace, :get_collection_by_name, collection_name)
|
86
|
+
|
87
|
+
collection_id = nil
|
88
|
+
results.each do |result|
|
89
|
+
collection_id = result[:collection_id]
|
90
|
+
end
|
91
|
+
collection_id
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_collections(sccm_devices)
|
95
|
+
NexposeSCCM.logger.debug('Getting name of collections for all existing Rapid7 Collections')
|
96
|
+
collections = []
|
97
|
+
results = Wql.run(@conn, @namespace, :get_collections)
|
98
|
+
results.each do |result|
|
99
|
+
NexposeSCCM.logger.debug("Getting device membership for #{result[:name]} collection")
|
100
|
+
collection = Collection.new(result[:name],result[:collection_id],result[:member_count])
|
101
|
+
|
102
|
+
collection.current_members = get_collection_devices(collection.collection_id,sccm_devices)
|
103
|
+
|
104
|
+
collections << collection
|
105
|
+
end
|
106
|
+
collections
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_collection_devices(collection_id, sccm_devices)
|
110
|
+
NexposeSCCM.logger.debug("Getting devices for collection ID: #{collection_id}")
|
111
|
+
devices = Set.new
|
112
|
+
members = Wql.run(@conn, @namespace, :get_collection_members, collection_id)
|
113
|
+
members.each do |member|
|
114
|
+
device = sccm_devices.select{|device| device.resource_id.eql?(member[:resource_id])}.first
|
115
|
+
devices.add(device) unless device.nil?
|
116
|
+
end
|
117
|
+
devices
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_devices
|
121
|
+
NexposeSCCM.logger.debug('Getting devices known to SCCM with details')
|
122
|
+
devices = []
|
123
|
+
members = Wql.run(@conn, @namespace, :get_devices)
|
124
|
+
members.each do |member|
|
125
|
+
if member[:ip_addresses].is_a?(Nori::StringWithAttributes)
|
126
|
+
ips = [member[:ip_addresses]]
|
127
|
+
else
|
128
|
+
ips = member[:ip_addresses]
|
129
|
+
end
|
130
|
+
device = Device.new(ips,member[:netbios_name],member[:resource_id])
|
131
|
+
devices << device
|
132
|
+
end
|
133
|
+
devices
|
134
|
+
end
|
135
|
+
|
136
|
+
def get_deployment_package(name)
|
137
|
+
Wql.run(@conn, @namespace, :get_deployment_package, name)
|
138
|
+
end
|
139
|
+
|
140
|
+
def download_patches(sup_name, ci_ids)
|
141
|
+
NexposeSCCM.logger.info("Downloading Software Update Patches for Deployment Packages.")
|
142
|
+
contentIds = []
|
143
|
+
## Need to get ContentID using ci_id
|
144
|
+
ci_ids.each do |c|
|
145
|
+
results = Wql.run(@conn, @namespace, :ci_to_contentid, c)
|
146
|
+
results.each do |r|
|
147
|
+
contentIds.push(r[:content_id]) unless contentIds.include?(r[:content_id])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
## Need to get content info using ContentId
|
151
|
+
contentIds.each do |c|
|
152
|
+
NexposeSCCM.logger.debug("Working on Content Update: #{c}")
|
153
|
+
results = Wql.run(@conn, @namespace, :get_update_url, c)
|
154
|
+
results.each do |r|
|
155
|
+
res = Powershell.run(@conn, :download_content, r[:source_url], "#{@staging}\\#{sup_name}", c, r[:file_name])
|
156
|
+
if res
|
157
|
+
NexposeSCCM.logger.debug("Successfully downloaded content update: #{c}")
|
158
|
+
else
|
159
|
+
NexposeSCCM.logger.error("There was an error downloading content update: #{c}")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module NexposeSCCM
|
2
|
+
module DataSource
|
3
|
+
# Connection object to interact with SCCM and SCCM utilities
|
4
|
+
#
|
5
|
+
# * *Args* :
|
6
|
+
# - +data_source+ - A String identifying 'nsc' or 'dwh' for the source of Nexpose data
|
7
|
+
# - +pg+ - A Hash identifying the Postgres connection settings
|
8
|
+
# - +nx+ - A Hash identifying the Nexpose connection settings
|
9
|
+
#
|
10
|
+
class Connection
|
11
|
+
def initialize(data_source='nsc', pg=nil, nx=nil)
|
12
|
+
connection_type = data_source
|
13
|
+
|
14
|
+
if connection_type.casecmp('dwh') == 0
|
15
|
+
@connection_type = :dwh
|
16
|
+
unless pg.nil?
|
17
|
+
require_relative 'helpers/pg_helper'
|
18
|
+
@conn = Helpers::PGHelper::Connection.new(pg)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@connection_type = :nsc
|
22
|
+
unless nx.nil?
|
23
|
+
require_relative 'helpers/nexpose_helper'
|
24
|
+
@conn = Helpers::NexposeHelper::Connection.new(nx)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_data(query)
|
30
|
+
res = @conn.get_data(query)
|
31
|
+
Data.new(res, @connection_type)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Universal Data object to send back to client and makes the data source transparent
|
36
|
+
#
|
37
|
+
# * *Args* :
|
38
|
+
# - +data+ - A resultset, either using the pg_helper or nexpose_helper
|
39
|
+
# - +connection_type+ - A symbol representing whether to use postgres or nexpose
|
40
|
+
#
|
41
|
+
class Data
|
42
|
+
def initialize(data, connection_type)
|
43
|
+
@data = data
|
44
|
+
@connection_type = connection_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def each
|
48
|
+
@data.each do |p|
|
49
|
+
sym_p = p.inject({}){|res,(k,v)| res[k.to_sym] = v; res}
|
50
|
+
yield sym_p
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def length
|
55
|
+
case @connection_type
|
56
|
+
when :dwh
|
57
|
+
@data.cmd_tuples
|
58
|
+
when :nsc
|
59
|
+
@data.length
|
60
|
+
else
|
61
|
+
NexposeSCCM.logger.error("An invalid connection type made it's way in here, exiting...")
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module NexposeSCCM
|
2
|
+
class DeploymentPackage
|
3
|
+
attr_reader :name, :sug_name, :path
|
4
|
+
attr_accessor :id, :collection_name
|
5
|
+
|
6
|
+
def initialize(name,sug_name,path,id=nil,collection_name=nil,deployment_type='Available')
|
7
|
+
@name = name
|
8
|
+
@id = id
|
9
|
+
@sug_name = sug_name
|
10
|
+
@path = path
|
11
|
+
@collection_name = collection_name
|
12
|
+
@deployment_type = deployment_type
|
13
|
+
end
|
14
|
+
|
15
|
+
def save(conn)
|
16
|
+
NexposeSCCM.logger.info("Created Deployment Package: #{@name}")
|
17
|
+
NexposeSCCM.logger.debug("Deployment package has path [#{@path}]")
|
18
|
+
Powershell.run(conn.conn,
|
19
|
+
:create_deployment_package,
|
20
|
+
conn.namespace,
|
21
|
+
conn.host,
|
22
|
+
@name,
|
23
|
+
@name,
|
24
|
+
@path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def download_updates(conn)
|
28
|
+
NexposeSCCM.logger.debug("Downloading updates for #{sug_name}")
|
29
|
+
Powershell.run(conn.conn,
|
30
|
+
:download_software_updates,
|
31
|
+
conn.location,
|
32
|
+
@name,
|
33
|
+
@sug_name,
|
34
|
+
@path)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Device
|
2
|
+
attr_accessor :remediation_items
|
3
|
+
attr_reader :ip_address, :host_name, :resource_id
|
4
|
+
|
5
|
+
def initialize(ip_address, host_name, resource_id)
|
6
|
+
@ip_address = ip_address
|
7
|
+
@host_name = host_name
|
8
|
+
@resource_id = resource_id
|
9
|
+
@remediation_items = Set.new
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'nexpose'
|
2
|
+
require 'csv'
|
3
|
+
|
4
|
+
module NexposeSCCM
|
5
|
+
module DataSource
|
6
|
+
module Helpers
|
7
|
+
module NexposeHelper
|
8
|
+
class Connection
|
9
|
+
def initialize(settings)
|
10
|
+
nexpose_ip = settings[:host]
|
11
|
+
nexpose_un = settings[:user]
|
12
|
+
nexpose_pw = settings[:pass]
|
13
|
+
nexpose_pt = settings[:port]
|
14
|
+
nexpose_silo = settings[:silo]
|
15
|
+
nexpose_timeout = settings[:timeout]
|
16
|
+
@nexpose_query_timeout = settings[:query_timeout]
|
17
|
+
|
18
|
+
## New Nexpose Connection -> Requirements are Device IP, Username, Password, Port with optional Silo ID
|
19
|
+
@nsc = Nexpose::Connection.new(nexpose_ip, nexpose_un, nexpose_pw, nexpose_pt, nexpose_silo)
|
20
|
+
login(nexpose_timeout)
|
21
|
+
register_metrics(nexpose_ip, nexpose_pt, {})
|
22
|
+
end
|
23
|
+
|
24
|
+
def login(timeout=120)
|
25
|
+
@nsc.login
|
26
|
+
|
27
|
+
# Check for a valid session.
|
28
|
+
unless @nsc.session_id
|
29
|
+
NexposeSCCM.logger.error("Login Failed")
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
NexposeSCCM.logger.debug("Logging out")
|
35
|
+
@nsc.logout if @nsc.session_id
|
36
|
+
end
|
37
|
+
|
38
|
+
## Set the http read timeout.
|
39
|
+
NexposeSCCM.logger.info("Setting the web session timeout to #{timeout}")
|
40
|
+
@nsc.timeout = timeout.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_data(query)
|
44
|
+
report_config = Nexpose::AdhocReportConfig.new(nil, 'sql')
|
45
|
+
report_config.add_filter('version', '2.3.0')
|
46
|
+
report_config.add_filter('query', query)
|
47
|
+
|
48
|
+
NexposeSCCM.logger.info("Running SQL report for a list of windows vulnerabilities.")
|
49
|
+
report_output = report_config.generate(@nsc, @nexpose_query_timeout)
|
50
|
+
|
51
|
+
CSV.parse(report_output.chomp, {:headers => :first_row})
|
52
|
+
end
|
53
|
+
|
54
|
+
def register_metrics(hostname, port, payload)
|
55
|
+
NexposeSCCM.logger.debug("Sending_Stats")
|
56
|
+
NexposeSCCM.logger.on_connect(hostname,
|
57
|
+
port,
|
58
|
+
@nsc.session_id,
|
59
|
+
payload)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
module NexposeSCCM
|
4
|
+
module DataSource
|
5
|
+
module Helpers
|
6
|
+
module PGHelper
|
7
|
+
class Connection
|
8
|
+
def initialize(settings)
|
9
|
+
host = settings[:host]
|
10
|
+
port = settings[:port]
|
11
|
+
user = settings[:user]
|
12
|
+
pass = settings[:pass]
|
13
|
+
db = settings[:db]
|
14
|
+
sslmode = settings[:sslmode]
|
15
|
+
|
16
|
+
@conn = PG::Connection.open(:host => host, :dbname => db, :port => port, :user => user, :password => pass, :sslmode => sslmode)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_data(query)
|
20
|
+
@conn.exec(query)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'winrm'
|
2
|
+
|
3
|
+
module NexposeSCCM
|
4
|
+
module Powershell
|
5
|
+
|
6
|
+
@cmds = {
|
7
|
+
:get_sccm_info => <<~COMMAND,
|
8
|
+
Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\SMS\\Setup
|
9
|
+
COMMAND
|
10
|
+
:download_content => <<~COMMAND,
|
11
|
+
$url = "%s"
|
12
|
+
$content = "%s\\%s"
|
13
|
+
If(!(test-path $content))
|
14
|
+
{
|
15
|
+
New-Item -ItemType Directory -Force -Path $content
|
16
|
+
$output = "$content\\%s"
|
17
|
+
$wc = New-Object System.Net.WebClient
|
18
|
+
$wc.DownloadFile($url, $output)
|
19
|
+
}
|
20
|
+
COMMAND
|
21
|
+
:sccm_download_content => <<~COMMAND,
|
22
|
+
|
23
|
+
COMMAND
|
24
|
+
:create_software_update_group => <<~COMMAND,
|
25
|
+
$PSDefaultParameterValues =@{"get-wmiobject:namespace"="%s";"get-WMIObject:computername"="%s"}
|
26
|
+
$class = Get-WmiObject -Class SMS_CI_LocalizedProperties -list
|
27
|
+
$LocalizedProperties = $class.CreateInstance()
|
28
|
+
$LocalizedProperties.DisplayName="%s"
|
29
|
+
$LocalizedProperties.Description="%s"
|
30
|
+
$class = $class = Get-WmiObject -Class SMS_AuthorizationList -list
|
31
|
+
$UpdateGroup = $class.CreateInstance()
|
32
|
+
$UpdateGroup.LocalizedInformation = $LocalizedProperties
|
33
|
+
$UpdateGroup.Updates = %s
|
34
|
+
$UpdateGroup.put()
|
35
|
+
COMMAND
|
36
|
+
:update_software_update_group => <<~COMMAND,
|
37
|
+
$PSDefaultParameterValues =@{"get-wmiobject:namespace"="%s";"get-WMIObject:computername"="%s"}
|
38
|
+
$UpdateGroup = Get-WmiObject -Class SMS_AuthorizationList | Where-Object -Property CI_ID -EQ "%s"
|
39
|
+
$UpdateGroup.Updates = %s
|
40
|
+
$UpdateGroup.put()
|
41
|
+
COMMAND
|
42
|
+
:update_software_update_group_empty => <<~COMMAND,
|
43
|
+
$PSDefaultParameterValues =@{"get-wmiobject:namespace"="%s";"get-WMIObject:computername"="%s"}
|
44
|
+
$UpdateGroup = Get-WmiObject -Class SMS_AuthorizationList | Where-Object -Property CI_ID -EQ "%s"
|
45
|
+
$UpdateGroup.Updates = @()
|
46
|
+
$UpdateGroup.put()
|
47
|
+
COMMAND
|
48
|
+
:create_collection => <<~COMMAND,
|
49
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
50
|
+
Set-Location %s
|
51
|
+
New-CMDeviceCollection -Name "%s" -LimitingCollectionName "All Systems"
|
52
|
+
COMMAND
|
53
|
+
:add_device_to_collection => <<~COMMAND,
|
54
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
55
|
+
Set-Location %s
|
56
|
+
Add-CMDeviceCollectionDirectMembershipRule -CollectionId "%s" -ResourceId "%s"
|
57
|
+
COMMAND
|
58
|
+
:remove_device_from_collection => <<~COMMAND,
|
59
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
60
|
+
Set-Location %s
|
61
|
+
Remove-CMDeviceCollectionDirectMembershipRule -CollectionId "%s" -ResourceId "%s" –Force
|
62
|
+
COMMAND
|
63
|
+
:create_deployment_package => <<~COMMAND,
|
64
|
+
$PSDefaultParameterValues =@{"get-wmiobject:namespace"="%s";"get-WMIObject:computername"="%s"}
|
65
|
+
$class = Get-WmiObject -Class SMS_SoftwareUpdatesPackage -List
|
66
|
+
$DeployPackage = $class.CreateInstance()
|
67
|
+
$DeployPackage.Name = "%s"
|
68
|
+
$DeployPackage.Description = "%s Updates"
|
69
|
+
$DeployPackage.PkgSourcePath = "%s"
|
70
|
+
$DeployPackage.PkgSourceFlag = [int32]2
|
71
|
+
$DeployPackage.put()
|
72
|
+
COMMAND
|
73
|
+
:delete_deployment_package => <<~COMMAND,
|
74
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
75
|
+
Set-Location %s
|
76
|
+
Remove-CMSoftwareUpdateDeploymentPackage -Name %s -Force
|
77
|
+
COMMAND
|
78
|
+
:download_software_updates => <<~COMMAND,
|
79
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
80
|
+
Set-Location %s
|
81
|
+
Save-CMSoftwareUpdate -DeploymentPackageName "%s" -SoftwareUpdateGroupName "%s" -SoftwareUpdateLanguage English
|
82
|
+
COMMAND
|
83
|
+
:deploy_package => <<~COMMAND,
|
84
|
+
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\\..\\ConfigurationManager.psd1"
|
85
|
+
Set-Location %s
|
86
|
+
New-CMSoftwareUpdateDeployment -SoftwareUpdateGroupName %s -CollectionName %s -DeploymentName %s -DeploymentType %s
|
87
|
+
COMMAND
|
88
|
+
}
|
89
|
+
|
90
|
+
def self.run(conn, cmd, *args)
|
91
|
+
unless @cmds.key?(cmd)
|
92
|
+
NexposeSCCM.logger.error("Invalid command supplied: #{cmd}")
|
93
|
+
end
|
94
|
+
cmd = @cmds[cmd] % [*args]
|
95
|
+
result = []
|
96
|
+
conn.shell(:powershell) do |shell|
|
97
|
+
err = nil
|
98
|
+
output = shell.run(cmd) do |response, stderr|
|
99
|
+
result << response
|
100
|
+
err = stderr
|
101
|
+
end
|
102
|
+
if output.exitcode != 0
|
103
|
+
NexposeSCCM.logger.error(err)
|
104
|
+
result = nil
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
result
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|