mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
First version of subdomain takeover runbook
This commit is contained in:
@@ -30,7 +30,7 @@ CompanyName = 'Effectory B.V.'
|
||||
Copyright = '(c) Effectory B.V. - Jurjen Ladenius. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
# Description = ''
|
||||
Description = 'Functions to list, store, retrieve and check DNS bindings of resources that don''t exist anymore to prevent subdomain takeover.'
|
||||
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
# PowerShellVersion = ''
|
||||
@@ -51,7 +51,7 @@ Copyright = '(c) Effectory B.V. - Jurjen Ladenius. All rights reserved.'
|
||||
# ProcessorArchitecture = ''
|
||||
|
||||
# Modules that must be imported into the global environment prior to importing this module
|
||||
RequiredModules = @('Az.Accounts','Az.Websites','Az.FrontDoor','Az.Storage','Az.Cdn','Az.Network','Az.TrafficManager','Az.ContainerInstance')
|
||||
RequiredModules = @('Az.Accounts','Az.Websites','Az.FrontDoor','Az.Storage','Az.Cdn','Az.Network','Az.TrafficManager','Az.ContainerInstance','Az.Resources', 'DnsClient')
|
||||
|
||||
# Assemblies that must be loaded prior to importing this module
|
||||
# RequiredAssemblies = @()
|
||||
@@ -69,7 +69,7 @@ ScriptsToProcess = @('classes\*')
|
||||
# NestedModules = @()
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @('Get-EffectoryDomainResources','PerformDanglingDnsRecordsCheck','Set-BlobEffectoryDomainResources')
|
||||
FunctionsToExport = @('Get-EffectoryDomainResources','Set-BlobEffectoryDomainResources','Get-BlobEffectoryDomainResources', 'VerifyEffectoryDomainResources')
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = '*'
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
function DnsResolveHost {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $domainName,
|
||||
[Parameter(Mandatory)]
|
||||
[string] $effectoryDomainPattern,
|
||||
[Parameter()]
|
||||
[string] $externalDNSServer = "8.8.8.8"
|
||||
)
|
||||
|
||||
try {
|
||||
$CnameChain = resolve-dnsname -name $domainName -DnsOnly -Type A -NoHostsFile -Server $externalDNSServer -ErrorAction Ignore
|
||||
$CnameChain.Where({$_.NameHost -notlike $effectoryDomainPattern}, 'First').NameHost
|
||||
}
|
||||
catch {
|
||||
$null
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
function Get-BlobEffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Retrieves the stored domain resources list
|
||||
.DESCRIPTION
|
||||
Retrieves the newest domain resources list from the CSV in Azure storage.
|
||||
.PARAMETER connectionString
|
||||
Connection string of the storage account to retrieve from.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $connectionString
|
||||
)
|
||||
|
||||
[EffectoryDomainNameCheck[]] $loadedResources = @()
|
||||
$context = New-AzStorageContext -ConnectionString $connectionString
|
||||
|
||||
$blob = Get-AzStorageBlob -Container "dangling-dns" -Context $context | Sort-Object -Property Name | Select-Object -Last 1
|
||||
if ($null -ne $blob) {
|
||||
Get-AzStorageBlobContent -Context $context -CloudBlob $blob.ICloudBlob -Destination "$Env:temp/$($blob.Name).history.csv" -Force >$null
|
||||
$loadedResources = Import-CSV "$Env:temp/$($blob.Name).history.csv"
|
||||
Remove-Item -Path "$Env:temp/$($blob.Name).history.csv"
|
||||
}
|
||||
|
||||
$loadedResources
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# $context = New-AzStorageContext -ConnectionString "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
# Get-AzTrafficManagerProfile | Export-Csv "$Env:temp/test4.csv"
|
||||
# Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/test4.csv" -Blob "test2.csv" -Force >$null
|
||||
|
||||
# Get-AzStorageBlobContent -Context $context -Container "dangling-dns" -Blob "test2.csv" -Destination "$Env:temp/test3.csv" -Force
|
||||
# $foo = Import-CSV "$Env:temp/test3.csv"
|
||||
|
||||
# $foo
|
||||
@@ -1,134 +0,0 @@
|
||||
#Requires -Modules Az.Accounts,Az.Websites,Az.FrontDoor,Az.Storage,Az.Cdn,Az.Network,Az.TrafficManager,Az.ContainerInstance
|
||||
function Get-EffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Find resources in Azure that have DNS records
|
||||
.DESCRIPTION
|
||||
Gets all resources that have hostnames.
|
||||
.PARAMETER subscriptionId
|
||||
Optional Subscription Id to set the context to. Otherwise uses the current context.
|
||||
#>
|
||||
param(
|
||||
[Parameter()]
|
||||
[string] $subscriptionId
|
||||
)
|
||||
|
||||
# Initialize
|
||||
[EffectoryDomainNameCheck[]]$result = @()
|
||||
[string]$effectoryDomainPattern = "*.effectory.com"
|
||||
|
||||
# Get subscription info
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$currentContext = $null
|
||||
if (![string]::IsNullOrWhitespace($subscriptionId)) {
|
||||
$currentContext = Set-AzContext -SubscriptionId $subscriptionId
|
||||
}
|
||||
else {
|
||||
$currentContext = Get-AzContext
|
||||
$subscriptionId = $currentContext.Subscription
|
||||
}
|
||||
|
||||
Write-Host "Processing subscription $($currentContext.Name)"
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking WebApps and WebApp Slots for subscription $($currentContext.Name)"
|
||||
# $webApps = Get-AzWebApp
|
||||
# [int]$webAppCounter = 0
|
||||
# [int]$webAppSlotCounter = 0
|
||||
|
||||
# if ($null -ne $webApps) {
|
||||
# # check webapps
|
||||
# $itemsWebApps = CheckWebApps -subscription $currentContext -webApps $webApps -effectoryDomainPattern $effectoryDomainPattern
|
||||
# $webAppCounter += $itemsWebApps.Count
|
||||
# $result += $itemsWebApps
|
||||
|
||||
# # check webapp slots
|
||||
# foreach ($webApp in $webApps) {
|
||||
# $slot = Get-AzWebAppSlot -WebApp $webApp
|
||||
# if ($null -ne $slot) {
|
||||
# $itemsWebAppSlots = CheckWebApps -subscription $currentContext -webApps $slot -effectoryDomainPattern $effectoryDomainPattern
|
||||
# $webAppSlotCounter += $itemsWebAppSlots.Count
|
||||
# $result += $itemsWebAppSlots
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# Write-Host "Found $($webAppCounter) WebApps and $($webAppSlotsCounter) WebApp Slots for subscription $($currentContext.Name)"
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
Write-Host "Checking FrontDoor Endpoints for subscription $($currentContext.Name)"
|
||||
$frontDoors = Get-AzFrontDoor
|
||||
[int]$frontDoorEndPointCounter = 0
|
||||
|
||||
if ($null -ne $frontDoors) {
|
||||
$itemsFrontDoors = CheckFrontDoorEndPoints -subscription $currentContext -frontDoors $frontDoors -effectoryDomainPattern $effectoryDomainPattern
|
||||
$frontDoorEndPointCounter += $itemsFrontDoors.Count
|
||||
$result += $itemsFrontDoors
|
||||
}
|
||||
Write-Host "Found $($frontDoorEndPointCounter) FrontDoor Endpoints for subscription $($currentContext.Name)"
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
Write-Host "Checking Storage Accounts for subscription $($currentContext.Name)"
|
||||
$storageAccounts = Get-AzStorageAccount | Where-Object { $_.CustomDomain.Name -like $effectoryDomainPattern } # storage accounts
|
||||
[int]$storageCounter = 0
|
||||
|
||||
if ($null -ne $storageAccounts) {
|
||||
$itemsStorage = CheckStorageAccounts -subscription $currentContext -storageAccounts $storageAccounts -effectoryDomainPattern $effectoryDomainPattern
|
||||
$storageCounter += $itemsStorage.Count
|
||||
$result += $itemsStorage
|
||||
}
|
||||
Write-Host "Found $($storageCounter) Storage Accounts for subscription $($currentContext.Name)"
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking Cdn Endpoints for subscription $($currentContext.Name)"
|
||||
# $cdnProfiles = Get-AzCdnProfile
|
||||
# [int]$cdnCounter = 0
|
||||
|
||||
# if ($null -ne $cdnProfiles) {
|
||||
# $itemsCdn = CheckCdnEndpoints -subscription $currentContext -cdnProfiles $cdnProfiles -effectoryDomainPattern $effectoryDomainPattern
|
||||
# $cdnCounter += $itemsCdn.Count
|
||||
# $result += $itemsCdn
|
||||
# }
|
||||
# Write-Host "Found $($cdnCounter) Cdn Endpoints for subscription $($currentContext.Name)"
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking public IP addresses for subscription $($currentContext.Name)"
|
||||
# $ipAddresses = Get-AzPublicIpAddress | Where-Object DnsSettings -ne $null | Where-Object { $_.DnsSettings.DomainNameLabel -ne "" }
|
||||
# [int]$ipCounter = 0
|
||||
|
||||
# if ($null -ne $ipAddresses) {
|
||||
# $itemsIpAddresses = CheckIpAddresses -subscription $currentContext -ipAddresses $ipAddresses -effectoryDomainPattern $effectoryDomainPattern
|
||||
# $ipCounter += $itemsIpAddresses.Count
|
||||
# $result += $itemsIpAddresses
|
||||
# }
|
||||
# Write-Host "Found $($ipCounter) public IP addresses for subscription $($currentContext.Name)"
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking Traffic Managers for subscription $($currentContext.Name)"
|
||||
# $trafficManagers = Get-AzTrafficManagerProfile
|
||||
# [int]$trafficManagerCounter = 0
|
||||
|
||||
# if ($null -ne $trafficManagers) {
|
||||
# $itemsTrafficManagers = CheckTrafficManagers -subscription $currentContext -trafficManagers $trafficManagers -effectoryDomainPattern $effectoryDomainPattern
|
||||
# $trafficManagerCounter += $itemsTrafficManagers.Count
|
||||
# $result += $itemsTrafficManagers
|
||||
# }
|
||||
# Write-Host "Found $($trafficManagerCounter) Traffic Managers for subscription $($currentContext.Name)"
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking Container groups for subscription $($currentContext.Name)"
|
||||
# $containerInstances = Get-AzContainerGroup
|
||||
|
||||
# if ($null -ne $containerInstances) {
|
||||
# throw "Container groups are not implemented yet."
|
||||
# }
|
||||
|
||||
# # ------------------------------------------------------------------------------------------------------------------
|
||||
# Write-Host "Checking API Management for subscription $($currentContext.Name)"
|
||||
# $apiManagementServices = Get-AzApiManagement
|
||||
|
||||
# if ($null -ne $apiManagementServices) {
|
||||
# throw "API Management services are not implemented yet."
|
||||
# }
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
$result
|
||||
}
|
||||
@@ -17,47 +17,22 @@ function Set-BlobEffectoryDomainResources {
|
||||
[string] $connectionString
|
||||
)
|
||||
|
||||
[string] $fileName = "$((Get-Date).ToString("yyyy-MM-dd hh-mm")) - resources.csv"
|
||||
[string] $fileName = "$((Get-Date).ToString("yyyy-MM-dd HH-mm-ss")) - resources.csv"
|
||||
Write-Host "Storing resources to $($fileName)"
|
||||
|
||||
$context = New-AzStorageContext -ConnectionString $connectionString
|
||||
|
||||
# move to history
|
||||
$blobs = Get-AzStorageBlob -Container "dangling-dns" -Context $context
|
||||
if ($null -ne $blobs) {
|
||||
foreach ($blob in $blobs) {
|
||||
Start-AzStorageBlobCopy -CloudBlob $blob.ICloudBlob -DestContainer "dangling-dns-history" -DestBlob $blob.Name -Context $context
|
||||
Remove-AzStorageBlob -Container "dangling-dns" -Blob $blob.Name -Context $context
|
||||
Start-AzStorageBlobCopy -CloudBlob $blob.ICloudBlob -DestContainer "dangling-dns-history" -DestBlob $blob.Name -Context $context -Force >$null
|
||||
Remove-AzStorageBlob -Container "dangling-dns" -Blob $blob.Name -Context $context -Force >$null
|
||||
}
|
||||
}
|
||||
|
||||
# store as current
|
||||
$effectoryResources | Export-Csv "$Env:temp/$($fileName)"
|
||||
Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/$($fileName)" -Blob $fileName -Force
|
||||
Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/$($fileName)" -Blob $fileName -Force >$null
|
||||
Remove-Item -Path "$Env:temp/$($fileName)"
|
||||
}
|
||||
|
||||
# function Get-BlobEffectoryDomainResources {
|
||||
# <#
|
||||
# .SYNOPSIS
|
||||
# -
|
||||
# .DESCRIPTION
|
||||
# -
|
||||
# .PARAMETER subscriptionId
|
||||
# -
|
||||
# #>
|
||||
|
||||
# [EffectoryDomainNameCheck[]] $effectoryResources
|
||||
|
||||
|
||||
# }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# $context = New-AzStorageContext -ConnectionString "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
# Get-AzTrafficManagerProfile | Export-Csv "$Env:temp/test4.csv"
|
||||
# Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/test4.csv" -Blob "test2.csv" -Force >$null
|
||||
|
||||
# Get-AzStorageBlobContent -Context $context -Container "dangling-dns" -Blob "test2.csv" -Destination "$Env:temp/test3.csv" -Force
|
||||
# $foo = Import-CSV "$Env:temp/test3.csv"
|
||||
|
||||
# $foo
|
||||
@@ -0,0 +1,50 @@
|
||||
function VerifyEffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Find resources in Azure that no longer exist, but have DNS records.
|
||||
.DESCRIPTION
|
||||
Gets all resources that have hostnames.
|
||||
.PARAMETER effectoryDomainPattern
|
||||
The domain pattern to look for when enumerating hosts, e.g. '*.effectory.com'
|
||||
.PARAMETER effectoryResources
|
||||
The resources that currently exist.
|
||||
.PARAMETER effectoryResourcesPrevious
|
||||
The resources that existed previously.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $effectoryDomainPattern,
|
||||
[Parameter(Mandatory)]
|
||||
[AllowNull()]
|
||||
[EffectoryDomainNameCheck[]] $effectoryResources,
|
||||
[Parameter(Mandatory)]
|
||||
[AllowNull()]
|
||||
[EffectoryDomainNameCheck[]] $effectoryResourcesPrevious
|
||||
)
|
||||
|
||||
[bool] $hasErrors = $false
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------
|
||||
Write-Information "Comparing found resources with previously stored resources to find records that should've been deleted."
|
||||
foreach ($oldResource in $effectoryResourcesPrevious) {
|
||||
$currentItem = $effectoryResources.Where({$_.DomainName -eq $oldResource.DomainName}, 'First')
|
||||
|
||||
if (($null -eq $currentItem) -or ($currentItem.Count -eq 0)) {
|
||||
# Host name no longer exists, so there should be no DNS record
|
||||
# check
|
||||
Write-Warning "Host name '$($oldResource.DomainName)' no longer exists. Checking DNS record for '$($oldResource.ResourceName)' ($($oldResource.ResourceType))."
|
||||
$CName = DnsResolveHost -domainName $oldResource.DomainName -effectoryDomainPattern $effectoryDomainPattern -externalDNSServer "8.8.8.8"
|
||||
if (($null -ne $CName) -and ($CName -ne "")) {
|
||||
Write-Error "Host name '$($oldResource.DomainName)' no longer exists, but found DNS record '$($CName)' for '$($oldResource.ResourceName)' ($($oldResource.ResourceType))."
|
||||
$hasErrors = $true
|
||||
}
|
||||
}
|
||||
elseif (($oldResource.ResourceName -ne $currentItem.ResourceName) -or ($oldResource.ResourceId -ne $currentItem.ResourceId)) {
|
||||
# found, but does not point to the same resource
|
||||
# verify the DNS record to make sure it points to this resource
|
||||
Write-Warning "Host name '$($oldResource.DomainName)' was found, but points to another resource. Assuming this was intentional."
|
||||
}
|
||||
}
|
||||
|
||||
$hasErrors
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
#
|
||||
# Module manifest for module 'Effectory.Dns'
|
||||
#
|
||||
# Generated by: Jurjen Ladenius
|
||||
#
|
||||
# Generated on: 8/11/2021
|
||||
#
|
||||
|
||||
@{
|
||||
|
||||
# Script module or binary module file associated with this manifest.
|
||||
RootModule = 'Effectory.Dns.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '0.0.1'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
|
||||
# ID used to uniquely identify this module
|
||||
GUID = '1e64644e-639c-47d1-8816-c0e48390a6a7'
|
||||
|
||||
# Author of this module
|
||||
Author = 'Jurjen Ladenius'
|
||||
|
||||
# Company or vendor of this module
|
||||
CompanyName = 'Effectory B.V.'
|
||||
|
||||
# Copyright statement for this module
|
||||
Copyright = '(c) Effectory B.V. - Jurjen Ladenius. All rights reserved.'
|
||||
|
||||
# Description of the functionality provided by this module
|
||||
Description = 'Functions to list, store, retrieve and check DNS bindings of resources that don''t exist anymore to prevent subdomain takeover.'
|
||||
|
||||
# Minimum version of the PowerShell engine required by this module
|
||||
# PowerShellVersion = ''
|
||||
|
||||
# Name of the PowerShell host required by this module
|
||||
# PowerShellHostName = ''
|
||||
|
||||
# Minimum version of the PowerShell host required by this module
|
||||
# PowerShellHostVersion = ''
|
||||
|
||||
# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# DotNetFrameworkVersion = ''
|
||||
|
||||
# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
|
||||
# ClrVersion = ''
|
||||
|
||||
# Processor architecture (None, X86, Amd64) required by this module
|
||||
# ProcessorArchitecture = ''
|
||||
|
||||
# Modules that must be imported into the global environment prior to importing this module
|
||||
RequiredModules = @('Az.Accounts','Az.Websites','Az.FrontDoor','Az.Storage','Az.Cdn','Az.Network','Az.TrafficManager','Az.ContainerInstance','Az.Resources', 'DnsClient')
|
||||
|
||||
# Assemblies that must be loaded prior to importing this module
|
||||
# RequiredAssemblies = @()
|
||||
|
||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||
ScriptsToProcess = @('classes\*')
|
||||
|
||||
# Type files (.ps1xml) to be loaded when importing this module
|
||||
# TypesToProcess = @()
|
||||
|
||||
# Format files (.ps1xml) to be loaded when importing this module
|
||||
# FormatsToProcess = @()
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
# NestedModules = @()
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @('Get-BlobEffectoryDomainResources','PerformDanglingDnsRecordsCheck','Set-BlobEffectoryDomainResources','VerifyEffectoryDomainResources')
|
||||
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = '*'
|
||||
|
||||
# Variables to export from this module
|
||||
VariablesToExport = '*'
|
||||
|
||||
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
|
||||
AliasesToExport = '*'
|
||||
|
||||
# DSC resources to export from this module
|
||||
# DscResourcesToExport = @()
|
||||
|
||||
# List of all modules packaged with this module
|
||||
# ModuleList = @()
|
||||
|
||||
# List of all files packaged with this module
|
||||
# FileList = @()
|
||||
|
||||
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
|
||||
PrivateData = @{
|
||||
|
||||
PSData = @{
|
||||
|
||||
# Tags applied to this module. These help with module discovery in online galleries.
|
||||
# Tags = @()
|
||||
|
||||
# A URL to the license for this module.
|
||||
# LicenseUri = ''
|
||||
|
||||
# A URL to the main website for this project.
|
||||
# ProjectUri = ''
|
||||
|
||||
# A URL to an icon representing this module.
|
||||
# IconUri = ''
|
||||
|
||||
# ReleaseNotes of this module
|
||||
# ReleaseNotes = ''
|
||||
|
||||
# Prerelease string of this module
|
||||
# Prerelease = ''
|
||||
|
||||
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
|
||||
# RequireLicenseAcceptance = $false
|
||||
|
||||
# External dependent modules of this module
|
||||
# ExternalModuleDependencies = @()
|
||||
|
||||
} # End of PSData hashtable
|
||||
|
||||
} # End of PrivateData hashtable
|
||||
|
||||
# HelpInfo URI of this module
|
||||
# HelpInfoURI = ''
|
||||
|
||||
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
|
||||
# DefaultCommandPrefix = ''
|
||||
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
#Region '.\classes\EffectoryDomainNameCheck.ps1' 0
|
||||
class EffectoryDomainNameCheck {
|
||||
[string] $SubscriptionId = ""
|
||||
[string] $SubscriptionName = ""
|
||||
[string] $ResourceId = ""
|
||||
[string] $ResourceGroupName = ""
|
||||
[string] $ResourceName = ""
|
||||
[string] $ResourceType = ""
|
||||
[string] $DomainName = ""
|
||||
[string] $Tag_Team = ""
|
||||
[string] $Tag_Product = ""
|
||||
[string] $Tag_Environment = ""
|
||||
[string] $Tag_Data = ""
|
||||
}
|
||||
#EndRegion '.\classes\EffectoryDomainNameCheck.ps1' 14
|
||||
#Region '.\private\CheckCdnEndpoints.ps1' 0
|
||||
function CheckCdnEndpoints() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Cdn.Models.Profile.PSProfile[]] $cdnProfiles,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
foreach($cdnProfile in $cdnProfiles) {
|
||||
$cdnEndPoints = Get-AzCdnEndpoint -ProfileName $cdnProfile.Name -ResourceGroupName $cdnProfile.ResourceGroupName
|
||||
foreach($cdnEndPoint in $cdnEndPoints) {
|
||||
$resource = Get-AzResource -ResourceId $cdnEndPoint.Id
|
||||
$cdnEffectory = Get-AzCdnCustomDomain -CdnEndpoint $cdnEndPoint | Where-Object HostName -Like $effectoryDomainPattern
|
||||
|
||||
foreach($cdn in $cdnEffectory) {
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $cdn.Id;
|
||||
ResourceName = $cdn.Name;
|
||||
ResourceType = $cdn.Type;
|
||||
ResourceGroupName = $cdn.ResourceGroupName;
|
||||
DomainName = $cdn.HostName;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
|
||||
#EndRegion '.\private\CheckCdnEndpoints.ps1' 40
|
||||
#Region '.\private\CheckFrontDoorEndPoints.ps1' 0
|
||||
function CheckFrontDoorEndPoints() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.FrontDoor.Models.PSFrontDoor[]] $frontDoors,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
foreach($frontDoor in $frontDoors) {
|
||||
$resource = Get-AzResource -ResourceId $frontDoor.Id
|
||||
|
||||
if ($endPointHostNames = $frontDoor.FrontendEndpoints | Where-Object HostName -like $effectoryDomainPattern) {
|
||||
foreach ($endPoint in $endPointHostNames) {
|
||||
# frontdoor
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $endPoint.Id;
|
||||
ResourceName = $endPoint.Name;
|
||||
ResourceType = $endPoint.Type;
|
||||
ResourceGroupName = $resource.ResourceGroupName;
|
||||
DomainName = $endPoint.HostName;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
} }
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
#EndRegion '.\private\CheckFrontDoorEndPoints.ps1' 37
|
||||
#Region '.\private\CheckIpAddresses.ps1' 0
|
||||
function CheckIpAddresses() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Network.Models.PSPublicIpAddress[]] $ipAddresses,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
# public ip => Assume binding if an IP has a domain name.
|
||||
|
||||
foreach($ipAddress in $ipAddresses) {
|
||||
$resource = Get-AzResource -ResourceId $ipAddress.Id
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $ipAddress.Id;
|
||||
ResourceName = $ipAddress.Name;
|
||||
ResourceType = $resource.ResourceType;
|
||||
ResourceGroupName = $resource.ResourceGroupName;
|
||||
DomainName = $ipAddress.DnsSettings.DomainNameLabel;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
#EndRegion '.\private\CheckIpAddresses.ps1' 34
|
||||
#Region '.\private\CheckStorageAccounts.ps1' 0
|
||||
function CheckStorageAccounts() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Management.Storage.Models.PSStorageAccount[]] $storageAccounts,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
foreach($storageAccount in $storageAccounts) {
|
||||
$resource = Get-AzResource -ResourceId $storageAccount.Id
|
||||
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $storageAccount.Id;
|
||||
ResourceName = $resource.Name;
|
||||
ResourceType = $resource.ResourceType;
|
||||
ResourceGroupName = $resource.ResourceGroupName;
|
||||
DomainName = $storageAccount.CustomDomain.Name;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
#EndRegion '.\private\CheckStorageAccounts.ps1' 33
|
||||
#Region '.\private\CheckTrafficManagers.ps1' 0
|
||||
function CheckTrafficManagers() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.TrafficManager.Models.TrafficManagerProfile[]] $trafficManagers,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
# traffic manager => Assume binding
|
||||
|
||||
foreach($trafficManager in $trafficManagers) {
|
||||
$resource = Get-AzResource -ResourceId $trafficManager.Id
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $trafficManager.Id;
|
||||
ResourceName = $trafficManager.Name;
|
||||
ResourceType = $resource.ResourceType;
|
||||
ResourceGroupName = $resource.ResourceGroupName;
|
||||
DomainName = $trafficManager.RelativeDnsName;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
#EndRegion '.\private\CheckTrafficManagers.ps1' 34
|
||||
#Region '.\private\CheckWebApps.ps1' 0
|
||||
function CheckWebApps() {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.WebApps.Models.PSSite[]] $webApps,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$effectoryDomainPattern
|
||||
)
|
||||
[EffectoryDomainNameCheck[]]$Result = @()
|
||||
|
||||
$webAppsEffectory = $webApps | Where-Object {@($_.HostNames) -like $effectoryDomainPattern}
|
||||
foreach ($webAppEffectory in $webAppsEffectory) {
|
||||
foreach ($hostName in $webAppEffectory.HostNames | Where-Object {$_ -like $effectoryDomainPattern}) {
|
||||
$domainNameCheck = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $webAppEffectory.Id;
|
||||
ResourceName = $webAppEffectory.Name;
|
||||
ResourceType = $webAppEffectory.Type;
|
||||
ResourceGroupName = $webAppEffectory.ResourceGroup;
|
||||
DomainName = $hostName;
|
||||
Tag_Team = $webAppEffectory.Tags.team
|
||||
Tag_Product = $webAppEffectory.Tags.product
|
||||
Tag_Environment = $webAppEffectory.Tags.environment
|
||||
Tag_Data = $webAppEffectory.Tags.data
|
||||
}
|
||||
$Result += $domainNameCheck
|
||||
}
|
||||
}
|
||||
|
||||
$Result
|
||||
}
|
||||
#EndRegion '.\private\CheckWebApps.ps1' 34
|
||||
#Region '.\private\DnsResolveHost.ps1' 0
|
||||
function DnsResolveHost {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $domainName,
|
||||
[Parameter(Mandatory)]
|
||||
[string] $effectoryDomainPattern,
|
||||
[Parameter()]
|
||||
[string] $externalDNSServer = "8.8.8.8"
|
||||
)
|
||||
|
||||
try {
|
||||
$CnameChain = resolve-dnsname -name $domainName -DnsOnly -Type A -NoHostsFile -Server $externalDNSServer -ErrorAction Ignore
|
||||
$CnameChain.Where({$_.NameHost -notlike $effectoryDomainPattern}, 'First').NameHost
|
||||
}
|
||||
catch {
|
||||
$null
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#EndRegion '.\private\DnsResolveHost.ps1' 21
|
||||
#Region '.\private\GetDomainNameCheck.ps1' 0
|
||||
function GetDomainNameCheck () {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Commands.Profile.Models.Core.PSAzureContext]$subscription,
|
||||
[Parameter(Mandatory)]
|
||||
[Microsoft.Azure.Management.WebSites.Models.Resource] $resource
|
||||
)
|
||||
$Result = [EffectoryDomainNameCheck] @{
|
||||
SubscriptionId = $subscriptionId;
|
||||
SubscriptionName = $subscription.Name;
|
||||
ResourceId = $resource.Id;
|
||||
ResourceName = $resource.Name;
|
||||
ResourceType = $resource.Type;
|
||||
Tag_Team = $resource.Tags.team
|
||||
Tag_Product = $resource.Tags.product
|
||||
Tag_Environment = $resource.Tags.environment
|
||||
Tag_Data = $resource.Tags.data
|
||||
}
|
||||
|
||||
$Result;
|
||||
}
|
||||
#EndRegion '.\private\GetDomainNameCheck.ps1' 22
|
||||
#Region '.\public\Get-BlobEffectoryDomainResources.ps1' 0
|
||||
function Get-BlobEffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Retrieves the stored domain resources list
|
||||
.DESCRIPTION
|
||||
Retrieves the newest domain resources list from the CSV in Azure storage.
|
||||
.PARAMETER connectionString
|
||||
Connection string of the storage account to retrieve from.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $connectionString
|
||||
)
|
||||
|
||||
[EffectoryDomainNameCheck[]] $loadedResources = @()
|
||||
$context = New-AzStorageContext -ConnectionString $connectionString
|
||||
|
||||
$blob = Get-AzStorageBlob -Container "dangling-dns" -Context $context | Sort-Object -Property Name | Select-Object -Last 1
|
||||
if ($null -ne $blob) {
|
||||
Get-AzStorageBlobContent -Context $context -CloudBlob $blob.ICloudBlob -Destination "$Env:temp/$($blob.Name).history.csv" -Force >$null
|
||||
$loadedResources = Import-CSV "$Env:temp/$($blob.Name).history.csv"
|
||||
Remove-Item -Path "$Env:temp/$($blob.Name).history.csv"
|
||||
}
|
||||
|
||||
$loadedResources
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# $context = New-AzStorageContext -ConnectionString "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
# Get-AzTrafficManagerProfile | Export-Csv "$Env:temp/test4.csv"
|
||||
# Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/test4.csv" -Blob "test2.csv" -Force >$null
|
||||
|
||||
# Get-AzStorageBlobContent -Context $context -Container "dangling-dns" -Blob "test2.csv" -Destination "$Env:temp/test3.csv" -Force
|
||||
# $foo = Import-CSV "$Env:temp/test3.csv"
|
||||
|
||||
# $foo
|
||||
#EndRegion '.\public\Get-BlobEffectoryDomainResources.ps1' 40
|
||||
#Region '.\public\PerformDanglingDnsRecordsCheck.ps1' 0
|
||||
function PerformDanglingDnsRecordsCheck() {
|
||||
|
||||
[EffectoryDomainNameCheck[]]$current = @()
|
||||
[EffectoryDomainNameCheck[]]$previous = @()
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
Write-Host "RETRIEVING PREVIOUS DOMAIN RECSOURCES"
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
Write-Host "RETRIEVING CURRENT DOMAIN RECSOURCES"
|
||||
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||
|
||||
foreach ($subscription in $subscriptions)
|
||||
{
|
||||
$items = Get-EffectoryDomainResources -subscriptionId $subscription.Id
|
||||
$current = $current + $items
|
||||
}
|
||||
|
||||
$current
|
||||
}
|
||||
#EndRegion '.\public\PerformDanglingDnsRecordsCheck.ps1' 22
|
||||
#Region '.\public\Set-BlobEffectoryDomainResources.ps1' 0
|
||||
function Set-BlobEffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Stores the effectory domain resources list as csv in Azure storage.
|
||||
.DESCRIPTION
|
||||
Stores the effectory domain resources list as csv in Azure storage, while making a backup of the previous state.
|
||||
.PARAMETER effectoryResources
|
||||
Resources to be exported to CSV.
|
||||
.PARAMETER connectionString
|
||||
Connection string of the storage account to save to.
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[EffectoryDomainNameCheck[]] $effectoryResources,
|
||||
[Parameter(Mandatory)]
|
||||
[string] $connectionString
|
||||
)
|
||||
|
||||
[string] $fileName = "$((Get-Date).ToString("yyyy-MM-dd HH-mm-ss")) - resources.csv"
|
||||
Write-Host "Storing resources to $($fileName)"
|
||||
|
||||
$context = New-AzStorageContext -ConnectionString $connectionString
|
||||
|
||||
# move to history
|
||||
$blobs = Get-AzStorageBlob -Container "dangling-dns" -Context $context
|
||||
if ($null -ne $blobs) {
|
||||
foreach ($blob in $blobs) {
|
||||
Start-AzStorageBlobCopy -CloudBlob $blob.ICloudBlob -DestContainer "dangling-dns-history" -DestBlob $blob.Name -Context $context -Force >$null
|
||||
Remove-AzStorageBlob -Container "dangling-dns" -Blob $blob.Name -Context $context -Force >$null
|
||||
}
|
||||
}
|
||||
|
||||
# store as current
|
||||
$effectoryResources | Export-Csv "$Env:temp/$($fileName)"
|
||||
Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/$($fileName)" -Blob $fileName -Force >$null
|
||||
Remove-Item -Path "$Env:temp/$($fileName)"
|
||||
}
|
||||
#EndRegion '.\public\Set-BlobEffectoryDomainResources.ps1' 39
|
||||
#Region '.\public\VerifyEffectoryDomainResources.ps1' 0
|
||||
function VerifyEffectoryDomainResources {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Find resources in Azure that no longer exist, but have DNS records.
|
||||
.DESCRIPTION
|
||||
Gets all resources that have hostnames.
|
||||
.PARAMETER effectoryDomainPattern
|
||||
The domain pattern to look for when enumerating hosts, e.g. '*.effectory.com'
|
||||
.PARAMETER effectoryResources
|
||||
The resources that currently exist.
|
||||
.PARAMETER effectoryResourcesPrevious
|
||||
The resources that existed previously.
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $effectoryDomainPattern,
|
||||
[Parameter(Mandatory)]
|
||||
[AllowNull()]
|
||||
[EffectoryDomainNameCheck[]] $effectoryResources,
|
||||
[Parameter(Mandatory)]
|
||||
[AllowNull()]
|
||||
[EffectoryDomainNameCheck[]] $effectoryResourcesPrevious
|
||||
)
|
||||
|
||||
[bool] $hasErrors = $false
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------
|
||||
Write-Information "Comparing found resources with previously stored resources to find records that should've been deleted."
|
||||
foreach ($oldResource in $effectoryResourcesPrevious) {
|
||||
$currentItem = $effectoryResources.Where({$_.DomainName -eq $oldResource.DomainName}, 'First')
|
||||
|
||||
if (($null -eq $currentItem) -or ($currentItem.Count -eq 0)) {
|
||||
# Host name no longer exists, so there should be no DNS record
|
||||
# check
|
||||
Write-Warning "Host name '$($oldResource.DomainName)' no longer exists. Checking DNS record for '$($oldResource.ResourceName)' ($($oldResource.ResourceType))."
|
||||
$CName = DnsResolveHost -domainName $oldResource.DomainName -effectoryDomainPattern $effectoryDomainPattern -externalDNSServer "8.8.8.8"
|
||||
if (($null -ne $CName) -and ($CName -ne "")) {
|
||||
Write-Error "Host name '$($oldResource.DomainName)' no longer exists, but found DNS record '$($CName)' for '$($oldResource.ResourceName)' ($($oldResource.ResourceType))."
|
||||
$hasErrors = $true
|
||||
}
|
||||
}
|
||||
elseif (($oldResource.ResourceName -ne $currentItem.ResourceName) -or ($oldResource.ResourceId -ne $currentItem.ResourceId)) {
|
||||
# found, but does not point to the same resource
|
||||
# verify the DNS record to make sure it points to this resource
|
||||
Write-Warning "Host name '$($oldResource.DomainName)' was found, but points to another resource. Assuming this was intentional."
|
||||
}
|
||||
}
|
||||
|
||||
$hasErrors
|
||||
}
|
||||
#EndRegion '.\public\VerifyEffectoryDomainResources.ps1' 51
|
||||
@@ -5,27 +5,29 @@
|
||||
#Import-Module .\Output\Effectory.Dns\0.0.1\Effectory.Dns.psm1 -Force
|
||||
#Import-Module .\build\Effectory.Dns\0.0.1\Effectory.Dns.psm1 -Force
|
||||
|
||||
Start-Transcript -Path .\output.txt
|
||||
|
||||
Import-Module .\Effectory.Dns -Force
|
||||
|
||||
# $subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||
$connectionString = "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
|
||||
# foreach ($subscription in $subscriptions)
|
||||
# {
|
||||
# [Object[]]$result = @()
|
||||
# $items = Get-EffectoryDomainResources -subscriptionId $subscription.Id
|
||||
# $result = $result + $items
|
||||
# }
|
||||
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||
|
||||
# $result
|
||||
[EffectoryDomainNameCheck[]]$effectoryResources = @()
|
||||
|
||||
$effectoryResources = Get-EffectoryDomainResources -subscriptionId "a134faf1-7a89-4f2c-8389-06d00bd5e2a7"
|
||||
Set-BlobEffectoryDomainResources -effectoryResources $effectoryResources -connectionString "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
foreach ($subscription in $subscriptions)
|
||||
{
|
||||
$items = Get-EffectoryDomainResources -subscriptionId $subscription.Id -effectoryDomainPattern "*.effectory.com"
|
||||
$effectoryResources = $effectoryResources + $items
|
||||
}
|
||||
|
||||
# $context = New-AzStorageContext -ConnectionString "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
||||
# Get-AzTrafficManagerProfile | Export-Csv "$Env:temp/test4.csv"
|
||||
# Set-AzStorageBlobContent -Context $context -Container "dangling-dns" -File "$Env:temp/test4.csv" -Blob "test2.csv" -Force >$null
|
||||
#$effectoryResources = Get-EffectoryDomainResources -subscriptionId "a134faf1-7a89-4f2c-8389-06d00bd5e2a7" -effectoryDomainPattern "*.effectory.com"
|
||||
$effectoryResourcesPrevious = Get-BlobEffectoryDomainResources -connectionString $connectionString
|
||||
$result = VerifyEffectoryDomainResources -effectoryDomainPattern "*.effectory.com" -effectoryResources $effectoryResources -effectoryResourcesPrevious $effectoryResourcesPrevious
|
||||
Set-BlobEffectoryDomainResources -connectionString $connectionString -effectoryResources $effectoryResources
|
||||
|
||||
# Get-AzStorageBlobContent -Context $context -Container "dangling-dns" -Blob "test2.csv" -Destination "$Env:temp/test3.csv" -Force
|
||||
# $foo = Import-CSV "$Env:temp/test3.csv"
|
||||
if ($result -eq $true) {
|
||||
Write-Error ("FOUND ERRORS!")
|
||||
}
|
||||
|
||||
# $foo
|
||||
Stop-Transcript
|
||||
17
Powershell/RunBooks/SQLMaintenanceTemplate.ps1
Normal file
17
Powershell/RunBooks/SQLMaintenanceTemplate.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
$AzureSQLServerName = "xxxx"
|
||||
$AzureSQLDatabaseName = "yyyy"
|
||||
$SQLOutput = ""
|
||||
|
||||
try {
|
||||
$AzureSQLServerName = $AzureSQLServerName + ".database.windows.net"
|
||||
$Cred = Get-AutomationPSCredential -Name "SQLServerUser-AzureAutomation"
|
||||
$SQLOutput = $(Invoke-Sqlcmd -ServerInstance $AzureSQLServerName -Username $Cred.UserName -Password $Cred.GetNetworkCredential().Password -Database $AzureSQLDatabaseName -Query "exec [dbo].[AzureSQLMaintenance] @Operation='all' ,@LogToTable=1" -QueryTimeout 65535 -ConnectionTimeout 60 -Verbose) 4>&1
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Host $_
|
||||
throw "Error occured!"
|
||||
}
|
||||
finally {
|
||||
Write-Output $SQLOutput
|
||||
}
|
||||
89
Powershell/RunBooks/SubdomainTakeOverCheck.ps1
Normal file
89
Powershell/RunBooks/SubdomainTakeOverCheck.ps1
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
$effectoryDomainPattern = "*.effectory.com"
|
||||
|
||||
Import-Module Az.Accounts
|
||||
Import-Module Az.Websites
|
||||
Import-Module Az.FrontDoor
|
||||
Import-Module Az.Storage
|
||||
Import-Module Az.Cdn
|
||||
Import-Module Az.Network
|
||||
Import-Module Az.TrafficManager
|
||||
Import-Module Az.ContainerInstance
|
||||
Import-Module Az.Automation
|
||||
Import-Module Az.Resources
|
||||
Import-Module Effectory.Dns -Force
|
||||
Import-Module DnsClient
|
||||
|
||||
# --------------------------------------------------------- Connect to Azure
|
||||
$connectionName = "AzureRunAsConnection"
|
||||
try
|
||||
{
|
||||
# Get the connection "AzureRunAsConnection "
|
||||
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
|
||||
$account = Connect-AzAccount `
|
||||
-ServicePrincipal `
|
||||
-TenantId $servicePrincipalConnection.TenantId `
|
||||
-ApplicationId $servicePrincipalConnection.ApplicationId `
|
||||
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
|
||||
Write-Output ("Connected with Automation Account [$($account.Name)]")
|
||||
}
|
||||
catch {
|
||||
if (!$servicePrincipalConnection)
|
||||
{
|
||||
throw "Connection $($connectionName) not found."
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -Message $_.Exception
|
||||
throw $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- Get the connection string
|
||||
$connectionName = "RunbooksEffectory-StorageConnectionString"
|
||||
try
|
||||
{
|
||||
$Cred = Get-AutomationPSCredential -Name $connectionName
|
||||
$connectionString = $cred.GetNetworkCredential().Password
|
||||
Write-Output ("Retrieved connection string to Storage Account [$($cred.UserName)]")
|
||||
}
|
||||
catch {
|
||||
if (!$connectionString)
|
||||
{
|
||||
throw "Connection $($connectionName) not found."
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Error -Message $_.Exception
|
||||
throw $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
# --------------------------------------------------------------- Get the current resources
|
||||
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||
|
||||
[EffectoryDomainNameCheck[]]$effectoryResources = @()
|
||||
|
||||
foreach ($subscription in $subscriptions)
|
||||
{
|
||||
$items = Get-EffectoryDomainResources -subscriptionId $subscription.Id -effectoryDomainPattern $effectoryDomainPattern
|
||||
$effectoryResources = $effectoryResources + $items
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- Get and compare the previous resources to the current resources
|
||||
|
||||
$effectoryResourcesPrevious = Get-BlobEffectoryDomainResources -connectionString $connectionString
|
||||
$hasErrors = VerifyEffectoryDomainResources -effectoryDomainPattern $effectoryDomainPattern -effectoryResources $effectoryResources -effectoryResourcesPrevious $effectoryResourcesPrevious
|
||||
|
||||
if ($hasErrors -eq $false) {
|
||||
Set-BlobEffectoryDomainResources -connectionString $connectionString -effectoryResources $effectoryResources
|
||||
}
|
||||
else {
|
||||
throw "Found domains that could possibly be used for subdomain takeover. Check the log for details."
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error -Message $_.Exception
|
||||
throw $_.Exception
|
||||
}
|
||||
Reference in New Issue
Block a user