Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New function: Export-AzSentinel #121

Merged
merged 3 commits into from
Oct 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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