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