Thema
Dieses Skript importiert eine CSV-Datei mit Schwachstellen, die aus verschiedenen Schwachstellen-Scan-Tools und -Plattformen exportiert wurden.
Umgebung
NinjaOne Automation
Beschreibung
Um dieses Skript zu verwenden, speichern Sie es als Batch-Datei und laden Sie es in Ihre Skriptbibliothek hoch. Sie können es dann bei Bedarf über die Wiedergabetaste auf der Gerätedetailseite oder über die Gerätesuche ausführen. Anweisungen und Ressourcen finden Sie unter Automatisieren des Imports von Schwachstellen.
<#
.SYNOPSIS
Dieses Skript wird verwendet, um eine CSV-Datei mit Schwachstellen zu importieren, die aus verschiedenen Tools/Plattformen zum Scannen von Schwachstellen exportiert wurde.
.DESCRIPTION
Dieses Skript wird verwendet, um eine CSV-Datei mit Schwachstellen zu importieren, die aus verschiedenen Tools/Plattformen zum Scannen von Schwachstellen exportiert wurde.
Sobald die Datei erfolgreich importiert wurde, wird die CSV-Datei gelöscht. Wenn der Import der CSV-Datei aufgrund eines Problems
mit der CSV-Datei fehlschlägt, wird "FAILED_" an den Namen der CSV-Datei angehängt. Wenn der erste Importaufruf erfolgreich ist, aber die nachfolgenden Statusprüfungen
fehlschlagen, wird "UNKNOWN_" an den Namen der CSV-Datei angehängt. In diesem Fall müssen Sie den Status in der NinjaOne-Benutzeroberfläche überprüfen.
# ---------------------------------------------------------------
# Autor: Mark Giordano
# Datum: 03.05.2025
# Beschreibung: NinjaOne-Sicherheitslücke Import und Protokollierung
# ---------------------------------------------------------------
.NOTES
Standard-API-URLs sind:
app.ninjarmm.com
eu.ninjarmm.com
oc.ninjarmm.com
ca.ninjarmm.com
us2.ninjarmm.com
Wenn Sie dies als wiederkehrende Aufgabe in NinjaOne einrichten möchten, wird empfohlen, dies auf einem sicheren Gerät zu tun, das nicht für alltägliche Zwecke verwendet wird.
Die Anmeldedaten sollten in sicheren benutzerdefinierten Feldern gespeichert und von dort abgerufen werden.
Siehe die von Luke Whitelock empfohlene Einrichtung (Erste Schritte) hier: https://docs.mspp.io/ninjaone/getting-started
#>
<# Kommentieren Sie diesen Abschnitt aus, wenn Sie Ihre API-Anmeldedaten aus den sicheren benutzerdefinierten Feldern von NinjaOne abrufen möchten
$ClientID = Ninja-Property-Get NinjaOneAPIClientID
$ClientSecret = Ninja-Property-Get NinjaOneAPISecret
#>
# Passen Sie die BaseURL an die entsprechende Instanz an #
$BaseURL = 'ca.ninjarmm.com'
# Scan-Gruppen-ID angeben #
$ScanGroupID = 'SCANGROUP-ID-NUMMER EINGEBEN'
# Verzeichnis für die CSV-Dateien zum Importieren #
$PathtoCSV = "$env:SystemDrivetemp"
# Anfangsmuster der CSV-Dateinamen, die übereinstimmen sollen #
$CSVName = 'VulnExport_'
## Funktionseinrichtung ##
function Get-NinjaToken {
$Headers = @{
"Content-Type" = "application/x-www-form-urlencoded"
}
$Scope = "monitoring management offline_access"
if ([string]::IsNullOrWhiteSpace($ClientID) -or [string]::IsNullOrWhiteSpace($ClientSecret)) {
if ($($PSVersionTable.PSVersion -lt [version]'7.0')) {
$ClientID = Read-Host -Prompt "ClientID"
$ClientSecret = Read-Host -Prompt "ClientSecret"
}
else {
$ClientID = Read-Host -MaskInput "ClientID"
$ClientSecret = Read-Host -MaskInput "ClientSecret"
}
}
$GrantType = 'client_credentials'
$params = @{
Uri = "https://$($BaseURL)/ws/oauth/token"
Method = 'POST'
Body = "grant_type=$GrantType&client_id=$ClientID&client_secret=$ClientSecret&scope=$Scope"
}
$Response = Invoke-RestMethod @Params -Headers $Headers
return $Response.access_token
}
function Get-BaseSettings {
[CmdletBinding()]
param (
[Parameter()]
[String]$Method = 'Get',
[Parameter()]
[String]$Body,
[switch]$Paginate,
[string]$After,
[string]$ContentType
)
if ($Paginate) {
$URL = "https://$($BaseURL)/api/v2/$($Request)?pageSize=$($PageSize)&after=$($After)"
}
else {
$URL = "https://$($BaseURL)/api/v2/$($Request)"
}
$Params = @{
Uri = "$URL"
Method = "$Method"
Headers = @{
'Authorization' = 'Bearer {0}' -f "$Token"
"Content-Type" = 'application/json'
}
}
if ($Body) {
$Params['Body'] = $Body
}
return $Params
}
function Get-VulScanGroups {
[CmdletBinding()]
param (
[Parameter()]
[int]$SGID
)
if ($SGID) {
$Request = "/vulnerability/scan-groups/$SGID"
}
else {
$Request = '/vulnerability/scan-groups'
}
$Params = Get-BaseSettings
try {
$ScanGroupRaw = Invoke-WebRequest @Params
return $ScanGroupRaw.Content | ConvertFrom-Json
}
catch {
return $false
}
}
function New-VulScanImport {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[int]$SGID,
[Parameter(Mandatory = $true)]
[string]$CSV
)
if ($($PSVersionTable.PSVersion -ge [version]'7.0')) {
$Request = "vulnerability/scan-groups/$SGID/upload"
$Params = Get-BaseSettings -Method 'Post'
$Form = @{
"csv" = Get-Item $CSV
}
try {
$Response = Invoke-WebRequest @Params -Form $Form
Write-LogEntry -Message ($Response.Content | Out-String)
}
catch {
Write-LogEntry -Message 'Failed to import CSV.'
Write-LogEntry -Message "$($_.Exception.Message)"
exit 1
}
}
else {
$APIURL = "https://$BaseUrl/api/v2/vulnerability/scan-groups/$SGID/upload"
Add-Type -AssemblyName System.Net.Http
$HTTPClient = New-Object System.Net.Http.HttpClient
$HTTPClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $Token)
# Erstellen Sie den Multipart-Formulardateninhalt
$MPFormData = New-Object System.Net.Http.MultipartFormDataContent
# Öffnen Sie die CSV-Datei als Stream und bereiten Sie den StreamContent vor
$FileStream = [System.IO.File]::OpenRead($CSV)
$FileName = [System.IO.Path]::GetFileName($CSV)
$StreamContent = New-Object System.Net.Http.StreamContent($FileStream)
$StreamContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse("text/csv")
# Fügen Sie den Inhalt der CSV-Datei mit dem Formularfeldnamen "csv" hinzu
$MPFormData.Add($StreamContent, "csv", $FileName)
# Den mehrteiligen Inhalt senden und auf das Ergebnis warten
$APICall = $HTTPClient.PostAsync($APIURL, $MPFormData)
$APICall.Wait()
$Response = $APICall.Result
# Den Inhalt der Antwort lesen
$APIResponse = $Response.Content.ReadAsStringAsync()
$APIResponse.Wait()
if (!($Response.IsSuccessStatusCode)) {
Write-LogEntry -Message 'Failed to import CSV.'
Write-LogEntry -Message ($APIResponse.Result | Out-String)
$FileStream.Close()
$HTTPClient.Dispose()
exit 1
}
Write-LogEntry -Message ($APIResponse.Result | Out-String)
$FileStream.Close()
$HTTPClient.Dispose()
}
}
function Write-LogEntry {
param (
[Parameter(Mandatory = $true)]
[string]$Message
)
$LogPath = "$PathtoCSVNinjaOneVulnerabiltyImport.log"
$TimeStamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
Add-Content -Path $LogPath -Value "$TimeStamp $Message"
Write-Host "$TimeStamp $Message"
}
## End Function Setup ##
$Token = Get-NinjaToken
if (!(Test-Path $PathtoCSV)) {
Write-LogEntry -Message 'Der eingegebene Pfad zu den CSV-Dateien existiert nicht. Beenden.'
exit 1
}
$CSVFiles = Get-ChildItem $PathtoCSV | Where-Object { $_.Extension -eq '.csv' -and $_.Name -match "^$CSVName" }
if (!($CSVFiles)) {
Write-LogEntry -Message 'Keine CSV-Datei zum Importieren vorhanden. Beenden.'
exit 0
}
foreach ($CSV in $CSVFiles) {
Write-LogEntry -Message "CSV gefunden: $($CSV.Name)"
Write-LogEntry -Message "Importing to ScanGroup $ScanGroupID"
try {
New-VulScanImport -SGID $ScanGroupID -CSV $($CSV.FullName)
}
catch {
Write-LogEntry -Message 'Failed to import csv.'
Write-LogEntry -Message ($_.Exception.Message)
exit 1
}
$ImportStatus = (Get-VulScanGroups -SGID $ScanGroupID).Status
if (!($ImportStatus)) {
Write-LogEntry -Message 'Importstatus kann nicht abgerufen werden, aber der Import kann dennoch erfolgreich sein.'
Write-LogEntry -Message 'Bitte überprüfen Sie den NinjaOne-UI auf den Importstatus der Schwachstellen.'
Write-LogEntry -Message 'CSV-Dateiname mit UNKNOWN_ anhängen'
try {
Rename-Item -Path $($CSV.FullName) "UNKNOWN_$($CSV.Name)" -ErrorAction Stop
Write-LogEntry -Message "Erfolgreich umbenannt in UNKNOWN_$($CSV.Name)."
exit 1
}
catch {
Write-LogEntry -Message "Failed to rename CSV."
exit 1
}
}
while ($ImportStatus -ne 'Complete') {
Write-LogEntry -Message "Import Status: $ImportStatus"
Start-Sleep 10
$ImportStatus = (Get-VulScanGroups -SGID $ScanGroupID).Status
}
if ($ImportStatus -eq 'Complete' ) {
Write-LogEntry -Message "Importstatus: $ImportStatus"
Write-LogEntry -Message "Import erfolgreich"
Write-LogEntry -Message "Löschen von $($CSV.Name)..."
try {
Remove-Item -Path $($CSV.FullName) -Force -ErrorAction Stop
Write-LogEntry -Message "Erfolgreich gelöscht."
exit 0
}
catch {
Write-LogEntry -Message "Failed to delete CSV."
exit 1
}
}
else {
Write-LogEntry -Message "Import Status: $ImportStatus"
Write-LogEntry -Message "Import failed!"
Write-LogEntry -Message "Renaming $($CSV.Name)..."
try {
Rename-Item -Path $($CSV.FullName) "FAILED_$($CSV.Name)" -ErrorAction Stop
Write-LogEntry -Message "Successfully renamed to FAILED_$($CSV.Name)."
exit 1
}
catch {
Write-LogEntry -Message "Failed to rename CSV."
exit 1
}
}
}