-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPSTenableSC.psm1
6385 lines (5876 loc) · 317 KB
/
PSTenableSC.psm1
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Import localization data.
Import-LocalizedData -BindingVariable local -FileName PSTenableSCLocal -UICulture en-US
# Import support functions.
. "$PSScriptRoot\PSTenableSCSupport.ps1"
#region Set globally accessible variables.
# Get window title.
$DefaultPSWindowTitle = [Console]::Title
# Set culture variable to manipulate text later.
$Global:Culture = (Get-Culture).TextInfo
# Set regular expressions templates.
## IPv4.
[RegEx]$Global:IPv4RegEx = '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
Write-SCLog -LogInfo $($local.LOG_IPV4_REGEX -f $IPv4RegEx)
## FQDN.
[RegEx]$Global:FQDNRegEx = '([\D]{1,2}[\w]{4}.)([\D])*?([\w]){5,9}.([\w]).(com|net)'
Write-SCLog -LogInfo $($local.LOG_FQDN_REGEX -f $FQDNRegEx)
## Single label name.
[RegEx]$Global:HostNameRegEx = '[a-zA-Z]{1,2}[0-9]{4,5}'
## CVE.
[RegEx]$Global:CVERegEx = "CVE-(1999|2\d{3})-(0\d{2}[1-9]|[1-9]\d{3,})"
Write-SCLog -LogInfo $($local.LOG_CVE_REGEX -f $CVERegEx)
# Tenable.SC address.
[String]$Global:ServerFQDN = "tenablesc.server.net"
# New line.
$Global:NewLine = [Environment]::NewLine
# Buffer height and subtract 15 lines, just in case.
$Global:BufferHeight = [console]::BufferHeight-15
#endregion
Function ConvertFrom-SCReportCSV2XLSX {
<#
.SYNOPSIS
Convert Tenable SecurityCenter reports from CSV to XLSX.
.DESCRIPTION
Convert report CSV file(s), from Tenable SecurityCenter, to a presentable Excel spreadsheet.
.EXAMPLE
Convert compliance report CSV file to XLSX spreadsheet with the minimum parameter set. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Compliance -ComplianceCSV C:\TEMP\compliance.csv -TargetXLSX C:\TEMP\compliance.xlsx -SourceCSVDelimiter ","
.EXAMPLE
Convert compliance report CSV file to XLSX spreadsheet and show all lines. By default, erronous lines are excluded from the output. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Compliance -ComplianceCSV C:\TEMP\compliance.csv -TargetXLSX C:\TEMP\compliance.xlsx -SourceCSVDelimiter "," -ShowAll
.EXAMPLE
Convert compliance report CSV file to XLSX spreadsheet with tab as delimiter. By default it's semicolon. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Compliance -ComplianceCSV C:\TEMP\compliance.csv -TargetXLSX C:\TEMP\compliance.xlsx -SourceCSVDelimiter "," -TargetCSVDelimiter ";"
.EXAMPLE
Convert compliance report CSV file to XLSX spreadsheet and keep the TEMP files created during the process. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Compliance -ComplianceCSV C:\TEMP\compliance.csv -TargetXLSX C:\TEMP\compliance.xlsx -SourceCSVDelimiter "," -KeepTEMP
.EXAMPLE
Convert vulnerability report CSV files to XLSX spreadsheet with the minimum parameter set, including summary and detailed sheets. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Vulnerability -VulnSummaryCSV C:\TEMP\vuln_summary.csv -VulnDetailCSV C:\TEMP\vuln_detailed.csv -SourceCSVDelimiter "," -TargetXLSX C:\TEMP\vulnerabilities.xlsx
.EXAMPLE
Convert vulnerability report CSV file to XLSX spreadsheet without the summary sheet. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Vulnerability -NoVulnSummary -VulnDetailCSV C:\TEMP\vuln_detailed.csv -SourceCSVDelimiter "," -TargetXLSX C:\TEMP\vulnerabilities.xlsx
.EXAMPLE
Convert vulnerability report CSV file to XLSX spreadsheet and exclude some plugins by entering them into an array. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Vulnerability -VulnSummaryCSV C:\TEMP\vuln_summary.csv -VulnDetailCSV C:\TEMP\vuln_detailed.csv -TargetXLSX C:\TEMP\vulnerabilities.xlsx -SourceCSVDelimiter "," -ExcludePlugins 18405,108757,90433
.EXAMPLE
Convert vulnerability report CSV file to XLSX spreadsheet and exclude some plugins by reading plugins from a file. One plugin ID per line. A comma-separated array of plugin IDs is not supported. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Vulnerability -VulnSummaryCSV C:\TEMP\vuln_summary.csv -VulnDetailCSV C:\TEMP\vuln_detailed.csv -TargetXLSX C:\TEMP\vulnerabilities.xlsx -SourceCSVDelimiter "," -ExcludePlugins (Get-Content -Path C:\TEMP\plugins.txt)
.EXAMPLE
Convert vulnerability report CSV file to XLSX spreadsheet and exclude some plugins by reading plugins from a file, and some severities. Also specify the delimiter used in the source CSV files.
ConvertFrom-ReportCSV2XLSX -Vulnerability -VulnSummaryCSV C:\TEMP\vuln_summary.csv -VulnDetailCSV C:\TEMP\vuln_detailed.csv -TargetXLSX C:\TEMP\vulnerabilities.xlsx -SourceCSVDelimiter "," -ExcludePlugins (Get-Content -Path C:\TEMP\plugins.txt) -ExcludeSeverities Info, Low
.PARAMETER Compliance
Compliance switch makes available other parameters in the compliance parameter set. Compliance and Vulnerability parameter sets cannot be used at the same time.
.PARAMETER Vulnerability
Vulnerability switch makes available other parameters in the Vulnerability parameter set. Vulnerability and compliance parameter sets cannot be used at the same time.
.PARAMETER NoVulnSummary
Use this parameter if you want to convert just the detailed part.
.PARAMETER ComplianceCSV
Enter path to compliance CSV file.
.PARAMETER VulnSummaryCSV
Enter path to vulnerability summary CSV file.
.PARAMETER VulnDetailCSV
Enter path to vulnerability detailed CSV file.
.PARAMETER SourceCSVDelimiter
Set a custom delimiter for the Source CSV.
.PARAMETER TargetCSVDelimiter
Set a custom delimiter for the Target CSV. Default is semicolon (;).
.PARAMETER TargetXLSX
Set output Excel file Path.
.PARAMETER ExcludePlugins
Exclude some plugins from the output.
.PARAMETER ExcludeSeverities
Exclude some severities from the output.
.PARAMETER ShowAll
Show all compliance report lines from the Source CSV File. By default erronous items are excluded.
.PARAMETER KeepTEMP
Keep the temp CSV files made during the conversion process.
.INPUTS
None, You can't pipe objects to ConvertFrom-SCReportCSV2XLSX.
.OUTPUTS
Preformatted Excel pacakge.
.NOTES
This Module needs ImportExcel Module to work.
.ROLE
TenableSC User.
.COMPONENT
ImportExcel
.FUNCTIONALITY
Convert SecurityCenver compliance or vulnerability reports to a nice looking spreadsheet.
#>
[CmdletBinding()]
Param(
[Parameter( Position = 0, Mandatory = $True, ParameterSetName = 'Compliance', HelpMessage = { $local.REPC2X_HELP_REPORT_TYPE } )]
[Switch]$Compliance,
[Parameter( Position = 1, Mandatory = $False, ParameterSetName = 'Compliance', HelpMessage = { $local.REPC2X_HELP_COMPLIANCE_SOURCE } )]
[ValidateScript( { Test-Path -Path $PSItem -PathType Leaf } )]
[ValidatePattern( '^*.csv$' )]
[String]$ComplianceCSV,
[Parameter( Position = 2, Mandatory = $True, ParameterSetName = 'VulnerabilitySummary', HelpMessage = { $local.REPC2X_HELP_REPORT_TYPE } )]
[Parameter( ParameterSetName = 'NoVulnerabilitySummary' )]
[Switch]$Vulnerability,
[Parameter( Position = 3, Mandatory = $False, ParameterSetName = 'NoVulnerabilitySummary', HelpMessage = { $local.REPC2X_HELP_VULNERABILITY_NO_SUMMARY } )]
[Switch]$NoVulnSummary,
[Parameter( Position = 4, Mandatory = $False, ParameterSetName = 'VulnerabilitySummary', HelpMessage = { $local.REPC2X_HELP_VULNERABILITY_SUMMARY_SOURCE } )]
[ValidatePattern( '^*.csv$' )]
[String]$VulnSummaryCSV,
[Parameter( Position = 5, Mandatory = $False, ParameterSetName = 'VulnerabilitySummary', HelpMessage = { $local.REPC2X_HELP_VULNERABILITY_DETAIL_SOURCE } )]
[Parameter( ParameterSetName = 'NoVulnerabilitySummary' )]
[ValidateScript( { Test-Path -Path $PSItem -PathType Leaf } )]
[ValidatePattern( '^*.csv$' )]
[String]$VulnDetailCSV,
[Parameter( Position = 6, Mandatory = $True, Helpmessage = { $local.REPC2X_HELP_SOURCE_DELIMETER } )]
[ValidateLength( 1, 1 )]
[String]$SourceCSVDelimiter,
[Parameter( Position = 7, Mandatory = $False, Helpmessage = { $local.REPC2X_HELP_TARGET_DELIMETER } )]
[ValidateLength( 1, 1 )]
[ValidateScript( {
# Do not allow using delimiters that can cause structural instability in the CSV.
If ($PSItem -in @(",","`"","'","*","-","+")) {
Write-SCError -Message $($local.REPC2X_ERROR_UNSUPPORTED_DELIMITER -f $PSItem) -RecommendedAction $local.REPC2X_ERROR_UNSUPPORTED_DELIMITER_FIX
} # Provided delimiter is not supported, exit.
Else {
# Supported delimiter was used.
$True
} # Provided delimiter is OK. End of TargetCSVDelimiter check.
} )]
[String]$TargetCSVDelimiter = ';',
[Parameter( Position = 8, Mandatory = $True, HelpMessage = { $local.REPC2X_HELP_TARGET } )]
[ValidateScript( {
If (Test-Path -Path $PSItem) {
# File exists, exit. Can't be bothered to offer to save with another name at this point, exit.
Write-SCError -Message $local.REPC2X_ERROR_TARGET_FILE_EXISTS -RecommendedAction $local.REPC2X_ERROR_TARGET_FILE_EXISTS_FIX
} # File check failed, file already exists, exit.
Else {
# No existing file with the same name.
$True
} # Filename does not already exist. End of TargetXLSX file path check.
} )]
[ValidatePattern( '^*.xlsx$' )]
[String]$TargetXLSX,
[Parameter( Position = 9, Mandatory = $False, ParameterSetName = 'VulnerabilitySummary', HelpMessage = { $local.REPC2X_HELP_EXCLUDE_PLUGINS } )]
[Parameter( ParameterSetName = 'NoVulnerabilitySummary' )]
[String[]]$ExcludePlugins,
[Parameter( Position = 10, Mandatory = $False, HelpMessage = { $local.REPC2X_HELP_EXCLUDE_SEVERITIES } )]
[String[]]$ExcludeSeverities,
[Parameter( Position = 11, Mandatory = $True, ParameterSetName = 'Compliance', HelpMessage = { $local.REPC2X_HELP_SHOWALL } )]
[Switch]$ShowAll,
[Parameter( Position = 12, Mandatory = $False, HelpMessage = { $local.REPC2X_HELP_KEEPTEMP } )]
[Switch]$KeepTEMP
)
Begin {
# Show running cmdlet in window title.
[Console]::Title = $($local.INFO_TITLE_RUNNING_CMDLET -f $MyInvocation.MyCommand)
} # End of Begin.
Process {
Switch ($PSCmdlet.ParameterSetName) {
'Compliance' {
Write-SCLog -LogInfo $local.REPC2X_LOG_COMPLIANCE
# Put current scope name into a variable.
$Scope = 'Compliance'
Write-SCLog -LogInfo $($local.REPC2X_LOG_SET_SCOPE -f $Scope)
# Create TEMP files for the conversion process.
$ComplianceTMP1 = [System.IO.Path]::GetTempFileName()
Write-SCLog -LogInfo $($local.REPC2X_LOG_TEMP_FILE -f $ComplianceTMP1, $Scope)
# Go through TEMP CSV output and remove NULL or white spaces and make a new output CSV file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_MODIFY_CSV_STRUCTURE -f $ComplianceTMP1, $SourceCSVDelimiter, $TargetCSVDelimiter, $VulnSummaryCSV)
(Get-Content -Path $ComplianceCSV -Raw) | Where-Object { ![String]::IsNullOrWhiteSpace($PSItem).Replace('"' + $SourceCSVDelimiter + '"',"$TargetCSVDelimiter") } | Out-File -FilePath $ComplianceTMP1
# Take the CSV contents and export them to Excel.
$WSName = $local.REPC2X_VULNERABILITY_SUMMARY_WORKSHEET
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_VARIABLE -f $WSName)
$TBLName = $local.REPC2X_VULNERABILITY_SUMMARY_TABLE
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_TABLE_VARIABLE -f $WSName, $TBLName)
# Check whether ExcludeSeverities parameter was used.
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUSION_PARAMETERS_CHECK
If ($ExcludeSeverities) {
Write-SCLog -LogInfo $($local.REPC2X_LOG_EXCLUDESEVERITIES_USED -f $ExcludeSeverities)
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $ComplianceTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
$ExportToXLSX = Import-Csv -Path $ComplianceTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object Severity -NotIn $ExcludeSeverities | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # ExcludeSeverities: True.
Else {
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUSION_PARAMETERS_NOT_USED
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $ComplianceTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
$ExportToXLSX = Import-Csv -Path $ComplianceTMP1 -Delimiter "$TargetCSVDelimiter" | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # ExcludeSeverities: False. End of ExcludeSeverities parameter check.
# Save the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_SAVE_EXCEL_PACKAGE -f $Scope)
$ExportToXLSX.Save()
# Dispose of the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DISPOSE_OF_PACKAGE -f $Scope)
$ExportToXLSX.Dispose()
# Checking if KeepTEMP parameter was used.
If (!$KeepTEMP) {
# Remove temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_REMOVE_TEMP_FILE -f $ComplianceTMP1)
Remove-Item -Path $ComplianceTMP1
} # KeepTEMP: False
Else {
# Or don't remove the temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DONT_REMOVE_TEMP_FILE -f $ComplianceTMP1)
} # KeepTEMP: True. End of KeepTEMP parameter check.
# Tell garbage collector to dump unnecessary stuff.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DUMP_GARBAGE -f $Scope)
[GC]::Collect()
Write-SCLog -LogInfo $($local.REPC2X_LOG_SECTION_END -f $Scope)
} # End of compliance parameter check.
'Vulnerability' {
If (!$NoVulnSummary) {
#region Summary
Write-SCLog -LogInfo $local.REPC2X_LOG_VULNERABILITY
# Put current scope Name into a variable.
$Scope = 'Vulnerability Summary'
Write-SCLog -LogInfo $($local.REPC2X_LOG_SET_SCOPE -f $Scope)
# Create TEMP file for the conversion process.
$SummaryTMP1 = [System.IO.Path]::GetTempFileName()
Write-SCLog -LogInfo $($local.REPC2X_LOG_TEMP_FILE -f $SummaryTMP1, $Scope)
# Convert comma seprarator in CSV to $TargetCSVDelimiter provided delimiter instead. Also remove NULL or white spaces.
Write-SCLog -LogInfo $($local.REPC2X_LOG_MODIFY_CSV_STRUCTURE -f $SummaryTMP1, $SourceCSVDelimiter, $TargetCSVDelimiter, $VulnSummaryCSV)
(Get-Content -Path $VulnSummaryCSV -Raw | Where-Object { ![String]::IsNullOrWhiteSpace($PSItem) }).Replace('"' + $SourceCSVDelimiter + '"','"' + $TargetCSVDelimiter + '"').Replace('Vulnerability Priority Rating','VPR') | Out-File -FilePath $SummaryTMP1
# Take the CSV contents and Export them to Excel.
$WSName = $local.REPC2X_VULNERABILITY_SUMMARY_WORKSHEET
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_VARIABLE -f $WSName)
$TBLName = $local.REPC2X_VULNERABILITY_SUMMARY_TABLE
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_TABLE_VARIABLE -f $WSName, $TBLName)
# Check whether ExcludeSeverities or ExcludePlugins parameters were used.
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUSION_PARAMETERS_CHECK
If ($ExcludePlugins -or $ExcludeSeverity) {
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $SummaryTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
If ($ExcludePlugins -and $ExcludeSeverities) {
Write-SCLog -LogInfo $($local.REPC2X_LOG_EXCLUDEPLUGINS_EXCLUDESEVERITIES_USED -f $ExcludePlugins, $ExcludeSeverities)
$ExportToXLSX = Import-Csv -Path $SummaryTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object { $PSItem.Plugin -NotIn $ExcludePlugins -and $PSItem.Severity -NotIn $ExcludeSeverities } | Select-Object *, 'Last Month?','Owner(s)','Actions','Ticket Number(s)','Status','Comments','Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludePlugins and ExcludeSeverity parameters check.
ElseIf ($ExcludePlugins) {
Write-SCLog -LogInfo $($local.REPC2X_LOG_EXCLUDEPLUGINS_USED -f $ExcludePlugins)
$ExportToXLSX = Import-Csv -Path $SummaryTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object Plugin -NotIn $ExcludePlugins | Select-Object *, 'Last Month?','Owner(s)','Actions','Ticket Number(s)','Status','Comments','Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludePlugins parameter check.
ElseIf ($ExcludeSeverities) {
Write-SCLog -LogInfo $($local.REPC2X_LOG_EXCLUDESEVERITIES_USED -f $ExcludeSeverities)
$ExportToXLSX = Import-Csv -Path $SummaryTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object Severity -NotIn $ExcludeSeverities | Select-Object *, 'Last Month?','Owner(s)','Actions','Ticket Number(s)','Status','Comments','Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludeSeverities parameter check.
} # ExcludePlugins or ExcludeSeverity: True.
Else {
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUSION_PARAMETERS_NOT_USED
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $DetailedTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
$ExportToXLSX = Import-Csv -Path $SummaryTMP1 -Delimiter "$TargetCSVDelimiter" | Select-Object *, 'Last Month?','Owner(s)','Actions','Ticket Number(s)','Status','Comments','Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # ExcludePlugins and ExcludeSeverity: False. End of ExcludePlugins and/or ExcludeSeverity parameter(s) check.
# Save the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_SAVE_EXCEL_PACKAGE -f $Scope)
$ExportToXLSX.Save()
# Dispose of the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DISPOSE_OF_PACKAGE -f $Scope)
$ExportToXLSX.Dispose()
# Checking if KeepTEMP parameter was used.
If (!$KeepTEMP) {
# Remove temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_REMOVE_TEMP_FILE -f $SummaryTMP1)
Remove-Item -Path $SummaryTMP1
} # KeepTEMP: False
Else {
# Or don't remove the temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DONT_REMOVE_TEMP_FILE -f $SummaryTMP1)
} # KeepTEMP: True. End of KeepTEMP parameter check.
# Tell Garbage Collector to dump unnecessary stuff.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DUMP_GARBAGE -f $Scope)
[GC]::Collect()
Write-SCLog -LogInfo $($local.REPC2X_LOG_SECTION_END -f $Scope)
} # End of NoVulnSummary parameter check.
#endregion
#region Detailed
# Put current scope name into a variable.
$Scope = 'Vulnerability Detailed'
Write-SCLog -LogInfo $($local.REPC2X_LOG_SET_SCOPE -f $Scope)
# Create TEMP file for the conversion process.
$DetailedTMP1 = [System.IO.Path]::GetTempFileName()
Write-SCLog -LogInfo $($local.REPC2X_LOG_TEMP_FILE -f $DetailedTMP1, $Scope)
# Convert comma seprarator in CSV to $TargetCSVDelimiter provided delimiter instead. Remove NULL or white spaces.
Write-SCLog -LogInfo $($local.REPC2X_LOG_MODIFY_CSV_STRUCTURE -f $SummaryTMP1, $SourceCSVDelimiter, $TargetCSVDelimiter, $VulnSummaryCSV)
(Get-Content -Path $VulnDetailCSV -Raw | Where-Object {-not [String]::IsNullOrWhiteSpace($PSItem)}).Replace('"' + $SourceCSVDelimiter + '"','"' + $TargetCSVDelimiter + '"').Replace('Vulnerability Priority Rating','VPR') | Out-File -FilePath $DetailedTMP1
# Take the CSV contents and export them to Excel.
$WSName = $local.REPC2X_VULNERABILITY_DETAIL_WORKSHEET
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_VARIABLE -f $WSName)
$TBLName = $local.REPC2X_VULNERABILITY_DETAIL_TABLE
Write-SCLog -LogInfo $($local.REPC2X_LOG_WORKSHEET_TABLE_VARIABLE -f $WSName, $TBLName)
# Check whether ExcludeSeverities or ExcludePlugins parameters were used.
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUSION_PARAMETERS_CHECK
If ($ExcludePlugins -or $ExcludeSeverity) {
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $DetailedTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
If ($ExcludePlugins -and $ExcludeSeverities) {
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUDEPLUGINS_EXCLUDESEVERITIES_USED
$ExportToXLSX = Import-Csv -Path $DetailedTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object { $PSItem.Plugin -NotIn $ExcludePlugins -and $PSItem.Severity -NotIn $ExcludeSeverities } | Select-Object *, 'Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludePlugins and ExcludeSeverity parameters check.
ElseIf ($ExcludePlugins) {
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUDEPLUGINS_USED
$ExportToXLSX = Import-Csv -Path $DetailedTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object Plugin -NotIn $ExcludePlugins | Select-Object *, 'Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludePlugins parameter check.
ElseIf ($ExcludeSeverities) {
Write-SCLog -LogInfo $local.REPC2X_LOG_EXCLUDESEVERITIES_USED
$ExportToXLSX = Import-Csv -Path $DetailedTMP1 -Delimiter "$TargetCSVDelimiter" | Where-Object Severity -NotIn $ExcludeSeverities | Select-Object *, 'Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # End of ExcludeSeverities parameter check.
} # ExcludePlugins or ExcludeSeverity: True.
Else {
$local.REPC2X_LOG_EXCLUSION_PARAMETERS_NOT_USED
# Import the modified CSV and export it to spreadsheet.
Write-SCLog -LogInfo $($local.REPC2X_LOG_IN_CSV_OUT_XLSX -f $DetailedTMP1, $TargetCSVDelimiter, $TargetXLSX, $TBLName, $WSName)
$ExportToXLSX = Import-Csv -Path $DetailedTMP1 -Delimiter "$TargetCSVDelimiter" | Select-Object *, 'Excluded' | Export-Excel -Path $TargetXLSX -WorkSheetname $WSName -TableName $TBLName -TableStyle Medium2 -FreezeTopRow -AutoSize -PassThru
} # ExcludePlugins and ExcludeSeverity: False. End of ExcludePlugins and/or ExcludeSeverity parameter(s) check.
# Save the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_SAVE_EXCEL_PACKAGE -f $Scope)
$ExportToXLSX.Save()
# Dispose of the Excel package.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DISPOSE_OF_PACKAGE -f $Scope)
$ExportToXLSX.Dispose()
# Checking if KeepTEMP parameter was used.
If (!$KeepTEMP) {
# Remove temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_REMOVE_TEMP_FILE -f $DetailedTMP1)
Remove-Item -Path $DetailedTMP1
} # KeepTEMP: False
Else {
# Or don't remove the temp file.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DONT_REMOVE_TEMP_FILE -f $DetailedTMP1)
} # KeepTEMP: True. End of KeepTEMP parameter check.
# Tell garbage collector to dump unnecessary stuff.
Write-SCLog -LogInfo $($local.REPC2X_LOG_DUMP_GARBAGE -f $Scope)
[GC]::Collect()
Write-SCLog -LogInfo $($local.REPC2X_LOG_SECTION_END -f $Scope)
#endregion
} # End of vulnerability parameter check.
} # End of parameter Switch.
} # End of Process.
End {
# Reset window title.
[Console]::Title = $DefaultPSWindowTitle
} # End of End.
} # End of Function ConvertFrom-SCReportCSV2XLSX.
Function Initialize-SCConnection {
<#
.SYNOPSIS
API connection support function.
Only to be used within the module.
.DESCRIPTION
Connects to Tenable SecurityCenter API using a username/password pair or username/encrypted file/key file combo.
Password is unencrypted!
.EXAMPLE
Use username and password:
Initialize-SCConnection -Username "SCUser" -Password "SCP@55w0rd."
.EXAMPLE
Use username, password file and Key File:
Initialize-SCConnection -Username "SCUser" -EncryptedPasswordPath "C:\Protected\Path\password.file" -KeyPath "C:\Protected\Path\key.file"
.EXAMPLE
Use username, password and turn certificate Validation Check off in case self signed, or otherwise invalid, but internally trusted certificate is used in SecurityCenter.
Initialize-SCConnection -Username "SCUser" -Password "SCP@55w0rd." -DisableCertificateCheck
.PARAMETER username
Enter SecurityCenter username.
.PARAMETER password
Enter SecurityCenter user password.
.PARAMETER EncryptedPasswordPath
Enter SecurityCenter user encrypted password File Path.
.PARAMETER KeyPath
Enter SecurityCenter user encrypted password File Key Path.
.PARAMETER DisableCertificateCheck
Turn off certificate Validation check.
.NOTES
Tenable.SC API does not support encrypted passwords, nor API keys.
.FUNCTIONALITY
Creates a connection to Tenable.SC's API.
#>
[CmdletBinding()]
Param(
[Parameter( Position = 0, Mandatory = $False, HelpMessage = { $local.INITCONN_HELP_USERNAME } )]
[String]$Username,
[Parameter( Position = 1, Mandatory = $False, ParameterSetName = 'Interactive', HelpMessage = { $local.INITCONN_HELP_PASSWORD } )]
[String]$Password,
[Parameter( Position = 2, Mandatory = $False, ParameterSetName = 'EncryptedPasswordFile', HelpMessage = { $local.INITCONN_HELP_ENCRYPTED_PASSWORD_FILE } )]
[ValidateScript( { Test-Path -Path $PSItem -PathType Leaf } )]
[String]$EncryptedPasswordPath,
[Parameter( Position = 3, Mandatory = $False, ParameterSetName = 'EncryptedPasswordFile', HelpMessage = { $local.INITCONN_HELP_ENCRYPTED_PASSWORD_KEY_FILE } )]
[ValidateScript( { Test-Path -Path $PSItem -PathType Leaf } )]
[String]$KeyPath,
[Parameter( Position = 4, Mandatory = $false, HelpMessage = { $local.INITCONN_HELP_DISABLE_CERTIFICATE_CHECK } )]
[Switch]$DisableCertificateCheck
)
Begin {
# Check if DisableCertificateCheck parameter was used.
If ($DisableCertificateCheck) {
# Disable SSL certificate validation. Necessary if server certificate is invalid, that includes self-signed certificates.
Write-SCLog -LogInfo $local.INITCONN_LOG_DISABLING_CERTIFICATE_CHECK
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
} # End of DisableCertificateCheck check.
# Set TLS version.
Write-SCLog -LogInfo $local.INITCONN_LOG_SET_TLS12
[System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Store server REST endpoint in a globally accessible variable.
$Global:Server = "https://$ServerFQDN/rest"
Write-SCLog -LogInfo $($local.INITCONN_LOG_SERVER_ADDRESS -f $Server)
} # End of Begin
Process {
# Checking if password parameter was used.
If ($Password) {
# Credentials with interactively entered password.
$Private:credentials = '{
"username" : "' + $Username + '",
"password" : "' + $Password + '",
"releaseSession" : "FALSE"
}'
Write-SCLog -LogInfo $($local.INITCONN_LOG_SET_CREDENTIALS -f ($credentials | ConvertFrom-Json).releaseSession)
} # Username and password: True, logging in using interactively entered credentials.
Else {
# Decrypt password from a file specified in EncryptedPasswordPath parameter.
Write-SCLog -LogInfo $($local.INITCONN_LOG_LOAD_ENCRYPTED_PASSWORD -f $EncryptedPasswordPath, $KeyPath)
$Private:LoadPassword = ConvertTo-SecureString -String (Get-Content -Path "$EncryptedPasswordPath") -Key (Get-Content -Path "$KeyPath")
Write-SCLog -LogInfo $local.INITCONN_LOG_DECRYPT_PASSWORD
$Private:Binary = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($LoadPassword)
$Private:Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Binary)
# Build JSON structured credential.
$Private:credentials = '{
"username" : "' + $Username + '",
"password" : "' + $Password + '",
"releaseSession" : "FALSE"
}'
Write-SCLog -LogInfo $($local.INITCONN_LOG_SET_CREDENTIALS -f ($credentials | ConvertFrom-Json).releaseSession)
# Check if the files are encrypted, pass the ACL checks, if yes.
Write-SCLog -LogInfo $($local.INITCONN_LOG_FILE_ENCRYPTION -f $EncryptedPasswordPath, $KeyPath)
$Private:Encryption = Get-ItemProperty -Path $EncryptedPasswordPath, $KeyPath | Select-Object -ExpandProperty Attributes
If ($Encryption[0] -notlike "*Encrypted*" -and $Encryption[1] -notlike "*Encrypted*") {
Write-SCLog -LogInfo ($local.INITCONN_LOG_FILES_NOT_ENCRYPTED -f $EncryptedPasswordPath, $KeyPath)
# Check if password encryption key is overprivileged.
Write-SCLog -LogInfo $($local.INITCONN_LOG_ENCRYPTED_FILE_VARIABLE -f $KeyPath)
$Private:KeyACL = Get-Acl -Path $KeyPath
Write-SCLog -LogInfo $($local.INITCONN_LOG_CHECK_ENCRYPTED_FILE_ACL -f $KeyPath)
If ($KeyACL.AccessToString.Contains('BUILTIN\Users') -or $KeyACL.AccessToString.Contains('NT AUTHORITY\Authenticated Users') -or $KeyACL.AccessToString.Contains('BUILTIN\Administrators')) {
Write-SCLog -LogInfo $($local.INITCONN_LOG_ENCRYPTED_FILE_ACL_WARNING -f $KeyPath)
Write-Warning -Message $($local.INITCONN_LOG_OVER_PRIVILEGED_PASSWORD_FILES -f $KeyPath)
} # End of KeyACL ACL check.
# Check if password file is overprivileged.
Write-SCLog -LogInfo $($local.INITCONN_LOG_ENCRYPTED_FILE_VARIABLE -f $EncryptedPasswordPath)
$Private:PWDFileACL = Get-Acl -Path $EncryptedPasswordPath
Write-SCLog -LogInfo $($local.INITCONN_LOG_CHECK_ENCRYPTED_FILE_ACL -f $EncryptedPasswordPath)
If ($PWDFileACL.AccessToString.Contains('BUILTIN\Users') -or $PWDFileACL.AccessToString.Contains('NT AUTHORITY\Authenticated Users') -or $PWDFileACL.AccessToString.Contains('BUILTIN\Administrators')) {
Write-SCLog -LogInfo $($local.INITCONN_LOG_ENCRYPTED_FILE_ACL_WARNING -f $EncryptedPasswordPath)
Write-Warning -Message $($local.INITCONN_LOG_OVER_PRIVILEGED_PASSWORD_FILES -f $EncryptedPasswordPath)
} # End of PWDFileACL ACL check.
} # Password and key files are not encrypted.
Else {
Write-SCLog -LogInfo ($local.INITCONN_LOG_FILES_ENCRYPTED -f $EncryptedPasswordPath, $KeyPath)
} # Password and key files are encrypted. End of files encryption check.
} # Username and password: False, logging in using password file.
# Start a session and make it globally available.
$Global:StartSession = Invoke-RestMethod -Method POST -Uri "$Server/token" -SessionVariable SCSession -Body $credentials -ContentType 'application/json' -Headers @{ 'HTTP' = 'X-SecurityCenter' }
Write-SCLog -LogInfo $($local.INITCONN_LOG_NEW_CONNECTION -f $Server, $StartSession.response.token)
# Make session variable globally available.
Write-SCLog -LogInfo $local.INITCONN_LOG_SESSION_VARIABLE
$Global:SCSession = $SCSession
}
End {
# If a password variable was not set, destroy binary string and password variables.
If (!$Password) {
Write-SCLog -LogInfo $local.INITCONN_LOG_OVERWRITE_DECRYPTED_PASSWORD
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($Binary)
Write-SCLog -LogInfo $local.INITCONN_LOG_REMOVE_PASSWORD_VARIABLE
Remove-Variable -Name password
} # End of password variable check.
# Destroy credentials variables in any case.
Write-SCLog -LogInfo $local.INITCONN_LOG_REMOVE_CREDENTIALS_VARIABLE
Remove-Variable -Name credentials -ErrorAction SilentlyContinue
Write-SCLog -LogInfo $local.INITCONN_LOG_REMOVE_USERNAME_VARIABLE
Remove-Variable -Name username -ErrorAction SilentlyContinue
}
} # End of Function Initialize-SCConnection.
Function Get-SCCurrentUser {
<#
.SYNOPSIS
Show currently logged in user.
.DESCRIPTION
Shows Currently logged in user username.
.FUNCTIONALITY
Show Currently logged in user username.
#>
[CmdletBinding()]
Param()
# Get current user.
$Method = 'GET'
$URI = "$Server/currentUser?fields=username"
Write-SCLog -LogInfo $($local.GETCURRENT_USER_LOG_USERNAME_GET_DATA -f $Method, $URI)
$User = Invoke-RestMethod -Method $Method -Uri $URI -WebSession $SCSession -Headers @{ 'X-SecurityCenter' = $StartSession.response.token } -ContentType 'application/json'
# Output current username.
Write-SCLog -LogInfo $local.GETCURRENT_USER_LOG_OUTPUT_USERNAME
Write-Output -InputObject $User.response.username
} # End of Function Get-SCCurrentUser.
Function Get-SCActivePluginFeedStatus {
<#
.SYNOPSIS
Show active plugin feed status.
.DESCRIPTION
Shows active type plugin's feed status.
.NOTES
Output is formatted as table with autoSize parameter.
.FUNCTIONALITY
Shows current active plugin feed status.
#>
[CmdletBinding()]
Param()
Begin {
# Show running cmdlet in window title.
[Console]::Title = $($local.INFO_TITLE_RUNNING_CMDLET -f $MyInvocation.MyCommand)
# Connect to Tenable.SC.
$User = 'testuser'
$PasswordFile = ''
$KeyFile = ''
Write-SCLog -LogInfo $($local.LOG_INIT_NEW_CONN -f $Server, $User, $PasswordFile, $KeyFile)
} # End of Begin.
Process {
Initialize-SCConnection -Username $User -EncryptedPasswordPath $PasswordFile -KeyPath $KeyFile
# Show current user and context.
Write-Host -ForegroundColor Yellow -Object $($local.INFO_LOGGED_IN -f $(Get-SCCurrentUser), $MyInvocation.MyCommand)
$Method = 'GET'
$URI = "$Server/feed/active"
Write-SCLog -LogInfo $($local.GETACTIVEPLUGINFEED_LOG_STATUS_GET_DATA -f $Method, $URI)
# Get feed update status.
$FeedStatus = Invoke-RestMethod -Method $Method -Uri $URI -WebSession $SCSession -Headers @{ 'X-SecurityCenter' = $StartSession.response.token } -ContentType 'application/json'
# Create a custom table of active plugin feed status contents.
Write-SCLog -LogInfo $($local.LOG_CUSTOM_OUTPUT_TABLE -f 'Active Plugin Feed Status')
$FeedTable = New-Object PSObject
Add-Member -InputObject $FeedTable -MemberType NoteProperty -Name $local.GETACTIVEPLUGINFEED_STATUS_UPTIME -Value (ConvertFrom-EpochToNormal -InputEpoch $FeedStatus.response.updateTime)
Add-Member -InputObject $FeedTable -MemberType NoteProperty -Name $local.GETACTIVEPLUGINFEED_STATUS_STALE -Value $Culture.ToTitleCase($FeedStatus.response.stale)
Add-Member -InputObject $FeedTable -MemberType NoteProperty -Name $local.GETACTIVEPLUGINFEED_STATUS_UPDATE_RUNNING -Value $Culture.ToTitleCase($FeedStatus.response.updateRunning)
# Output active plugin feed status data.
Write-SCLog -LogInfo $($local.LOG_OUTPUT_DATA -f 'Active Plugin Feed Status')
Write-Output -InputObject $FeedTable
} # End of Process.
End {
# Reset window title.
[Console]::Title = $DefaultPSWindowTitle
} # End of End.
} # End of Function Get-SCActivePluginFeedStatus.
Function Initialize-SCActivePluginFeedUpdate {
<#
.SYNOPSIS
Start active plugin feed update.
.DESCRIPTION
Initializes active type plugin's feed update.
.FUNCTIONALITY
Forces active type plugin feed update. This happens once a day by default.
#>
[CmdletBinding()]
Param()
Begin {
# Show running cmdlet in window title.
[Console]::Title = $($local.INFO_TITLE_RUNNING_CMDLET -f $MyInvocation.MyCommand)
# Connect to Tenable.SC.
$User = 'testuser'
$PasswordFile = ''
$KeyFile = ''
Write-SCLog -LogInfo $($local.LOG_INIT_NEW_CONN -f $Server, $User, $PasswordFile, $KeyFile)
} # End of Begin.
Process {
Initialize-SCConnection -Username $User -EncryptedPasswordPath $PasswordFile -KeyPath $KeyFile
# Show current user and context.
Write-Host -ForegroundColor Yellow -Object $($local.INFO_LOGGED_IN -f $(Get-SCCurrentUser), $MyInvocation.MyCommand)
$Method = 'POST'
$URI = "$Server/feed/active/update"
Write-SCLog -LogInfo $($local.INIT_APFEED_UPDATE_LOG -f $Method, $URI)
# Start active feed update.
Invoke-RestMethod -Method $Method -Uri $URI -WebSession $SCSession -Headers @{ 'X-SecurityCenter' = $StartSession.response.token } -ContentType 'application/json'
Write-Output -InputObject $local.INIT_APFEED_UPDATE_INFO_UPDATE_INITIATED
} # End of Process.
End {
# Reset window title.
[Console]::Title = $DefaultPSWindowTitle
} # End of End.
} # End of Function Initialize-SCActivePluginFeedUpdate.
Function Get-SCPlugin {
<#
.SYNOPSIS
Get plugin info.
.DESCRIPTION
Gets a specific plugin info.
.EXAMPLE
Get Kubernetes Web API Detection, which has an ID of 121471.
Get-SCPlugin -ID 121471
.EXAMPLE
Same as above, but a bit more detailed output.
Get-SCPlugin -ID 121471 -Detailed
.PARAMETER ID
Enter plugin ID.
.PARAMETER Detailed
Show more detailed output of the specified plugin.
.EXAMPLE
Show scans in an unformatted, less readable format. Use this if you want the output to look the way you want it, as you cannot format an output that has been already formatted.
This is also necessary if you want to export the output.
Get-SCPlugin -RAW
.PARAMETER ID
ID of the plugin.
.PARAMETER Detailed
Shows more detailed view of the plugin.
.PARAMETER RAW
Show unformatted output.
.FUNCTIONALITY
Shows plugin info.
#>
[CmdletBinding( DefaultParameterSetName = 'Default' )]
Param(
[Parameter( Position = 0, Mandatory = $True, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGIN_HELP_PLUGIN_ID }, ValueFromPipelineByPropertyName )]
[Int]$ID,
[Parameter( Position = 1, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.HELP_DETAILED } )]
[Switch]$Detailed,
[Parameter( Position = 2, Mandatory = $False, ParameterSetName = 'RAW', HelpMessage = { $local.HELP_RAW_OUTPUT } )]
[Switch]$RAW
)
Begin {
# Show running cmdlet in window Title.
[Console]::Title = $($local.INFO_TITLE_RUNNING_CMDLET -f $MyInvocation.MyCommand)
# Connect to Tenable.SC.
$User = 'testuser'
$PasswordFile = ''
$KeyFile = ''
Write-SCLog -LogInfo $($local.LOG_INIT_NEW_CONN -f $Server, $User, $PasswordFile, $KeyFile)
} # End of Begin.
Process {
Initialize-SCConnection -Username $User -EncryptedPasswordPath $PasswordFile -KeyPath $KeyFile
# Show current user and context.
Write-Host -ForegroundColor Yellow -Object $($local.INFO_LOGGED_IN -f $(Get-SCCurrentUser), $MyInvocation.MyCommand)
# Get plugin data.
$Method = 'GET'
$URI = "$Server/plugin/$ID"
Write-SCLog -LogInfo $($local.GETPLUGIN_LOG_GET_DATA -f $ID, $Method, $URI)
$Plugin = Invoke-RestMethod -Method $Method -Uri $URI -WebSession $SCSession -Headers @{ 'X-SecurityCenter' = $StartSession.response.token } -ContentType 'application/json'
# Store output table into variable.
If ($Detailed) {
Write-SCLog -LogInfo $local.GETPLUGIN_LOG_DETAILED_SWITCH
$OutputTable = $Plugin.response | Select-Object -Property `
@{ Name = $local.GETPLUGIN_TBL_ID; Expression = { $PSItem.id }},
@{ Name = $local.GETPLUGIN_TBL_NAME; Expression = { $PSItem.name }},
@{ Name = $local.GETPLUGIN_TBL_DESCRIPTION; Expression = { $PSItem.description }},
@{ Name = $local.GETPLUGIN_TBL_SOLUTION; Expression = { $PSItem.solution }},
@{ Name = $local.GETPLUGIN_TBL_SYNOPSIS; Expression = { $PSItem.synopsis }},
@{ Name = $local.GETPLUGIN_TBL_TCP_PORTS; Expression = { $PSItem.requiredPorts }},
@{ Name = $local.GETPLUGIN_TBL_UDP_PORTS; Expression = { $PSItem.requiredUDPPorts }},
@{ Name = $local.GETPLUGIN_TBL_PLUGIN_FILE; Expression = { $PSItem.sourceFile }},
@{ Name = $local.GETPLUGIN_TBL_DEPENDENCIES; Expression = { $PSItem.dependencies }},
@{ Name = $local.GETPLUGIN_TBL_RISK_FACTOR; Expression = { $PSItem.riskFactor }},
@{ Name = $local.GETPLUGIN_TBL_VPR_SCORE; Expression = { $PSItem.vprScore }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_VULNERABILITY_AGE; Expression = { $PSItem.vprContext.value[0] }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_CVSSV3_IMPACT_SCORE; Expression = { ([math]::Round($PSItem.vprContext.value[1],1)) }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_EXPLOIT_CODE_MATURITY; Expression = { $PSItem.vprContext.value[2] }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_PRODUCT_COVERAGE; Expression = { $PSItem.vprContext.value[3] }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_THREAT_INTENSITY; Expression = { $PSItem.vprContext.value[4] }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_THREAT_RECENCY; Expression = { $PSItem.vprContext.value[5] }},
@{ Name = $local.GETPLUGIN_TBL_VPR_CONTEXT_THREAT_SOURCES; Expression = { $PSItem.vprContext.value[6] }},
@{ Name = $local.GETPLUGIN_TBL_CVSSV3BASE; Expression = { $PSItem.cvssV3BaseScore }},
@{ Name = $local.GETPLUGIN_TBL_CVSSV3TEMPORAL; Expression = { $PSItem.cvssV3TemporalScore }},
@{ Name = $local.GETPLUGIN_TBL_CHECK_TYPE; Expression = { $Culture.ToTitleCase($PSItem.checkType) }},
@{ Name = $local.GETPLUGIN_TBL_EXPLOIT_AVAILABLE; Expression = { $Culture.ToTitleCase($PSItem.exploitAvailable) }},
@{ Name = $local.GETPLUGIN_TBL_PLUGIN_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.pluginPubDate }},
@{ Name = $local.GETPLUGIN_TBL_PATCH_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.patchPubDate }},
@{ Name = $local.GETPLUGIN_TBL_VULNERABILITY_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.vulnPubDate }},
@{ Name = $local.GETPLUGIN_TBL_REFERENCES; Expression = { ($PSItem.xrefs -replace ',', $NewLine -replace '.*CVE:','') }},
@{ Name = $local.GETPLUGIN_TBL_FAMILY; Expression = { $PSItem.family.name }},
@{ Name = $local.GETPLUGIN_TBL_HASH; Expression = { $PSItem.md5 }}
} # Detailed check: True.
Else {
# Shorter output (Default).
Write-SCLog -LogInfo $local.LOG_DEFAULT
$OutputTable = $Plugin.response | Select-Object -Property `
@{ Name = $local.GETPLUGIN_TBL_ID; Expression = { $PSItem.id }},
@{ Name = $local.GETPLUGIN_TBL_NAME; Expression = { $PSItem.name }},
@{ Name = $local.GETPLUGIN_TBL_RISK_FACTOR; Expression = { $PSItem.riskFactor }},
@{ Name = $local.GETPLUGIN_TBL_VPR_SCORE; Expression = { $PSItem.vprScore }},
@{ Name = $local.GETPLUGIN_TBL_EXPLOIT_AVAILABLE; Expression = { $Culture.ToTitleCase($PSItem.exploitAvailable) }},
@{ Name = $local.GETPLUGIN_TBL_PLUGIN_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.pluginPubDate }},
@{ Name = $local.GETPLUGIN_TBL_PATCH_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.patchPubDate }},
@{ Name = $local.GETPLUGIN_TBL_VULNERABILITY_PUBLICATION_DATE; Expression = { ConvertFrom-EpochToNormal -InputEpoch $PSItem.vulnPubDate }},
@{ Name = $local.GETPLUGIN_TBL_REFERENCES; Expression = { ($PSItem.xrefs -replace ',', $NewLine -replace '.*CVE:','') }},
@{ Name = $local.GETPLUGIN_TBL_FAMILY; Expression = { $PSItem.family.name }}
} # Detailed check: False. End of Detailed parameter check.
Write-SCLog -LogInfo $($local.LOG_OUTPUT_DATA -f 'Plugin')
# Check if RAW parameter was used.
If ($RAW) {
# Display unformatted, unchanged raw data.
Write-SCLog -LogInfo $local.LOG_RAW_OUTPUT
Write-Output -InputObject $Plugin.response
} # RAW parameter was used.
Else {
# Output plugin data.
Write-Output -InputObject $OutputTable
} # Showing default View. End of RAW parameter check.
}
End {
# Reset window title.
[Console]::Title = $DefaultPSWindowTitle
}
} # End of Function Get-SCPlugin.
Function Get-SCPlugins {
<#
.SYNOPSIS
Get plugins listing.
.DESCRIPTION
Retrieves a list of plugins.
.EXAMPLE
Show plugins that contain a word "rootkit" in them.
Get-SCPlugins -PluginName "rootkit"
.EXAMPLE
Show plugins with plugin family name like "IoT".
Get-SCPlugins -FamilyName "IoT"
.EXAMPLE
Show plugins that have CVEs like "CVE-2019-7061".
Get-SCPlugins -CVE "CVE-2019-7061"
.EXAMPLE
Show certain types of plugins. We have mostly active plugins, so to list those:
Type parameter takes only active, passive, or compliance values. Use tab, to switch between them.
Get-SCPlugins -Type active
.EXAMPLE
Show plugins with specified severity.
Severity parameter takes only Critical, High, Info, Low, Medium values. Use tab, to switch between them.
Get-SCPlugins -Severity Critical
.EXAMPLE
Show plugins with exploits.
Exploitable parameter takes only True and False values (String, not Boolean variables). Use tab, to switch between them.
Get-SCPlugins -Exploitable True
.EXAMPLE
Limit the output.
Default output of 10000 has been set because that is somewhat reasonable time to wait. But that means that some of the data can and most probably will be left out.
By turning up the limit, the amount of time you have to wait and the amount of data you get, will be inversely proportional.
At the moment, there is no point going over 2000000, but by turning it to the max, you will have to wait quite a long time, regardless of how many actual matches you will get. In turn you will get all the data.
Get-SCPlugins -PluginName VLC -Limit 20000
.EXAMPLE
Combining parameters to get more specific output.
Find plugins for Adobe Flash, with critical severity, existing exploits and belong to one of the Windows plugin families.
Get-SCPlugins -PluginName flash -Severity Critical -Exploitable True -FamilyName Windows
.EXAMPLE
Show data as customized structure, but not formatted as table. This way the data is still presented nicely, but will be shown as a list, which will not be desired output with larger results.
This parameter is necessary if you want to pass the output to a pipeline, or if you want to export the data. By default, in this module, all the output is formatted as table.
Get-SCPlugins -PluginName Adobe -NoFormat
.EXAMPLE
Show plugins in an unformatted, less readable format. Use this if you want the output to look the way you want it, as you cannot format an output that has been already formatted, such as a Table.
This can also be used if you want to export the output, or send it to pipeline.
Get-SCPlugins -RAW
.PARAMETER PluginName
Filter output by plugin name.
.PARAMETER FamilyName
Filter output by plugin family name.
.PARAMETER CVE
Filter output by plugin CVE's.
.PARAMETER Type
Filter output by plugin type.
.PARAMETER Severity
Filter output by severity of the plugins.
.PARAMETER Exploitable
Filter output by (non-)exploitable plugins.
.PARAMETER Limit
Limit output length.
.PARAMETER NoFormat
Allow data to be customized, but don't format the output as table.
.PARAMETER RAW
Show unformatted output.
.FUNCTIONALITY
Shows plugins listings.
#>
[CmdletBinding( DefaultParameterSetName = 'Default' )]
Param(
[Parameter( Position = 0, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_PLUGIN_NAME } )]
[String]$PluginName,
[Parameter( Position = 1, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_PLUGIN_FAMILY_NAME } )]
[String]$FamilyName,
[Parameter( Position = 2, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_CVE } )]
[String]$CVE,
[Parameter( Position = 3, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_PLUGIN_TYPE } )]
[ValidateSet( 'active','all','compliance','custom','lce','notPassive','passive' )]
[String]$Type = 'active',
[Parameter( Position = 4, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_SEVERITY } )]
[ValidateSet( 'critical','high','info','low','medium' )]
[String]$Severity,
[Parameter( Position = 5, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_EXPLOITABLE } )]
[ValidateSet( 'false','true' )]
[String]$Exploitable,
[Parameter( Position = 6, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.GETPLUGINS_HELP_OUTPUTLIMIT } )]
[Int]$Limit,
[Parameter( Position = 7, Mandatory = $False, ParameterSetName = 'Default', HelpMessage = { $local.HELP_NO_FORMAT } )]
[Switch]$NoFormat,
[Parameter( Position = 8, Mandatory = $False, ParameterSetName = 'RAW', HelpMessage = { $local.HELP_RAW_OUTPUT } )]
[Switch]$RAW
)
Begin {
# Show running cmdlet in window title.
[Console]::Title = $($local.INFO_TITLE_RUNNING_CMDLET -f $MyInvocation.MyCommand)
# Connect to Tenable.SC.
$User = 'testuser'
$PasswordFile = ''
$KeyFile = ''
Write-SCLog -LogInfo $($local.LOG_INIT_NEW_CONN -f $Server, $User, $PasswordFile, $KeyFile)
} # End of Begin.
Process {
Initialize-SCConnection -Username $User -EncryptedPasswordPath $PasswordFile -KeyPath $KeyFile
# Show current user and context.
Write-Host -ForegroundColor Yellow -Object $($local.INFO_LOGGED_IN -f $(Get-SCCurrentUser), $MyInvocation.MyCommand)
# Checking if Limit parameter was used.
If (!$Limit) {
# By Default, only as many as your current Buffer Height permits, will be displayed. Either change the value in PS properties, or use the Limit parameter,
# but then the ones that go beyond the Buffer limit, will be clipped (first ones). Send the output to a file then instead, using the -NoFormat parameter.
Write-SCLog -LogInfo $local.LOG_BUFFER_HEIGHT_VARIABLE
$Limit = $BufferHeight
} # End of Limit parameter check.
# Get Plugins Data.
$Method = 'GET'
$URI = "$Server/plugin?fields=id,name,family,type,riskFactor,exploitAvailable,xrefs&filterField=type&op=eq&value=$Type&endOffset=$Limit"
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_GET_DATA -f $Method, $URI)
$Plugins = Invoke-RestMethod -Method $Method -Uri $URI -WebSession $SCSession -Headers @{ 'X-SecurityCenter' = $StartSession.response.token } -ContentType 'application/json'
# Generate output, depending on provided input.
#region Conditions
If ($PluginName -and $Severity -and $FamilyName -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_FNAME_PNAME_SEVERITY -f $Exploitable, $FamilyName, $PluginName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.family.name -like "*$FamilyName*" -and $PSItem.name -like "*$PluginName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $Severity -and $FamilyName) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_FNAME_PNAME_SEVERITY -f $FamilyName, $PluginName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.family.name -like "*$FamilyName*" -and $PSItem.name -like "*$PluginName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $Severity -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_PNAME_SEVERITY -f $Exploitable, $PluginName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.name -like "*$PluginName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $FamilyName -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_FNAME_PNAME -f $Exploitable, $FamilyName, $PluginName)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.family.name -like "*$FamilyName*" -and $PSItem.name -like "*$PluginName*" }
}
ElseIf ($FamilyName -and $Severity -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_FNAME_SEVERITY -f $Exploitable, $FamilyName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.family.name -like "*$FamilyName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($CVE -and $Severity -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_SEVERITY_XREFS -f $CVE, $Exploitable, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.xrefs -like "*$CVE*" -and $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $Severity) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_PNAME_SEVERITY -f $PluginName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.name -like "*$PluginName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $Type) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_PNAME_TYPE -f $PluginName, $Type)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.name -like "*$PluginName*" -and $PSItem.type -eq $Type }
}
ElseIf ($CVE -and $Severity) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_SEVERITY_XREFS -f $CVE, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.xrefs -like "*$CVE*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName -and $FamilyName) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_FNAME_PNAME -f $FamilyName, $PluginName)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.family.name -like "*$FamilyName*" -and $PSItem.name -like "*$PluginName*" }
}
ElseIf ($Severity -and $Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY_SEVERITY -f $Exploitable, $Severity )
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($FamilyName -and $Severity) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_FNAME_SEVERITY -f $FamilyName, $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.family.name -like "*$FamilyName*" -and $PSItem.riskFactor -eq $Severity }
}
ElseIf ($PluginName) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_PNAME -f $PluginName)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.name -like "*$PluginName*" }
}
ElseIf ($FamilyName) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_FNAME -f $FamilyName)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.family.name -like "*$FamilyName*" }
}
ElseIf ($CVE) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_XREFS -f $CVE)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.xrefs -like "*$CVE*" }
}
ElseIf ($Severity) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_SEVERITY -f $Severity)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.riskFactor -eq $Severity }
}
ElseIf ($Exploitable) {
Write-SCLog -LogInfo $($local.GETPLUGINS_LOG_EXPLOITABILITY -f $Exploitable)
$OutputHolder = $Plugins.response | Where-Object { $PSItem.exploitAvailable -eq $Exploitable }
}
Else {