Skip to content

Commit

Permalink
New function: Export-AzSentinel (#121)
Browse files Browse the repository at this point in the history
* init code

* Release Export-AzSentinel and some small fixes/updates
  • Loading branch information
pkhabazi authored Oct 20, 2020
1 parent 46a8417 commit 94af32c
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 11 deletions.
1 change: 1 addition & 0 deletions AzSentinel/AzSentinel.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
'Get-AzSentinelAlertRuleTemplates',
'Add-AzSentinelIncidentComment',
'Get-AzSentinelDataConnector',
'Export-AzSentinel'
'Import-AzSentinelDataConnector'
)

Expand Down
182 changes: 182 additions & 0 deletions AzSentinel/Public/Export-AzSentinel.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
function Export-AzSentinel {
<#
.SYNOPSIS
Export Azure Sentinel
.DESCRIPTION
With this function you can export Azure Sentinel configuration
.PARAMETER SubscriptionId
Enter the subscription ID, if no subscription ID is provided then current AZContext subscription will be used
.PARAMETER WorkspaceName
Enter the Workspace name
.PARAMETER Kind
Select what you want to export: Alert, Hunting, Templates or All
.PARAMETER OutputFolder
The Path where you want to export the JSON files
.PARAMETER TemplatesKind
Select which Kind of templates you want to export, if empy all Templates will be exported
.EXAMPLE
Export-AzSentinel -WorkspaceName '' -Path C:\Temp\ -Kind All
In this example you export Alert, Hunting and Template rules
.EXAMPLE
Export-AzSentinel -WorkspaceName '' -Path C:\Temp\ -Kind Templates
In this example you export only the Templates
.EXAMPLE
Export-AzSentinel -WorkspaceName '' -Path C:\Temp\ -Kind Alert
In this example you export only the Scheduled Alert rules
#>

param (
[Parameter(Mandatory = $false,
ParameterSetName = "Sub")]
[ValidateNotNullOrEmpty()]
[string] $SubscriptionId,

[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$WorkspaceName,

[Parameter(Mandatory)]
[System.IO.FileInfo]$OutputFolder,

[Parameter(Mandatory,
ValueFromPipeline)]
[ExportType[]]$Kind,

[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[Kind[]]$TemplatesKind
)

begin {
precheck
}

process {
switch ($PsCmdlet.ParameterSetName) {
Sub {
$arguments = @{
WorkspaceName = $WorkspaceName
SubscriptionId = $SubscriptionId
}
}
default {
$arguments = @{
WorkspaceName = $WorkspaceName
}
}
}

$date = Get-Date -Format HHmmss_ddMMyyyy

<#
Test export path
#>
if (Test-Path $OutputFolder) {
Write-Verbose "Path Exists"
}
else {
try {
$null = New-Item -Path $OutputFolder -Force -ItemType Directory -ErrorAction Stop
}
catch {
$ErrorMessage = $_.Exception.Message
Write-Error $ErrorMessage
Write-Verbose $_
Break
}
}

<#
Export Alert rules section
#>
if (($Kind -like 'Alert') -or ($Kind -like 'All')) {

$rules = Get-AzSentinelAlertRule @arguments
if ($rules) {
$output = @{
Scheduled = @()
Fusion = @()
MLBehaviorAnalytics = @()
MicrosoftSecurityIncidentCreation = @()
}
$rules.Kind | ForEach-Object {
$output.$_ += $rules | Where-Object kind -eq $_
}

try {
$fullPath = "$($OutputFolder)AlertRules_$date.json"
$output | ConvertTo-Json -EnumsAsStrings -Depth 15 | Out-File $fullPath -ErrorAction Stop
Write-Output "Alert rules exported to: $fullPath"
}
catch {
$ErrorMessage = $_.Exception.Message
Write-Error $ErrorMessage
Write-Verbose $_
Break
}
}
}

<#
Export Hunting rules section
#>
if (($Kind -like 'Hunting') -or ($Kind -like 'All')) {
$rules = Get-AzSentinelHuntingRule @arguments

if ($rules) {
$output = @{
Hunting = @()
}
$output.Hunting += $rules
try {
$fullPath = "$($OutputFolder)HuntingRules_$date.json"
$output | ConvertTo-Json -EnumsAsStrings -Depth 15 | Out-File $fullPath -ErrorAction Stop
Write-Output "Hunting rules exported to: $fullPath"
}
catch {
$ErrorMessage = $_.Exception.Message
Write-Error $ErrorMessage
Write-Verbose $_
Break
}
}
}

<#
Export Templates section
#>
if (($Kind -like 'Templates') -or ($Kind -like 'All')) {

if ($TemplatesKind) {
$templates = Get-AzSentinelAlertRuleTemplates @arguments -Kind $TemplatesKind
}
else {
$templates = Get-AzSentinelAlertRuleTemplates @arguments
}

if ($templates) {
$output = @{
Scheduled = @()
Fusion = @()
MLBehaviorAnalytics = @()
MicrosoftSecurityIncidentCreation = @()
}
$templates.Kind | ForEach-Object {
$output.$_ += $templates | Where-Object kind -eq $_
}

try {
$fullPath = "$($OutputFolder)Templates_$date.json"
$output | ConvertTo-Json -EnumsAsStrings -Depth 15 | Out-File $fullPath -ErrorAction Stop
Write-Output "Templates xported to: $fullPath"
}
catch {
$ErrorMessage = $_.Exception.Message
Write-Error $ErrorMessage
Write-Verbose $_
Break
}
}
}
}
}
22 changes: 17 additions & 5 deletions AzSentinel/Public/Get-AzSentinelAlertRuleTemplates.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function Get-AzSentinelAlertRuleTemplates {
Write-Verbose -Message "Using URI: $($uri)"

try {
$alertRulesTemplates = Invoke-RestMethod -Uri $uri -Method Get -Headers $script:authHeader
$alertRulesTemplates = (Invoke-RestMethod -Uri $uri -Method Get -Headers $script:authHeader).value
}
catch {
Write-Verbose $_
Expand All @@ -70,16 +70,28 @@ function Get-AzSentinelAlertRuleTemplates {

$return = @()

if ($alertRulesTemplates.value) {
Write-Verbose "Found $($alertRulesTemplates.value.count) Alert rules templates"
if ($alertRulesTemplates) {
Write-Verbose "Found $($alertRulesTemplates.count) Alert rules templates"

if ($Kind) {
foreach ($item in $Kind) {
$return += $alertRulesTemplates.value | Where-Object Kind -eq $item
$alertRulesTemplates | Where-Object Kind -eq $item | ForEach-Object {
$_.properties | Add-Member -NotePropertyName name -NotePropertyValue $_.name -Force
$_.properties | Add-Member -NotePropertyName id -NotePropertyValue $_.id -Force
$_.properties | Add-Member -NotePropertyName kind -NotePropertyValue $_.kind -Force

$return += $_.properties
}
}
}
else {
$return += $alertRulesTemplates.value
$alertRulesTemplates | ForEach-Object {
$_.properties | Add-Member -NotePropertyName name -NotePropertyValue $_.name -Force
$_.properties | Add-Member -NotePropertyName id -NotePropertyValue $_.id -Force
$_.properties | Add-Member -NotePropertyName kind -NotePropertyValue $_.kind -Force

$return += $_.properties
}
}

return $return
Expand Down
17 changes: 12 additions & 5 deletions AzSentinel/Public/Import-AzSentinelHuntingRule.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,15 @@ function Import-AzSentinelHuntingRule {

if ($SettingsFile.Extension -eq '.json') {
try {
$analytics = (Get-Content $SettingsFile -Raw | ConvertFrom-Json -ErrorAction Stop).analytics
Write-Verbose -Message "Found $($analytics.count) rules"
$content = (Get-Content $SettingsFile -Raw | ConvertFrom-Json -ErrorAction Stop)
if ($content.analytics){
$hunting = $content.analytics
}
else {
$hunting = $content.Hunting
}

Write-Verbose -Message "Found $($hunting.count) rules"
}
catch {
Write-Verbose $_
Expand All @@ -75,8 +82,8 @@ function Import-AzSentinelHuntingRule {
}
elseif ($SettingsFile.Extension -in '.yaml', 'yml') {
try {
$analytics = [pscustomobject](Get-Content $SettingsFile -Raw | ConvertFrom-Yaml -ErrorAction Stop)
$analytics | Add-Member -MemberType NoteProperty -Name DisplayName -Value $analytics.name
$hunting = [pscustomobject](Get-Content $SettingsFile -Raw | ConvertFrom-Yaml -ErrorAction Stop)
$hunting | Add-Member -MemberType NoteProperty -Name DisplayName -Value $hunting.name
Write-Verbose -Message 'Found compatibel yaml file'
}
catch {
Expand All @@ -85,7 +92,7 @@ function Import-AzSentinelHuntingRule {
}
}

foreach ($item in $analytics) {
foreach ($item in $hunting) {
Write-Output "Started with Hunting rule: $($item.displayName)"

try {
Expand Down
Loading

0 comments on commit 94af32c

Please sign in to comment.