mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 18:52:18 +01:00
First importable
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
RootModule = 'Effectory.Dns.psm1'
|
RootModule = 'Effectory.Dns.psm1'
|
||||||
|
|
||||||
# Version number of this module.
|
# Version number of this module.
|
||||||
ModuleVersion = '0.0.1'
|
ModuleVersion = '0.0.3'
|
||||||
|
|
||||||
# Supported PSEditions
|
# Supported PSEditions
|
||||||
# CompatiblePSEditions = @()
|
# CompatiblePSEditions = @()
|
||||||
@@ -51,13 +51,13 @@ Description = 'Functions to list, store, retrieve and check DNS bindings of reso
|
|||||||
# ProcessorArchitecture = ''
|
# ProcessorArchitecture = ''
|
||||||
|
|
||||||
# Modules that must be imported into the global environment prior to importing this module
|
# 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')
|
RequiredModules = @('Az.Accounts','Az.Websites','Az.FrontDoor','Az.Storage','Az.Cdn','Az.Network','Az.TrafficManager','Az.ContainerInstance','Az.Resources', 'DnsClient-PS')
|
||||||
|
|
||||||
# Assemblies that must be loaded prior to importing this module
|
# Assemblies that must be loaded prior to importing this module
|
||||||
# RequiredAssemblies = @()
|
# RequiredAssemblies = @()
|
||||||
|
|
||||||
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
|
||||||
ScriptsToProcess = @('classes\*')
|
#WScriptsToProcess = @('*')
|
||||||
|
|
||||||
# Type files (.ps1xml) to be loaded when importing this module
|
# Type files (.ps1xml) to be loaded when importing this module
|
||||||
# TypesToProcess = @()
|
# TypesToProcess = @()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#Requires -Modules DnsClient-PS
|
||||||
function DnsResolveHost {
|
function DnsResolveHost {
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,8 +10,9 @@ function DnsResolveHost {
|
|||||||
)
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$CnameChain = resolve-dnsname -name $domainName -DnsOnly -Type A -NoHostsFile -Server $externalDNSServer -ErrorAction Ignore
|
|
||||||
$CnameChain.Where({$_.NameHost -notlike $effectoryDomainPattern}, 'First').NameHost
|
$CnameChain = Resolve-Dns -query $domainName -QueryType A -NameServer $externalDNSServer -ContinueOnDnsError -ContinueOnEmptyResponse
|
||||||
|
$CnameChain.AllRecords.Where({$_.DomainName.Value -notlike "$($effectoryDomainPattern)."}, 'First').DomainName.Value
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
$null
|
$null
|
||||||
|
|||||||
@@ -23,17 +23,4 @@ function Get-BlobEffectoryDomainResources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$loadedResources
|
$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
|
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#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(Mandatory)]
|
||||||
|
[string] $effectoryDomainPattern,
|
||||||
|
[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
|
||||||
|
}
|
||||||
@@ -1,21 +0,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
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -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.2'
|
||||||
|
|
||||||
|
# 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','Get-EffectoryDomainResources','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,536 @@
|
|||||||
|
#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
|
||||||
|
}
|
||||||
|
#EndRegion '.\public\Get-BlobEffectoryDomainResources.ps1' 27
|
||||||
|
#Region '.\public\Get-EffectoryDomainResources.ps1' 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(Mandatory)]
|
||||||
|
[string] $effectoryDomainPattern,
|
||||||
|
[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
|
||||||
|
}
|
||||||
|
#EndRegion '.\public\Get-EffectoryDomainResources.ps1' 137
|
||||||
|
#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
|
||||||
@@ -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.3'
|
||||||
|
|
||||||
|
# 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-PS')
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#WScriptsToProcess = @('*')
|
||||||
|
|
||||||
|
# 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','Get-EffectoryDomainResources','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,538 @@
|
|||||||
|
#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
|
||||||
|
#Requires -Modules DnsClient-PS
|
||||||
|
function DnsResolveHost {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $domainName,
|
||||||
|
[Parameter(Mandatory)]
|
||||||
|
[string] $effectoryDomainPattern,
|
||||||
|
[Parameter()]
|
||||||
|
[string] $externalDNSServer = "8.8.8.8"
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$CnameChain = Resolve-Dns -query $domainName -QueryType A -NameServer $externalDNSServer -ContinueOnDnsError -ContinueOnEmptyResponse
|
||||||
|
$CnameChain.AllRecords.Where({$_.DomainName.Value -notlike "$($effectoryDomainPattern)."}, 'First').DomainName.Value
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#EndRegion '.\private\DnsResolveHost.ps1' 23
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
#EndRegion '.\public\Get-BlobEffectoryDomainResources.ps1' 27
|
||||||
|
#Region '.\public\Get-EffectoryDomainResources.ps1' 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(Mandatory)]
|
||||||
|
[string] $effectoryDomainPattern,
|
||||||
|
[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
|
||||||
|
}
|
||||||
|
#EndRegion '.\public\Get-EffectoryDomainResources.ps1' 137
|
||||||
|
#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
|
||||||
Binary file not shown.
3357
Powershell/Modules/Effectory.Dns/output.txt
Normal file
3357
Powershell/Modules/Effectory.Dns/output.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,14 @@
|
|||||||
# .\build.ps1
|
# .\build.ps1
|
||||||
|
|
||||||
#Import-Module .\Output\Effectory.Dns\0.0.1\Effectory.Dns.psm1 -Force
|
#Import-Module .\Output\Effectory.Dns\0.0.1\Effectory.Dns.psm1 -Force
|
||||||
#Import-Module .\build\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
|
Start-Transcript -Path .\output.txt
|
||||||
|
|
||||||
Import-Module .\Effectory.Dns -Force
|
Import-Module .\Effectory.Dns -Force
|
||||||
|
|
||||||
$connectionString = "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=PIyewEcppMcm8imMhpUUOgrOUbWyFPK0o8PfdwPnEiNvEQqUvTDzjuV4W18z2sBuRzspGs5pV/Fz96umfePviw==;EndpointSuffix=core.windows.net"
|
$connectionString = "DefaultEndpointsProtocol=https;AccountName=runbookseffectory;AccountKey=QGi10UPphKRVehtiBhxca0XLaWZeg5woa5cTckS93NLECF1i4ggmAoEQiirz6JRyyOmDMwzjuZuef+0TgixwfA==;EndpointSuffix=core.windows.net"
|
||||||
|
|
||||||
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
$subscriptions = Get-AzSubscription | Where-Object State -eq "Enabled"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user