Skip to content

Instantly share code, notes, and snippets.

@mbrownnycnyc
Last active June 19, 2019 18:41
Show Gist options
  • Save mbrownnycnyc/ac7c569dd86644d5a6c351a8280ab0cd to your computer and use it in GitHub Desktop.
Save mbrownnycnyc/ac7c569dd86644d5a6c351a8280ab0cd to your computer and use it in GitHub Desktop.
A script to take members of an OU, look them up in Nexpose, and report on tagging status of these. The tags can then be used to adjust assets reported upon. This client had many machines that were powered off, but were once scanned (aka are managed assets) that they want to consider in some reports, but not all. This allows them to deal with ass…
<#1) copy over Rapid7Nexpose and Indented.Net.IP to a path in $env:psmodulePath, and install the OrionSDK https://github.com/solarwinds/OrionSDK/releases
2) store your password in a securestring
# https://blogs.technet.microsoft.com/robcost/2008/05/01/powershell-tip-storing-and-using-password-credentials/
$nscusername = "matt.brown"
$(read-host -assecurestring | convertfrom-securestring) | out-file .\Desktop\nscsstr.txt
#the securestring is encrypted against the personal key of the user for which is run using DPAPI
# https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Security/ConvertFrom-SecureString?view=powershell-5.1#description
# http://www.griffinscs.com/?p=12
# https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netframework-4.8#how-secure-is-securestring
# https://docs.microsoft.com/en-us/previous-versions/ms995355(v%3Dmsdn.10)
#to use later:
#$nsccreds = new-object -typename System.Management.Automation.PSCredential -argumentlist $nscusername,(get-content .\Desktop\nscsstr.txt | convertto-securestring)
You must create a custom tag before using this called StagedComputers: https://nexpose/tag/listing.jsp
Note that I am making all assets shortnames given the AD query. This is done as noted as "## creating shortnames" below. This will unify the AD query with the Nexpose hostname, but maybe you want to have the FQDN later. Remove this section.
#>
#https://github.com/My-Random-Thoughts/Rapid7Nexpose/
Import-Module -Name Rapid7Nexpose
function get-nexposeassets {
[CmdletBinding()]
param (
$sstrfile = "C:\Users\matt.brown\Desktop\nscsstr.txt",
$nscusername = "matt.brown",
$nschostname = "nexpose",
$nscport = "443",
$tag,
$hostname
)
$nsccreds = new-object -typename System.Management.Automation.PSCredential -argumentlist $nscusername,(get-content $sstrfile | convertto-securestring)
$nscconn = Connect-NexposeAPI -HostName $nschostname -Port $nscport -Credential $nsccreds
[System.GC]::Collect()
#query for Nexpose assets
if ($tag.length -gt 0) {
$assetsreturned = get-nexposeasset -tag "$tag" -tagtype "custom"
} elseif ($hostname.length -gt 0) {
write-verbose $hostname
$assetsreturned = get-nexposeasset -name $hostname
} else {
write-error "need either a tag or hostname"
}
return $assetsreturned
}
function add-nexposetagtoasset {
[CmdletBinding()]
param (
$sstrfile = "C:\Users\matt.brown\Desktop\nscsstr.txt",
$nscusername = "matt.brown",
$nschostname = "nexpose",
$nscport = "443",
$tag,
$hostname
)
$nsccreds = new-object -typename System.Management.Automation.PSCredential -argumentlist $nscusername,(get-content $sstrfile | convertto-securestring)
$nscconn = Connect-NexposeAPI -HostName $nschostname -Port $nscport -Credential $nsccreds
[System.GC]::Collect()
$stagingtagid = (get-nexposetag -name "$tag").id
$assetid = (get-nexposeasset -name "$hostname").id
Add-NexposeTagToObject -tagid $stagingtagid -objectid $assetid -objecttype asset
}
function remove-nexposetagfromasset {
[CmdletBinding()]
param (
$sstrfile = "C:\Users\matt.brown\Desktop\nscsstr.txt",
$nscusername = "matt.brown",
$nschostname = "nexpose",
$nscport = "443",
$tag,
$hostname
)
$nsccreds = new-object -typename System.Management.Automation.PSCredential -argumentlist $nscusername,(get-content $sstrfile | convertto-securestring)
$nscconn = Connect-NexposeAPI -HostName $nschostname -Port $nscport -Credential $nsccreds
[System.GC]::Collect()
$stagingtagid = (get-nexposetag -name "$tag").id
$assetid = (get-nexposeasset -name $hostname).id
remove-NexposeTagfromObject -tagid $stagingtagid -objectid $assetid -objecttype asset
}
function main {
$smtpserver = "casarray1.contoso.local"
$emailto = "[email protected]"
$emailfrom = "[email protected]"
$csvfilename = "$env:tmp\nexpose_staging_asset_report_$((get-date).tostring('yyyyMMdd-hhmmss')).csv"
$sstrfile = "C:\Users\matt.brown\Desktop\nscsstr.txt"
$nschostname = "nexpose"
$nscport = "443"
$nscusername = "matt.brown"
$nscstagingtag = "StagedComputers"
#query AD for list of PCs where tag should exist as of right now:
try {
$stagingcomputers = (Get-ADComputer -Filter * -SearchBase "OU=_Staging, OU=Workstations, DC=contoso, DC=local").name
} catch {
$stagingcomputers = (import-csv "\\contoso\dfs\Departments\IT\Vulnerability Management\_nexpose_staging_pc\EVRStagingMembers.csv").name
}
#get all objects that are present in the OU that are in and aren't in nexpose so we can add up the risk score difference for those that are in nexpose:
$stagingcomputersnscasset = @()
$stagingcomputersnotinnsc = @()
foreach ($hostname in $stagingcomputers) {
$tempobj = get-nexposeassets -verbose -nschostname $nschostname -nscport $nscport -nscusername $nscusername -sstrfile $sstrfile -hostname $hostname | select id, hostname, hostnames, ip, users, riskscore
if ( $($tempobj.hostname).length -gt 0 ) {
## creating shortnames
if ($tempobj.hostname -match ".") {
$tempobj.hostname = $tempobj.hostname.split(".")[0]
}
## end creating shortnames
$stagingcomputersnscasset += $tempobj
} else {
$stagingcomputersnotinnsc += $hostname
}
}
#query for all nscassets that have the tag present (who's to say these are actually staging PCs? we will determine this later)
$assetswithtag = get-nexposeassets -nschostname $nschostname -nscport $nscport -nscusername $nscusername -sstrfile $sstrfile -tag $nscstagingtag | select id, hostname, hostnames, ip, users, riskscore
#compare staging PCs in nexpose with tag to staging PCs in nexpose without tag
$leftside = $($assetswithtag.hostname)
$rightside = $($stagingcomputersnscasset.hostname)
$stagingcomparison = compare-object -includeequal $leftside $rightside
#$stagingcomparison.SideIndicator can -eq
## "=>" means that this item is in $leftside and not in $rightside (these assets have tags already)
## "<=" means that this item is not in $leftside and in $rightside (these assets need tags added) #we don't care about this as we already pulled this
## "==" means that this item is in $leftside and in $rightside (there should be no assets matching this condition as they either have a tag or don't have a tag)
$stagingcomputerswithouttag = ($stagingcomparison | ? {$_.sideindicator -eq "=>"}).inputobject
#select nsc assets objects that are without tags, so we can get at the additional properties
$stagingcomputerswithouttag = $stagingcomputersnscasset | ? { $stagingcomputerswithouttag -contains $_.hostname}
#select $assetswithtag that are not in $stagingcomputersnscasset
$assetswithtagsthatarenotstagingcomputers = $assetswithtag | ? {$stagingcomputersnscasset.hostname -notcontains $_.hostname}
#calculate riskscore totals
$totalriskscoreofstagingcomputerswithtag = 0
foreach ($item in $assetswithtag ) {
$totalriskscoreofstagingcomputerswithtag += $item.riskscore
}
$totalriskscoreofstagingcomputerswithouttag = 0
foreach ($item in $stagingcomputerswithouttag ) {
$totalriskscoreofstagingcomputerswithouttag += $item.riskscore
}
$totalriskscoreofassetswithtagsthatarenotstagingcomputers = 0
foreach ($item in $assetswithtagsthatarenotstagingcomputers) {
$totalriskscoreofassetswithtagsthatarenotstagingcomputers += $item.riskscore
}
##add tags to assets that need tags
<#
foreach ($stagingcomputerwithouttag in $stagingcomputerswithouttag) {
add-nexposetagtoasset -tag "$nscstagingtag" -hostname "$($stagingcomputerwithouttag.hostname)"
}
#>
##remove tags from assets that don't need tags
<#
foreach ($assetwithtagsthatarenotstagingcomputers in $assetswithtagsthatarenotstagingcomputers) {
remove-nexposetagfromasset -tag "$nscstagingtag" -hostname "$($assetwithtagsthatarenotstagingcomputers.hostname)"
}
#>
#combine all data
# $stagingcomputerswithouttag
# $assetswithtag
#create array for email.
$riskdelta = [math]::round($totalriskscoreofassetswithtagsthatarenotstagingcomputers - $totalriskscoreofstagingcomputerswithouttag)
$emailsubject = "[NEXPOSE] $($($stagingcomputerswithouttag.id).count) assets should be tagged, $($($assetswithtagsthatarenotstagingcomputers.id).count) assets should have tags removed: net riskscore delta after tagging operations $($riskdelta)ish"
## interesting fields for the email would be:
## hostname, PresentInStagingOU, PresentInNexpose, NexposeStagingTagExists, NexposeRiskScore
#psuedo code:
## presentinstagingou == $stagingcomputers
## presentinnexpose == ($stagingcomputersnscasset.hostname + $assetswithtag.hostname) | select -uniq #logical union https://stackoverflow.com/a/8609448
## NexposeStagingTagExists == $assetswithtag
#format for an email
$emailtable = @()
$allinscopehostnames = $stagingcomputers + $assetswithtag.hostname
foreach ($item in $allinscopehostnames) {
$tempobj = "" | select hostname, PresentInStagingOU, PresentInNexpose, NexposeStagingTagExists, NexposeRiskScore
$tempobj.hostname = $item
if ($stagingcomputers -contains $item) {
$tempobj.PresentInStagingOU = $true
} else {
$tempobj.PresentInStagingOU = $false
}
if ( $(($stagingcomputersnscasset.hostname + $assetswithtag.hostname) | select -uniq) -contains $item) {
$tempobj.PresentInNexpose = $true
} else {
$tempobj.PresentInNexpose = $false
}
if ($assetswithtag.hostname -contains $item) {
$tempobj.NexposeStagingTagExists = $true
} else {
$tempobj.NexposeStagingTagExists = $false
}
#remember ( ($true) -eq $true ) AND ($thisistrue = $true; ($thisistrue) -eq true)
if ($tempobj.PresentInNexpose) {
#in order to get the riskscore value, we need to find the nscasset data
#$stagingcomputersnscasset and $assetswithtag have the riskScore value contained
#find the indexof the nscasset data for $item
$indexofitem = $($stagingcomputersnscasset.hostname).indexof($item)
if ($indexofitem -ge 0) {
#then we found the $item in $stagingcomputersnscasset.hostname array
$tempobj.NexposeRiskScore = $stagingcomputersnscasset[$indexofitem].riskscore
} else {
#then we didn't find the $item in $stagingcomputersnscasset.hostname array
#because we know ($tempobj.PresentInNexpose), we know that the only other option is that it's in $assetswithtag.hostname
$indexofitem = $($assetswithtag.hostname).indexof($item)
$tempobj.NexposeRiskScore = $assetswithtag[$indexofitem].riskscore
}
}
$emailtable += $tempobj
}
if ($emailtable.count -gt 0 ) {
$emailtable | export-csv -notypeinfo $csvfilename
#http://thesurlyadmin.com/2013/01/21/how-to-create-html-reports/
$Header = "`
<style>
TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
TH {font-family: 'Calibri';font-size: 11pt;border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #8cc3ff;}
TD {font-family: 'Calibri';font-size: 11pt;border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
</style>
<title>
</title>"
send-mailmessage -smtpserver $smtpserver -to $emailto -from $emailfrom -subject $emailsubject -bodyashtml -body ( $emailtable | convertto-html -head $Header | out-string ) -attachment "$csvfilename"
}
}
. main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment