diff --git a/Automation/README.md b/Automation/README.md index cf8f0e2..8596a4d 100644 --- a/Automation/README.md +++ b/Automation/README.md @@ -4,7 +4,7 @@
-# Azure Resource Inventory Automation Account v3 +# Azure Resource Inventory Automation Account v4
@@ -52,7 +52,7 @@ Once you have created the Automation Account, Storage Account and Blob Container
-#### This will create an identity in the Azure AD. +#### This will create an identity in the Entra ID. ### Now we are going to use that identity to give the following permissions to the Automation Account: @@ -63,7 +63,7 @@ Once you have created the Automation Account, Storage Account and Blob Container

- +


@@ -77,7 +77,7 @@ Once you have created the Automation Account, Storage Account and Blob Container

- +


@@ -86,11 +86,10 @@ Once you have created the Automation Account, Storage Account and Blob Container ### Now, back in the Automation Account, the following Modules need to be imported with Runtime __7.2__: -#### 1) "ImportExcel" -#### 2) "Az.ResourceGraph" -#### 3) "Az.Storage" -#### 4) "Az.Account" -#### 5) "ThreadJob" +#### 1) "AzureResourceInventory" +#### 2) "ImportExcel" +#### 3) "Az.ResourceGraph" +#### 4) "ThreadJob"
@@ -103,7 +102,7 @@ Once you have created the Automation Account, Storage Account and Blob Container

- +


@@ -118,35 +117,35 @@ Once you have created the Automation Account, Storage Account and Blob Container

- +



-#### Then just copy the script content from __ARI_Automation.ps1__ +#### Then just add the "Invoke-ARI" command line inside the runbook.
-
+The line must contain the following parameters: -

- -

+```` +-TenantID +-SkipDiagram +-Automation +-StorageAccount +-StorageContainer +````
-
- -Remember to change the lines 33 and 36 with your Storage Account and Container name: - -
+The parameter "StorageAccount" is used to inform the Storage Account where the report will be placed and the "StorageContainer" parameter is used to pass the container within that Storage Account where the report will be placed.

- +

diff --git a/Automation/images/ARIAUT_ModuleImport.png b/Automation/images/ARIAUT_ModuleImport.png deleted file mode 100644 index f1e4953..0000000 Binary files a/Automation/images/ARIAUT_ModuleImport.png and /dev/null differ diff --git a/Automation/images/ARIAUT_RunBookScript.png b/Automation/images/ARIAUT_RunBookScript.png index 6e082ce..9f42b13 100644 Binary files a/Automation/images/ARIAUT_RunBookScript.png and b/Automation/images/ARIAUT_RunBookScript.png differ diff --git a/Automation/images/ARIAUT_StgAcc.png b/Automation/images/ARIAUT_StgAcc.png deleted file mode 100644 index bfaf09a..0000000 Binary files a/Automation/images/ARIAUT_StgAcc.png and /dev/null differ diff --git a/Automation/images/AUTv3Modules.png b/Automation/images/AUTv3Modules.png deleted file mode 100644 index c21335f..0000000 Binary files a/Automation/images/AUTv3Modules.png and /dev/null differ diff --git a/Automation/images/AUTv3Runbook.png b/Automation/images/AUTv3Runbook.png deleted file mode 100644 index 2058fa4..0000000 Binary files a/Automation/images/AUTv3Runbook.png and /dev/null differ diff --git a/Automation/images/AUTv3STGPerm.png b/Automation/images/AUTv3STGPerm.png deleted file mode 100644 index 75f61a8..0000000 Binary files a/Automation/images/AUTv3STGPerm.png and /dev/null differ diff --git a/Automation/images/AUTv3StorageName.png b/Automation/images/AUTv3StorageName.png deleted file mode 100644 index 401b2d9..0000000 Binary files a/Automation/images/AUTv3StorageName.png and /dev/null differ diff --git a/Automation/images/AUTv3Tenant.png b/Automation/images/AUTv3Tenant.png deleted file mode 100644 index 1d0f6b6..0000000 Binary files a/Automation/images/AUTv3Tenant.png and /dev/null differ diff --git a/Automation/images/AUTv4Modules.png b/Automation/images/AUTv4Modules.png new file mode 100644 index 0000000..0235d4f Binary files /dev/null and b/Automation/images/AUTv4Modules.png differ diff --git a/Automation/images/AUTv4Runbook.png b/Automation/images/AUTv4Runbook.png new file mode 100644 index 0000000..549685e Binary files /dev/null and b/Automation/images/AUTv4Runbook.png differ diff --git a/Automation/images/AUTv4STGPerm.png b/Automation/images/AUTv4STGPerm.png new file mode 100644 index 0000000..dae3ae0 Binary files /dev/null and b/Automation/images/AUTv4STGPerm.png differ diff --git a/Automation/images/AUTv4Tenant.png b/Automation/images/AUTv4Tenant.png new file mode 100644 index 0000000..b1ef849 Binary files /dev/null and b/Automation/images/AUTv4Tenant.png differ diff --git a/AzureResourceInventory.ps1 b/AzureResourceInventory.ps1 deleted file mode 100644 index 3c718f5..0000000 --- a/AzureResourceInventory.ps1 +++ /dev/null @@ -1,1682 +0,0 @@ -########################################################################################## -# # -# * Azure Resource Inventory ( ARI ) Report Generator * # -# # -# Version: 3.1.38 # -# # -# Date: 07/15/2024 # -# # -########################################################################################## -<# -.SYNOPSIS - This script creates Excel file to Analyze Azure Resources inside a Tenant - -.DESCRIPTION - Do you want to analyze your Azure Advisories in a table format? Document it in xlsx format. - -.PARAMETER TenantID - Specify the tenant ID you want to create a Resource Inventory. - - >>> IMPORTANT: YOU NEED TO USE THIS PARAMETER FOR TENANTS WITH MULTI-FACTOR AUTHENTICATION. <<< - -.PARAMETER SubscriptionID - Use this parameter to collect a specific Subscription in a Tenant - -.PARAMETER ManagementGroup - Use this parameter to collect a all Subscriptions in a Specific Management Group in a Tenant - -.PARAMETER Lite - Use this parameter to use only the Import-Excel module and don't create the charts (using Excel's API) - -.PARAMETER SecurityCenter - Use this parameter to collect Security Center Advisories - -.PARAMETER SkipAdvisory - Use this parameter to skip the capture of Azure Advisories - -.PARAMETER IncludeTags - Use this parameter to include Tags of every Azure Resources - -.PARAMETER Debug - Execute ASCI in debug mode. - -.EXAMPLE - Default utilization. Read all tenants you have privileges, select a tenant in menu and collect from all subscriptions: - PS C:\> .\AzureResourceInventory.ps1 - - Define the Tenant ID: - PS C:\> .\AzureResourceInventory.ps1 -TenantID - - Define the Tenant ID and for a specific Subscription: - PS C:\>.\AzureResourceInventory.ps1 -TenantID -SubscriptionID - -.NOTES - AUTHORS: Claudio Merola and Renato Gregio | Azure Infrastucture/Automation/Devops/Governance - -.LINK - Copyright (c) 2018 Microsoft Corporation. All rights reserved. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -#> - -param ($TenantID, - [switch]$SecurityCenter, - $SubscriptionID, - $ManagementGroup, - $Appid, - $Secret, - [string[]]$ResourceGroup, - $TagKey, - $TagValue, - [switch]$SkipAdvisory, - [switch]$SkipPolicy, - [switch]$IncludeTags, - [switch]$QuotaUsage, - [switch]$Online, - [switch]$Diagram, - [switch]$SkipDiagram, - [switch]$Lite, - [switch]$Debug, - [switch]$Help, - [switch]$DeviceLogin, - $AzureEnvironment, - [switch]$DiagramFullEnvironment, - $ReportName = 'AzureResourceInventory', - $ReportDir) - - if ($Debug.IsPresent) {$DebugPreference = 'Continue'} - - if ($Debug.IsPresent) {$ErrorActionPreference = "Continue" }Else {$ErrorActionPreference = "silentlycontinue" } - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Debbuging Mode: On. ErrorActionPreference was set to "Continue", every error will be presented.') - - if ($IncludeTags.IsPresent) { $Global:InTag = $true } else { $Global:InTag = $false } - - if ($Online.IsPresent) { $Global:RunOnline = $true }else { $Global:RunOnline = $false } - if ($Lite.IsPresent) { $Global:RunLite = $true }else { $Global:RunLite = $false } - if ($DiagramFullEnvironment.IsPresent) {$Global:FullEnv = $true}else{$Global:FullEnv = $false} - - $Global:SRuntime = Measure-Command -Expression { - - <######################################################### Help ######################################################################> - - Function usageMode() { - Write-Host "" - Write-Host "Parameters" - Write-Host "" - Write-Host " -TenantID : Specifies the Tenant to be inventoried. " - Write-Host " -SubscriptionID : Specifies Subscription(s) to be inventoried. " - Write-Host " -ResourceGroup : Specifies one (or more) unique Resource Group to be inventoried, This parameter requires the -SubscriptionID to work. " - Write-Host " -TagKey : Specifies the tag key to be inventoried, This parameter requires the -SubscriptionID to work. " - Write-Host " -TagValue : Specifies the tag value be inventoried, This parameter requires the -SubscriptionID to work. " - Write-Host " -SkipAdvisory : Do not collect Azure Advisory. " - Write-Host " -SkipPolicy : Do not collect Azure Policies. " - Write-Host " -SecurityCenter : Include Security Center Data. " - Write-Host " -IncludeTags : Include Resource Tags. " - Write-Host " -Online : Use Online Modules. " - Write-Host " -Debug : Run in a Debug mode. " - Write-Host " -AzureEnvironment : Change the Azure Cloud Environment. " - Write-Host " -ReportName : Change the Default Name of the report. " - Write-Host " -ReportDir : Change the Default Path of the report. " - Write-Host "" - Write-Host "" - Write-Host "" - Write-Host "Usage Mode and Examples: " - Write-Host "For CloudShell:" - Write-Host "e.g. />./AzureResourceInventory.ps1" - Write-Host "" - Write-Host "For PowerShell Desktop:" - Write-Host "" - Write-Host "If you do not specify Resource Inventory will be performed on all subscriptions for the selected tenant. " - Write-Host "e.g. />./AzureResourceInventory.ps1" - Write-Host "" - Write-Host "To perform the inventory in a specific Tenant and subscription use <-TenantID> and <-SubscriptionID> parameter " - Write-Host "e.g. />./AzureResourceInventory.ps1 -TenantID -SubscriptionID " - Write-Host "" - Write-Host "Including Tags:" - Write-Host " By Default Azure Resource inventory do not include Resource Tags." - Write-Host " To include Tags at the inventory use <-IncludeTags> parameter. " - Write-Host "e.g. />./AzureResourceInventory.ps1 -TenantID -IncludeTags" - Write-Host "" - Write-Host "Skipping Azure Advisor:" - Write-Host " By Default Azure Resource inventory collects Azure Advisor Data." - Write-Host " To ignore this use <-SkipAdvisory> parameter. " - Write-Host "e.g. />./AzureResourceInventory.ps1 -TenantID -SubscriptionID -SkipAdvisory" - Write-Host "" - Write-Host "Using the latest modules :" - Write-Host " You can use the latest modules. For this use <-Online> parameter." - Write-Host " It's a pre-requisite to have internet access for ARI GitHub repo" - Write-Host "e.g. />./AzureResourceInventory.ps1 -TenantID -Online" - Write-Host "" - Write-Host "Running in Debug Mode :" - Write-Host " To run in a Debug Mode use <-Debug> parameter." - Write-Host ".e.g. />/AzureResourceInventory.ps1 -TenantID -Debug" - Write-Host "" - } - - Function Variables { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Cleaning default variables') - $Global:ResourceContainers = @() - $Global:Resources = @() - $Global:Advisories = @() - $Global:Security = @() - $Global:Policies = @() - $Global:Subscriptions = '' - $Global:ReportName = $ReportName - - $Global:Repo = 'https://api.github.com/repos/microsoft/ari/git/trees/main?recursive=1' - $Global:RawRepo = 'https://raw.githubusercontent.com/microsoft/ARI/main' - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if -Online parameter will have to be forced.') - if(!$Online.IsPresent) - { - if($PSScriptRoot -like '*\*') - { - $LocalFilesValidation = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Subscriptions.ps1') - } - else - { - $LocalFilesValidation = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Subscriptions.ps1') - } - if([string]::IsNullOrEmpty($LocalFilesValidation)) - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Using -Online by force.') - $Global:RunOnline = $true - } - else - { - $Global:RunOnline = $false - } - } - - } - - <######################################################### Environment ######################################################################> - - Function Extractor { - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Extractor function') - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Powershell Edition: ' + ([string]$psversiontable.psEdition)) - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Powershell Version: ' + ([string]$psversiontable.psVersion)) - function checkAzCli() { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting checkAzCli function') - Write-Host "Validating Az Cli.." - $azcli = az --version - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Current az cli version: ' + $azcli[0]) - if ($null -eq $azcli) { - Read-Host "Azure CLI Not Found. Press to finish script" - Exit - } - Write-Host "Validating Az Cli Extension.." - $azcliExt = az extension list --output json | ConvertFrom-Json - $azcliExt = $azcliExt | Where-Object {$_.name -eq 'resource-graph'} - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Current Resource-Graph Extension Version: ' + $azcliExt.version) - $AzcliExtV = $azcliExt | Where-Object {$_.name -eq 'resource-graph'} - if (!$AzcliExtV) { - Write-Host "Adding Az Cli Extension" - az extension add --name resource-graph - } - Write-Host "Validating ImportExcel Module.." - $VarExcel = Get-InstalledModule -Name ImportExcel -ErrorAction silentlycontinue - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'ImportExcel Module Version: ' + ([string]$VarExcel.Version.Major + '.' + [string]$VarExcel.Version.Minor + '.' + [string]$VarExcel.Version.Build)) - if ($null -eq $VarExcel) { - Write-Host "Trying to install ImportExcel Module.." - Install-Module -Name ImportExcel -Force - } - $VarExcel = Get-InstalledModule -Name ImportExcel -ErrorAction silentlycontinue - if ($null -eq $VarExcel) { - Read-Host 'Admininstrator rights required to install ImportExcel Module. Press to finish script' - Exit - } - } - - function LoginSession() { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting LoginSession function') - if(![string]::IsNullOrEmpty($AzureEnvironment)) - { - az cloud set --name $AzureEnvironment - } - $CloudEnv = az cloud list | ConvertFrom-Json - Write-Host "Azure Cloud Environment: " -NoNewline - $CurrentCloudEnvName = $CloudEnv | Where-Object {$_.isActive -eq 'True'} - Write-Host $CurrentCloudEnvName.name -BackgroundColor Green - if (!$TenantID) { - write-host "Tenant ID not specified. Use -TenantID parameter if you want to specify directly. " - write-host "Authenticating Azure" - write-host "" - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Cleaning az account cache') - az account clear | Out-Null - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Calling az login') - if($DeviceLogin.IsPresent) - { - az login --use-device-code - } - else - { - az login --only-show-errors | Out-Null - } - write-host "" - write-host "" - $Tenants = az account list --query [].homeTenantId -o tsv --only-show-errors | Sort-Object -Unique - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking number of Tenants') - if ($Tenants.Count -eq 1) { - write-host "You have privileges only in One Tenant " - write-host "" - $TenantID = $Tenants - } - else { - write-host "Select the the Azure Tenant ID that you want to connect : " - write-host "" - $SequenceID = 1 - foreach ($TenantID in $Tenants) { - write-host "$SequenceID) $TenantID" - $SequenceID ++ - } - write-host "" - [int]$SelectTenant = read-host "Select Tenant ( default 1 )" - $defaultTenant = --$SelectTenant - $TenantID = $Tenants[$defaultTenant] - if($DeviceLogin.IsPresent) - { - az login --use-device-code -t $TenantID - } - else - { - az login -t $TenantID --only-show-errors | Out-Null - } - } - - write-host "Extracting from Tenant $TenantID" - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting Subscription details') - $Global:Subscriptions = az account list --output json --only-show-errors | ConvertFrom-Json - $Global:Subscriptions = $Subscriptions | Where-Object { $_.tenantID -eq $TenantID } - if ($SubscriptionID) - { - if($SubscriptionID.count -gt 1) - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -in $SubscriptionID } - } - else - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -eq $SubscriptionID } - } - } - } - else { - az account clear | Out-Null - if (!$Appid) { - if($DeviceLogin.IsPresent) - { - az login --use-device-code -t $TenantID - } - else - { - $AZConfig = az config get core.enable_broker_on_windows --only-show-errors | ConvertFrom-Json - if ($AZConfig.value -eq $true) - { - az config set core.enable_broker_on_windows=false --only-show-errors - #az config set core.login_experience_v2=off --only-show-errors - az login -t $TenantID --only-show-errors - az config set core.enable_broker_on_windows=true --only-show-errors - } - else - { - az login -t $TenantID --only-show-errors - } - - } - } - elseif ($Appid -and $Secret -and $tenantid) { - write-host "Using Service Principal Authentication Method" - az login --service-principal -u $appid -p $secret -t $TenantID | Out-Null - } - else{ - write-host "You are trying to use Service Principal Authentication Method in a wrong way." - write-host "It's Mandatory to specify Application ID, Secret and Tenant ID in Azure Resource Inventory" - write-host "" - write-host ".\AzureResourceInventory.ps1 -appid -secret -tenant " - Exit - } - $Global:Subscriptions = az account list --output json | ConvertFrom-Json - $Global:Subscriptions = $Subscriptions | Where-Object { $_.tenantID -eq $TenantID } - if ($SubscriptionID) - { - if($SubscriptionID.count -gt 1) - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -in $SubscriptionID } - } - else - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -eq $SubscriptionID } - } - } - } - } - - function checkPS() { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting checkPS function') - $CShell = try{Get-CloudShellTip}catch{} - if ($CShell) { - write-host 'Azure CloudShell Identified.' - $Global:PlatOS = 'Azure CloudShell' - write-host "" - if($ReportDir) - { - try - { - Resolve-Path $ReportDir -ErrorAction STOP - if ($ReportDir -notmatch '/$') - { - $ReportDir = $ReportDir + '/' - } - } - catch - { - Write-Host "ERROR:" -NoNewline -ForegroundColor Red - Write-Host " Wrong ReportDir Path!" - Write-Host "" - Write-Host "ReportDir Parameter must contain the full path." - Write-Host "" - Exit - } - } - $Global:DefaultPath = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/"} - $Global:DiagramCache = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/DiagramCache/"} - $Global:Subscriptions = az account list --output json --only-show-errors | ConvertFrom-Json - if ($SubscriptionID) - { - if($SubscriptionID.count -gt 1) - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -in $SubscriptionID } - } - else - { - $Global:Subscriptions = $Subscriptions | Where-Object { $_.ID -eq $SubscriptionID } - } - } - } - else - { - if ($PSVersionTable.Platform -eq 'Unix') { - write-host "PowerShell Unix Identified." - $Global:PlatOS = 'PowerShell Unix' - write-host "" - if($ReportDir) - { - try - { - Resolve-Path $ReportDir -ErrorAction STOP - if ($ReportDir -notmatch '/$') - { - $ReportDir = $ReportDir + '/' - } - } - catch - { - Write-Host "ERROR:" -NoNewline -ForegroundColor Red - Write-Host " Wrong ReportDir Path!" - Write-Host "" - Write-Host "ReportDir Parameter must contain the full path." - Write-Host "" - Exit - } - } - $Global:DefaultPath = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/"} - $Global:DiagramCache = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/DiagramCache/"} - LoginSession - } - else { - write-host "PowerShell Desktop Identified." - $Global:PlatOS = 'PowerShell Desktop' - write-host "" - if($ReportDir) - { - try - { - Resolve-Path $ReportDir -ErrorAction STOP - if ($ReportDir -notlike '*\') - { - $ReportDir = $ReportDir + '\' - } - } - catch - { - Write-Host "ERROR:" -NoNewline -ForegroundColor Red - Write-Host " Wrong ReportDir Path!" - Write-Host "" - Write-Host "ReportDir Parameter must contain the full path." - Write-Host "" - Exit - } - } - $Global:DefaultPath = if($ReportDir) {$ReportDir} else {"C:\AzureResourceInventory\"} - $Global:DiagramCache = if($ReportDir) {($ReportDir+'DiagramCache\')} else {"C:\AzureResourceInventory\DiagramCache\"} - LoginSession - } - } - } - - <###################################################### Checking PowerShell ######################################################################> - - checkAzCli - checkPS - - #Field for tags - if ($IncludeTags.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Tags will be included") - $GraphQueryTags = ",tags " - } else { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Tags will be ignored") - $GraphQueryTags = "" - } - - <###################################################### Subscriptions ######################################################################> - - Write-Progress -activity 'Azure Inventory' -Status "1% Complete." -PercentComplete 2 -CurrentOperation 'Discovering Subscriptions..' - - if (![string]::IsNullOrEmpty($ManagementGroup)) - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Management group name supplied: ' + $ManagmentGroupName) - $group = az account management-group entities list --query "[?name =='$ManagementGroup']" | ConvertFrom-Json - if ($group.Count -lt 1) - { - Write-Host "ERROR:" -NoNewline -ForegroundColor Red - Write-Host "Management Group $ManagementGroup not found!" - Write-Host "" - Write-Host "Please check the Management Group name and try again." - Write-Host "" - Exit - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Management groups found: ' + $group.count) - foreach ($item in $group) - { - $Global:Subscriptions = @() - $GraphQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$($item.name)' | summarize count()" - $EnvSize = az graph query -q $GraphQuery --output json --only-show-errors | ConvertFrom-Json - $EnvSizeNum = $EnvSize.data.'count_' - - if ($EnvSizeNum -ge 1) { - $Loop = $EnvSizeNum / 1000 - $Loop = [math]::ceiling($Loop) - $Looper = 0 - $Limit = 0 - - while ($Looper -lt $Loop) { - $GraphQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$($item.name)' | project id = subscriptionId" - $Resource = (az graph query -q $GraphQuery --skip $Limit --first 1000 --output json --only-show-errors).tolower() | ConvertFrom-Json - - foreach ($Sub in $Resource.data) { - $Global:Subscriptions += az account show --subscription $Sub.id --output json --only-show-errors | ConvertFrom-Json - } - - Start-Sleep 2 - $Looper ++ - Write-Progress -Id 1 -activity "Running Subscription Inventory Job" -Status "$Looper / $Loop of Subscription Jobs" -PercentComplete (($Looper / $Loop) * 100) - $Limit = $Limit + 1000 - } - } - Write-Progress -Id 1 -activity "Running Subscription Inventory Job" -Status "$Looper / $Loop of Subscription Jobs" -Completed - } - } - } - - $SubCount = [string]$Global:Subscriptions.id.count - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Number of Subscriptions Found: ' + $SubCount) - Write-Progress -activity 'Azure Inventory' -Status "3% Complete." -PercentComplete 3 -CurrentOperation "$SubCount Subscriptions found.." - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking report folder: ' + $DefaultPath ) - if ((Test-Path -Path $DefaultPath -PathType Container) -eq $false) { - New-Item -Type Directory -Force -Path $DefaultPath | Out-Null - } - if ((Test-Path -Path $DiagramCache -PathType Container) -eq $false) { - New-Item -Type Directory -Force -Path $DiagramCache | Out-Null - } - - <######################################################## INVENTORY LOOPs #######################################################################> - - $Global:ExtractionRuntime = Measure-Command -Expression { - - Write-Progress -Id 1 -activity "Running Inventory Jobs" -Status "1% Complete." -Completed - function Invoke-InventoryLoop { - param($GraphQuery,$FSubscri,$LoopName) - - $LocalResults = @() - if($FSubscri.count -gt 200) - { - $SubLoop = $FSubscri.count / 200 - $SubLooper = 0 - $NStart = 0 - $NEnd = 200 - while ($SubLooper -lt $SubLoop) - { - $Sub = $FSubscri[$NStart..$NEnd] - try - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $Sub --first 1000 --output json --only-show-errors | ConvertFrom-Json - } - catch - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $Sub --first 200 --output json --only-show-errors | ConvertFrom-Json - } - $LocalResults += $QueryResult - while ($QueryResult.skip_token) { - try - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $Sub --skip-token $QueryResult.skip_token --first 1000 --output json --only-show-errors | ConvertFrom-Json - } - catch - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $Sub --skip-token $QueryResult.skip_token --first 200 --output json --only-show-errors | ConvertFrom-Json - } - $LocalResults += $QueryResult - } - $NStart = $NStart + 200 - $NEnd = $NEnd + 200 - $SubLooper ++ - } - } - else - { - try - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $FSubscri --first 1000 --output json --only-show-errors - } - catch - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $FSubscri --first 200 --output json --only-show-errors - } - try - { - $QueryResult = $QueryResult | ConvertFrom-Json - } - catch - { - $QueryResult = $QueryResult | ConvertFrom-Json -AsHashtable - } - - $LocalResults += $QueryResult - while ($QueryResult.skip_token) { - try - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $FSubscri --skip-token $QueryResult.skip_token --first 1000 --output json --only-show-errors - } - catch - { - $QueryResult = az graph query -q $GraphQuery --subscriptions $FSubscri --skip-token $QueryResult.skip_token --first 200 --output json --only-show-errors - } - try - { - $QueryResult = $QueryResult | ConvertFrom-Json - } - catch - { - $QueryResult = $QueryResult | ConvertFrom-Json -AsHashtable - } - $LocalResults += $QueryResult - } - } - $LocalResults.data - } - - - Write-Progress -activity 'Azure Inventory' -Status "4% Complete." -PercentComplete 4 -CurrentOperation "Starting Resources extraction jobs.." - - if(![string]::IsNullOrEmpty($ResourceGroup) -and [string]::IsNullOrEmpty($SubscriptionID)) - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resource Group Name present, but missing Subscription ID.') - Write-Host '' - Write-Host 'If Using the -ResourceGroup Parameter, the Subscription ID must be informed' - Write-Host '' - Exit - } - else - { - $Subscri = $Global:Subscriptions.id - $RGQueryExtension = '' - $TagQueryExtension = '' - $MGQueryExtension = '' - if(![string]::IsNullOrEmpty($ResourceGroup) -and ![string]::IsNullOrEmpty($SubscriptionID)) - { - $RGQueryExtension = "| where resourceGroup in~ ('$([String]::Join("','",$ResourceGroup))')" - } - elseif(![string]::IsNullOrEmpty($TagKey) -and ![string]::IsNullOrEmpty($TagValue)) - { - $TagQueryExtension = "| where isnotempty(tags) | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey =~ '$TagKey' and tagValue =~ '$TagValue'" - } - elseif (![string]::IsNullOrEmpty($ManagementGroup)) - { - $MGQueryExtension = "| join kind=inner (resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$ManagementGroup' | project subscriptionId, managanagementGroup = managementGroupParent.name) on subscriptionId" - $MGContainerExtension = "| mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$ManagementGroup'" - } - } - - $GraphQuery = "resources $RGQueryExtension $TagQueryExtension $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Resources') - $Global:Resources += Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Resources' - - $GraphQuery = "networkresources $RGQueryExtension $TagQueryExtension $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Network Resources') - $Global:Resources += Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Network Resources' - - $GraphQuery = "recoveryservicesresources $RGQueryExtension $TagQueryExtension | where type =~ 'microsoft.recoveryservices/vaults/backupfabrics/protectioncontainers/protecteditems' or type =~ 'microsoft.recoveryservices/vaults/backuppolicies' $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Backup Resources') - $Global:Resources += Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Backup Items' - - $GraphQuery = "desktopvirtualizationresources $RGQueryExtension $MGQueryExtension| project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for AVD Resources') - $Global:Resources += Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Virtual Desktop' - - $GraphQuery = "resourcecontainers $RGQueryExtension $TagQueryExtension $MGContainerExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Resource Containers') - $Global:ResourceContainers = Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Subscriptions and Resource Groups' - - if (!($SkipPolicy.IsPresent)) - { - $GraphQuery = "policyresources | where type == 'microsoft.authorization/policyassignments' | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Policies Resources') - $Global:Policies = Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Policies' - } - if (!($SkipAdvisory.IsPresent)) - { - $GraphQuery = "advisorresources $RGQueryExtension $MGQueryExtension | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Advisories') - $Global:Advisories = Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Advisories' - } - if ($SecurityCenter.IsPresent) - { - $GraphQuery = "securityresources $RGQueryExtension | where type =~ 'microsoft.security/assessments' and properties['status']['code'] == 'Unhealthy' $MGQueryExtension | order by id asc" - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Security Resources') - $Global:Security = Invoke-InventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Security Center' - } - - <######################################################### QUOTA JOB ######################################################################> - - if($QuotaUsage.isPresent) - { - Start-Job -Name 'Quota Usage' -ScriptBlock { - - $Location = @() - Foreach($Sub in $($args[1])) - { - $Locs = ($($args[0]) | Where-Object {$_.subscriptionId -eq $Sub.id -and $_.Type -in 'microsoft.compute/virtualmachines','microsoft.compute/virtualmachinescalesets'} | Group-Object -Property Location).name - $Val = @{ - 'Loc' = $Locs; - 'Sub' = $Sub.name - } - $Location += $Val - } - $Quotas = @() - Foreach($Loc in $Location) - { - if($Loc.Loc.count -eq 1) - { - $Quota = az vm list-usage --location $Loc.Loc --subscription $Loc.Sub -o json | ConvertFrom-Json - $Quota = $Quota | Where-Object {$_.CurrentValue -ge 1} - $Q = @{ - 'Location' = $Loc.Loc; - 'Subscription' = $Loc.Sub; - 'Data' = $Quota - } - $Quotas += $Q - } - else { - foreach($Loc1 in $Loc.loc) - { - $Quota = az vm list-usage --location $Loc1 --subscription $Loc.Sub -o json | ConvertFrom-Json - $Quota = $Quota | Where-Object {$_.CurrentValue -ge 1} - $Q = @{ - 'Location' = $Loc1; - 'Subscription' = $Loc.Sub; - 'Data' = $Quota - } - $Quotas += $Q - } - } - } - $Quotas - } -ArgumentList $Global:Resources, $Global:Subscriptions - } - - Write-Progress -activity 'Azure Inventory' -PercentComplete 20 - - Write-Progress -Id 1 -activity "Running Inventory Jobs" -Status "100% Complete." -Completed - - } - } - - - <######################################################### Creating Excel File ######################################################################> - - Function RunMain { - - $Global:ReportingRunTime = Measure-Command -Expression { - - #### Creating Excel file variable: - $Global:File = ($DefaultPath + $Global:ReportName + "_Report_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".xlsx") - #$Global:DFile = ($DefaultPath + $Global:ReportName + "_Diagram_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".vsdx") - $Global:DDFile = ($DefaultPath + $Global:ReportName + "_Diagram_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".xml") - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Excel file:' + $File) - - #### Generic Conditional Text rules, Excel style specifications for the spreadsheets and tables: - $Global:TableStyle = "Light19" - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Excel Table Style used: ' + $TableStyle) - - Write-Progress -activity 'Azure Inventory' -Status "21% Complete." -PercentComplete 21 -CurrentOperation "Starting to process extraction data.." - - - <######################################################### IMPORT UNSUPPORTED VERSION LIST ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Importing List of Unsupported Versions.') - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/Support.json') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/Support.json') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\Support.json') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Support.json') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/Support.json') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Support.json') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $Unsupported = $ModuSeq | ConvertFrom-Json - - $DataActive = ('Azure Resource Inventory Reporting (' + ($resources.count) + ') Resources') - - <######################################################### DRAW.IO DIAGRAM JOB ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Draw.io Diagram Job Should be Run.') - if (!$SkipDiagram.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Draw.io Diagram Processing Job.') - Start-job -Name 'DrawDiagram' -ScriptBlock { - - $DiagramCache = $($args[5]) - - $TempPath = $DiagramCache.split("DiagramCache\")[0] - - $Logfile = ($TempPath+'DiagramLogFile.log') - - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Draw.IO Job') - - If ($($args[8]) -eq $true) { - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Running Online') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[10]) + '/Extras/DrawIODiagram.ps1') - } - Else { - if($($args[0]) -like '*\*') - { - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Running Local') - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\DrawIODiagram.ps1') - } - else - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/DrawIODiagram.ps1') - } - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/DrawIODiagram.ps1') - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Draw.IO Thread') - try - { - $DrawRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])).AddArgument($($args[4])).AddArgument($($args[5])).AddArgument($($args[6])).AddArgument($($args[7])) - - $DrawJob = $DrawRun.BeginInvoke() - - while ($DrawJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $DrawRun.EndInvoke($DrawJob) - - $DrawRun.Dispose() - } - catch - { - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+$_.Exception.Message) - } - Add-Content -Path $Logfile -Value ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Draw.IO Ended.') - - } -ArgumentList $PSScriptRoot, $Subscriptions, $Resources, $Advisories, $DDFile, $DiagramCache, $FullEnv, $ResourceContainers ,$RunOnline, $Repo, $RawRepo | Out-Null - } - - <######################################################### VISIO DIAGRAM JOB ######################################################################> - <# - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Visio Diagram Job Should be Run.') - if ($Diagram.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Visio Diagram Processing Job.') - Start-job -Name 'VisioDiagram' -ScriptBlock { - - If ($($args[5]) -eq $true) { - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[7]) + '/Extras/VisioDiagram.ps1') - } - Else { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\VisioDiagram.ps1') - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $ScriptBlock = [Scriptblock]::Create($ModuSeq) - - $VisioRun = ([PowerShell]::Create()).AddScript($ScriptBlock).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])).AddArgument($($args[4])) - - $VisioJob = $VisioRun.BeginInvoke() - - while ($VisioJob.IsCompleted -contains $false) {} - - $VisioRun.EndInvoke($VisioJob) - - $VisioRun.Dispose() - - } -ArgumentList $PSScriptRoot, $Subscriptions, $Resources, $Advisories, $DFile, $RunOnline, $Repo, $RawRepo | Out-Null - } - #> - - <######################################################### SECURITY CENTER JOB ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Security Center Job.') - if ($SecurityCenter.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Security Job.') - Start-Job -Name 'Security' -ScriptBlock { - - If ($($args[5]) -eq $true) { - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[6]) + '/Extras/SecurityCenter.ps1') - } - Else { - if($($args[0]) -like '*\*') - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\SecurityCenter.ps1') - } - else - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/SecurityCenter.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $SecRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])) - - $SecJob = $SecRun.BeginInvoke() - - while ($SecJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $SecResult = $SecRun.EndInvoke($SecJob) - - $SecRun.Dispose() - - $SecResult - - } -ArgumentList $PSScriptRoot, $Subscriptions , $Security, 'Processing' , $File, $RunOnline, $RawRepo | Out-Null - } - - <######################################################### POLICY JOB ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Policy Job.') - if (!$SkipPolicy.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Policy Processing Job.') - Start-Job -Name 'Policy' -ScriptBlock { - - If ($($args[5]) -eq $true) { - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[6]) + '/Extras/Policy.ps1') - } - Else { - if($($args[0]) -like '*\*') - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\Policy.ps1') - } - else - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/Policy.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $PolRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])).AddArgument($($args[4])) - - $PolJob = $PolRun.BeginInvoke() - - while ($PolJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $PolResult = $PolRun.EndInvoke($PolJob) - - $PolRun.Dispose() - - $PolResult - - } -ArgumentList $PSScriptRoot, $Policies, 'Processing', $Subscriptions, $File, $RunOnline, $RawRepo | Out-Null - } - - <######################################################### ADVISORY JOB ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Advisory Job.') - if (!$SkipAdvisory.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Advisory Processing Job.') - Start-Job -Name 'Advisory' -ScriptBlock { - - If ($($args[4]) -eq $true) { - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[5]) + '/Extras/Advisory.ps1') - } - Else { - if($($args[0]) -like '*\*') - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\Advisory.ps1') - } - else - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/Advisory.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $AdvRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])) - - $AdvJob = $AdvRun.BeginInvoke() - - while ($AdvJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $AdvResult = $AdvRun.EndInvoke($AdvJob) - - $AdvRun.Dispose() - - $AdvResult - - } -ArgumentList $PSScriptRoot, $Advisories, 'Processing' , $File, $RunOnline, $RawRepo | Out-Null - } - - <######################################################### SUBSCRIPTIONS JOB ######################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Subscriptions job.') - Start-Job -Name 'Subscriptions' -ScriptBlock { - - If ($($args[5]) -eq $true) { - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[6]) + '/Extras/Subscriptions.ps1') - } - Else { - if($($args[0]) -like '*\*') - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\Subscriptions.ps1') - } - else - { - $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '/Extras/Subscriptions.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $SubRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])).AddArgument($($args[4])) - - $SubJob = $SubRun.BeginInvoke() - - while ($SubJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $SubResult = $SubRun.EndInvoke($SubJob) - - $SubRun.Dispose() - - $SubResult - - } -ArgumentList $PSScriptRoot, $Subscriptions, $Resources, 'Processing' , $File, $RunOnline, $RawRepo | Out-Null - - <######################################################### RESOURCE GROUP JOB ######################################################################> - - switch ($Resources.count) - { - {$_ -le 1000} - { - $EnvSizeLooper = 1000 - $DebugEnvSize = 'Small' - } - {$_ -gt 1000 -and $_ -le 30000} - { - $EnvSizeLooper = 5000 - $DebugEnvSize = 'Medium' - } - {$_ -gt 30000 -and $_ -le 60000} - { - $EnvSizeLooper = 10000 - $DebugEnvSize = 'Large' - Write-Host $DebugEnvSize -NoNewline -ForegroundColor Green - Write-Host (' Size Environment Identified.') - Write-Host ('Jobs will be run in batches to avoid CPU Overload.') - } - {$_ -gt 60000} - { - $EnvSizeLooper = 5000 - $DebugEnvSize = 'Enormous' - Write-Host $DebugEnvSize -NoNewline -ForegroundColor Green - Write-Host (' Size Environment Identified.') - Write-Host ('Jobs will be run in batches to prevent CPU Overload.') - } - } - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Processing Jobs in '+ $DebugEnvSize +' Mode.') - - $Loop = $resources.count / $EnvSizeLooper - $Loop = [math]::ceiling($Loop) - $Looper = 0 - $Limit = 0 - $JobLoop = 1 - - $ResourcesCount = [string]$Resources.count - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Total Resources Being Processed: '+ $ResourcesCount) - - while ($Looper -lt $Loop) { - $Looper ++ - - $Resource = $resources | Select-Object -First $EnvSizeLooper -Skip $Limit - - $ResourceCount = [string]$Resource.count - $LoopCountStr = [string]$Looper - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resources Being Processed in ResourceJob_'+ $LoopCountStr + ': ' + $ResourceCount) - - Start-Job -Name ('ResourceJob_'+$Looper) -ScriptBlock { - - $Job = @() - - $Subscriptions = $($args[2]) - $InTag = $($args[3]) - $Resource = $($args[4]) - $Task = $($args[5]) - $Unsupported = $($args[12]) - $RunOnline = $($args[9]) - $Repo = $($args[10]) - $RawRepo = $($args[11]) - - If ($RunOnline -eq $true) { - $OnlineRepo = Invoke-WebRequest -Uri $Repo - $RepoContent = $OnlineRepo | ConvertFrom-Json - $Modules = ($RepoContent.tree | Where-Object {$_.path -like '*.ps1' -and $_.path -notlike 'Extras/*' -and $_.path -ne 'AzureResourceInventory.ps1' -and $_.path -notlike 'Automation/*'}).path - } - Else { - if($($args[1]) -like '*\*') - { - $Modules = Get-ChildItem -Path ($($args[1]) + '\Modules\*.ps1') -Recurse - } - else - { - $Modules = Get-ChildItem -Path ($($args[1]) + '/Modules/*.ps1') -Recurse - } - } - $job = @() - - $Modules | ForEach-Object { - If ($RunOnline -eq $true) { - $Modul = $_.split('/') - $ModName = $Modul[2] - $ModName = $ModName.replace(".ps1","") - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/' + $_) - } Else { - $ModName = $_.Name.replace(".ps1","") - $ModuSeq0 = New-Object System.IO.StreamReader($_.FullName) - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - Start-Sleep -Milliseconds 250 - - New-Variable -Name ('ModRun' + $ModName) - New-Variable -Name ('ModJob' + $ModName) - - Set-Variable -Name ('ModRun' + $ModName) -Value ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($PSScriptRoot).AddArgument($Subscriptions).AddArgument($InTag).AddArgument($Resource).AddArgument($Task).AddArgument($null).AddArgument($null).AddArgument($null).AddArgument($Unsupported) - - Set-Variable -Name ('ModJob' + $ModName) -Value ((get-variable -name ('ModRun' + $ModName)).Value).BeginInvoke() - - $job += (get-variable -name ('ModJob' + $ModName)).Value - Start-Sleep -Milliseconds 250 - Clear-Variable -Name ModName - } - - while ($Job.Runspace.IsCompleted -contains $false) { Start-Sleep -Milliseconds 1000 } - - $Modules | ForEach-Object { - If ($RunOnline -eq $true) { - $Modul = $_.split('/') - $ModName = $Modul[2] - $ModName = $ModName.replace(".ps1","") - } Else { - $ModName = $_.Name.replace(".ps1","") - } - Start-Sleep -Milliseconds 250 - - New-Variable -Name ('ModValue' + $ModName) - Set-Variable -Name ('ModValue' + $ModName) -Value (((get-variable -name ('ModRun' + $ModName)).Value).EndInvoke((get-variable -name ('ModJob' + $ModName)).Value)) - - Clear-Variable -Name ('ModRun' + $ModName) - Clear-Variable -Name ('ModJob' + $ModName) - Start-Sleep -Milliseconds 250 - Clear-Variable -Name ModName - } - - [System.GC]::GetTotalMemory($true) | out-null - - $Hashtable = New-Object System.Collections.Hashtable - - $Modules | ForEach-Object { - If ($RunOnline -eq $true) { - $Modul = $_.split('/') - $ModName = $Modul[2] - $ModName = $ModName.replace(".ps1","") - } Else { - $ModName = $_.Name.replace(".ps1","") - } - Start-Sleep -Milliseconds 250 - - $Hashtable["$ModName"] = (get-variable -name ('ModValue' + $ModName)).Value - - Clear-Variable -Name ('ModValue' + $ModName) - Start-Sleep -Milliseconds 100 - - Clear-Variable -Name ModName - } - - [System.GC]::GetTotalMemory($true) | out-null - - $Hashtable - } -ArgumentList $null, $PSScriptRoot, $Subscriptions, $InTag, $Resource, 'Processing', $null, $null, $null, $RunOnline, $Repo, $RawRepo, $Unsupported | Out-Null - $Limit = $Limit + $EnvSizeLooper - Start-Sleep -Milliseconds 250 - if($DebugEnvSize -in ('Large','Enormous') -and $JobLoop -eq 5) - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Waiting Batch of Jobs to Complete.') - - $coun = 0 - - $InterJobNames = (Get-Job | Where-Object {$_.name -like 'ResourceJob_*' -and $_.State -eq 'Running'}).Name - - while (get-job -Name $InterJobNames | Where-Object { $_.State -eq 'Running' }) { - $jb = get-job -Name $InterJobNames - $c = (((($jb.count - ($jb | Where-Object { $_.State -eq 'Running' }).Count)) / $jb.Count) * 100) - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'initial Jobs Running: '+[string]($jb | Where-Object { $_.State -eq 'Running' }).count) - $c = [math]::Round($coun) - Write-Progress -Id 1 -activity "Processing Initial Resource Jobs" -Status "$coun% Complete." -PercentComplete $coun - Start-Sleep -Seconds 15 - } - $JobLoop = 0 - } - $JobLoop ++ - [System.GC]::GetTotalMemory($true) | out-null - } - - <############################################################## RESOURCES LOOP CREATION #############################################################> - - - $Global:ResourcesCount = $Global:Resources.Count - - if($DebugEnvSize -in ('Large','Enormous')) - { - Clear-Variable Resources -Scope Global - [System.GC]::GetTotalMemory($true) | out-null - } - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Jobs Collector.') - Write-Progress -activity $DataActive -Status "Processing Inventory" -PercentComplete 0 - $c = 0 - - $JobNames = (Get-Job | Where-Object {$_.name -like 'ResourceJob_*'}).Name - - while (get-job -Name $JobNames | Where-Object { $_.State -eq 'Running' }) { - $jb = get-job -Name $JobNames - $c = (((($jb.count - ($jb | Where-Object { $_.State -eq 'Running' }).Count)) / $jb.Count) * 100) - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Jobs Still Running: '+[string]($jb | Where-Object { $_.State -eq 'Running' }).count) - $c = [math]::Round($c) - Write-Progress -Id 1 -activity "Processing Resource Jobs" -Status "$c% Complete." -PercentComplete $c - Start-Sleep -Seconds 5 - } - Write-Progress -Id 1 -activity "Processing Resource Jobs" -Status "100% Complete." -Completed - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Jobs Compleated.') - - $AzSubs = Receive-Job -Name 'Subscriptions' - - $Global:SmaResources = @() - - Foreach ($Job in $JobNames) - { - $TempJob = Receive-Job -Name $Job - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Job '+ $Job +' Returned: ' + ($TempJob.values | Where-Object {$_ -ne $null}).Count + ' Resource Types.') - $Global:SmaResources += $TempJob - } - - <############################################################## REPORTING ###################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Reporting Phase.') - Write-Progress -activity $DataActive -Status "Processing Inventory" -PercentComplete 50 - - If ($RunOnline -eq $true) { - $OnlineRepo = Invoke-WebRequest -Uri $Repo - $RepoContent = $OnlineRepo | ConvertFrom-Json - $Modules = ($RepoContent.tree | Where-Object {$_.path -like '*.ps1' -and $_.path -notlike 'Extras/*' -and $_.path -ne 'AzureResourceInventory.ps1' -and $_.path -notlike 'Automation/*'}).path - } - Else { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Running Offline, Gathering List Of Modules.') - if($PSScriptRoot -like '*\*') - { - $Modules = Get-ChildItem -Path ($PSScriptRoot + '\Modules\*.ps1') -Recurse - } - else - { - $Modules = Get-ChildItem -Path ($PSScriptRoot + '/Modules/*.ps1') -Recurse - } - } - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Modules Found: ' + $Modules.Count) - $Lops = $Modules.count - $ReportCounter = 0 - - foreach ($Module in $Modules) { - - $c = (($ReportCounter / $Lops) * 100) - $c = [math]::Round($c) - Write-Progress -Id 1 -activity "Building Report" -Status "$c% Complete." -PercentComplete $c - - If ($RunOnline -eq $true) { - $Modul = $Module.split('/') - $ModName = $Modul[2] - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/' + $Module) - } Else { - $ModuSeq0 = New-Object System.IO.StreamReader($Module.FullName) - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - Start-Sleep -Milliseconds 50 - $ModuleName = $Module.name.replace('.ps1','') - - $ModuleResourceCount = $SmaResources.$ModuleName.count - - if ($ModuleResourceCount -gt 0) - { - Start-Sleep -Milliseconds 100 - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Running Module: '$ModuleName'. Resources Count: $ModuleResourceCount") - - $ExcelRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($PSScriptRoot).AddArgument($null).AddArgument($InTag).AddArgument($null).AddArgument('Reporting').AddArgument($file).AddArgument($SmaResources).AddArgument($TableStyle).AddArgument($Unsupported) - - $ExcelJob = $ExcelRun.BeginInvoke() - - while ($ExcelJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $ExcelRun.EndInvoke($ExcelJob) - - $ExcelRun.Dispose() - - [System.GC]::GetTotalMemory($true) | out-null - } - - $ReportCounter ++ - - } - - if($DebugEnvSize -in ('Large','Enormous')) - { - Clear-Variable SmaResources -Scope Global - [System.GC]::GetTotalMemory($true) | out-null - } - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resource Reporting Phase Done.') - - <################################################################### QUOTAS ###################################################################> - - if($QuotaUsage.IsPresent) - { - get-job -Name 'Quota Usage' | Wait-Job - - $Global:AzQuota = Receive-Job -Name 'Quota Usage' - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Quota Usage sheet for: ' + $Global:AzQuota.count + ' Subscriptions/Regions.') - - Write-Progress -activity 'Azure Resource Inventory Quota Usage' -Status "50% Complete." -PercentComplete 50 -CurrentOperation "Building Quota Sheet" - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/QuotaUsage.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/QuotaUsage.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\QuotaUsage.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\QuotaUsage.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/QuotaUsage.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/QuotaUsage.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $QuotaRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($File).AddArgument($Global:AzQuota).AddArgument($TableStyle) - - $QuotaJob = $QuotaRun.BeginInvoke() - - while ($QuotaJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $QuotaRun.EndInvoke($QuotaJob) - - $QuotaRun.Dispose() - - Write-Progress -activity 'Azure Resource Inventory Quota Usage' -Status "100% Complete." -Completed - } - - - <################################################ SECURITY CENTER #######################################################> - #### Security Center worksheet is generated apart - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Security Center Sheet.') - if ($SecurityCenter.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Security Center Sheet.') - $Global:Secadvco = $Security.Count - - Write-Progress -activity $DataActive -Status "Building Security Center Report" -PercentComplete 0 -CurrentOperation "Considering $Secadvco Security Advisories" - - while (get-job -Name 'Security' | Where-Object { $_.State -eq 'Running' }) { - Write-Progress -Id 1 -activity 'Processing Security Center Advisories' -Status "50% Complete." -PercentComplete 50 - Start-Sleep -Seconds 2 - } - Write-Progress -Id 1 -activity 'Processing Security Center Advisories' -Status "100% Complete." -Completed - - $Sec = Receive-Job -Name 'Security' - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/SecurityCenter.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/SecurityCenter.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\SecurityCenter.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\SecurityCenter.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/SecurityCenter.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/SecurityCenter.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $SecExcelRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($null).AddArgument($null).AddArgument('Reporting').AddArgument($file).AddArgument($Sec).AddArgument($TableStyle) - - $SecExcelJob = $SecExcelRun.BeginInvoke() - - while ($SecExcelJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $SecExcelRun.EndInvoke($SecExcelJob) - - $SecExcelRun.Dispose() - } - - - <################################################ POLICY #######################################################> - #### Policy worksheet is generated apart from the resources - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Policy Sheet.') - if (!$SkipPolicy.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Policy Sheet.') - $Global:polco = $Policies.count - - Write-Progress -activity $DataActive -Status "Building Policy Report" -PercentComplete 0 -CurrentOperation "Considering $polco Policies" - - while (get-job -Name 'Policy' | Where-Object { $_.State -eq 'Running' }) { - Write-Progress -Id 1 -activity 'Processing Policies' -Status "50% Complete." -PercentComplete 50 - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Policy Job is: '+(get-job -Name 'Policy').State) - Start-Sleep -Seconds 2 - } - Write-Progress -Id 1 -activity 'Processing Policies' -Status "100% Complete." -Completed - - $Global:Pol = Receive-Job -Name 'Policy' - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/Policy.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/Policy.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\Policy.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Policy.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/Policy.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Policy.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $PolExcelRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($null).AddArgument('Reporting').AddArgument($null).AddArgument($file).AddArgument($Pol).AddArgument($TableStyle) - - $PolExcelJob = $PolExcelRun.BeginInvoke() - - while ($PolExcelJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $PolExcelRun.EndInvoke($PolExcelJob) - - $PolExcelRun.Dispose() - } - - - <################################################ ADVISOR #######################################################> - #### Advisor worksheet is generated apart from the resources - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Advisory Sheet.') - if (!$SkipAdvisory.IsPresent) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Advisor Sheet.') - $Global:advco = $Advisories.count - - Write-Progress -activity $DataActive -Status "Building Advisories Report" -PercentComplete 0 -CurrentOperation "Considering $advco Advisories" - - while (get-job -Name 'Advisory' | Where-Object { $_.State -eq 'Running' }) { - Write-Progress -Id 1 -activity 'Processing Advisories' -Status "50% Complete." -PercentComplete 50 - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Advisory Job is: '+(get-job -Name 'Advisory').State) - Start-Sleep -Seconds 2 - } - Write-Progress -Id 1 -activity 'Processing Advisories' -Status "100% Complete." -Completed - - $Adv = Receive-Job -Name 'Advisory' - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/Advisory.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/Advisory.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\Advisory.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Advisory.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/Advisory.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Advisory.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $AdvExcelRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($null).AddArgument('Reporting').AddArgument($file).AddArgument($Adv).AddArgument($TableStyle) - - $AdvExcelJob = $AdvExcelRun.BeginInvoke() - - while ($AdvExcelJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $AdvExcelRun.EndInvoke($AdvExcelJob) - - $AdvExcelRun.Dispose() - } - - <################################################################### SUBSCRIPTIONS ###################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Subscription sheet for: ' + $Subscriptions.count + ' Subscriptions.') - - Write-Progress -activity 'Azure Resource Inventory Subscriptions' -Status "50% Complete." -PercentComplete 50 -CurrentOperation "Building Subscriptions Sheet" - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/Subscriptions.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/Subscriptions.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\Subscriptions.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Subscriptions.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/Subscriptions.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Subscriptions.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - $SubsRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($null).AddArgument($null).AddArgument('Reporting').AddArgument($file).AddArgument($AzSubs).AddArgument($TableStyle) - - $SubsJob = $SubsRun.BeginInvoke() - - while ($SubsJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $SubsRun.EndInvoke($SubsJob) - - $SubsRun.Dispose() - - [System.GC]::GetTotalMemory($true) | out-null - - Write-Progress -activity 'Azure Resource Inventory Subscriptions' -Status "100% Complete." -Completed - - <################################################################### CHARTS ###################################################################> - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Overview sheet (Charts).') - - Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "10% Complete." -PercentComplete 10 -CurrentOperation "Starting Excel Chart's Thread." - - If ($RunOnline -eq $true) { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$RawRepo + '/Extras/Charts.ps1') - $ModuSeq = (New-Object System.Net.WebClient).DownloadString($RawRepo + '/Extras/Charts.ps1') - } - Else { - if($PSScriptRoot -like '*\*') - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '\Extras\Charts.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Charts.ps1') - } - else - { - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Looking for the following file: '+$PSScriptRoot + '/Extras/Charts.ps1') - $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Charts.ps1') - } - $ModuSeq = $ModuSeq0.ReadToEnd() - $ModuSeq0.Dispose() - } - - } - - Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "15% Complete." -PercentComplete 15 -CurrentOperation "Invoking Excel Chart's Thread." - - $ChartsRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($file).AddArgument($TableStyle).AddArgument($Global:PlatOS).AddArgument($Global:Subscriptions).AddArgument($Global:ResourcesCount).AddArgument($ExtractionRunTime).AddArgument($ReportingRunTime).AddArgument($RunLite) - - $ChartsJob = $ChartsRun.BeginInvoke() - - Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "30% Complete." -PercentComplete 30 -CurrentOperation "Waiting Excel Chart's Thread." - - while ($ChartsJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } - - $ChartsRun.EndInvoke($ChartsJob) - - $ChartsRun.Dispose() - - [System.GC]::GetTotalMemory($true) | out-null - - Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Finished Charts Phase.') - - Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "100% Complete." -Completed - - if($Diagram.IsPresent) - { - Write-Progress -activity 'Diagrams' -Status "Completing Diagram" -PercentComplete 70 -CurrentOperation "Consolidating Diagram" - - while (get-job -Name 'DrawDiagram' | Where-Object { $_.State -eq 'Running' }) { - Write-Progress -Id 1 -activity 'Processing Diagrams' -Status "50% Complete." -PercentComplete 50 - Start-Sleep -Seconds 2 - } - Write-Progress -Id 1 -activity 'Processing Diagrams' -Status "100% Complete." -Completed - - Write-Progress -activity 'Diagrams' -Status "Closing Diagram File" -Completed - } - - Get-Job | Wait-Job | Remove-Job - } - - - <######################################################### END OF FUNCTIONS ######################################################################> - - if ($Help.IsPresent) { - usageMode - Exit - } - else { - Variables - Extractor - RunMain - } - -} - -$Measure = $Global:SRuntime.Totalminutes.ToString('#######.##') - -Write-Host ('Report Complete. Total Runtime was: ') -NoNewline -Write-Host $Measure -NoNewline -ForegroundColor Cyan -Write-Host (' Minutes') -Write-Host ('Total Resources: ') -NoNewline -Write-Host $Global:ResourcesCount -ForegroundColor Cyan -if (!$SkipAdvisory.IsPresent) - { - Write-Host ('Total Advisories: ') -NoNewline - write-host $advco -ForegroundColor Cyan - } -if (!$SkipPolicy.IsPresent) - { - Write-Host ('Total Policies: ') -NoNewline - write-host $polco -ForegroundColor Cyan - } -if ($SecurityCenter.IsPresent) - { - Write-Host ('Total Security Advisories: ' + $Secadvco) - } - -Write-Host '' -Write-Host ('Excel file saved at: ') -NoNewline -write-host $File -ForegroundColor Cyan -Write-Host '' - -if(!$SkipDiagram.IsPresent) - { - Write-Host ('Draw.io Diagram file saved at: ') -NoNewline - write-host $DDFile -ForegroundColor Cyan - Write-Host '' - } \ No newline at end of file diff --git a/AzureResourceInventory.psd1 b/AzureResourceInventory.psd1 new file mode 100644 index 0000000..a5b4676 --- /dev/null +++ b/AzureResourceInventory.psd1 @@ -0,0 +1,181 @@ +# +# Module manifest for module 'AzureResourceInventory' +# +# Generated by: Claudio Merola +# +# Generated on: 8/14/2024 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'AzureResourceInventory.psm1' + +# Version number of this module. +ModuleVersion = '3.5.0' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '94bc2a7f-e865-426a-a054-cebde278a355' + +# Author of this module +Author = 'Claudio Merola' + +# Company or vendor of this module +CompanyName = 'Merola' + +# Copyright statement for this module +Copyright = '(c) Merola. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'Azure Resource Inventory - Its a Powerful tool to create EXCEL inventory from Azure Resources with low effort' + +# 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 = @('ImportExcel','Az.Accounts','Az.Compute','Az.ResourceGraph','Az.Storage') + +# 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 = @() + +# 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 = @('Modules/Core/ARITestPS.psm1', + 'Modules/ARIResourceJobs.psm1', + 'Modules/ARIResourcesReport.psm1', + 'Modules/Core/ARIExtraJobs.psm1' + 'Modules/Core/ARILoginSession.psm1', + 'Modules/Inventory/ARIResourceDataPull.psm1', + 'Modules/Core/ARIInventoryLoop.psm1', + 'Modules/Core/ARIGetSubs.psm1', + 'Modules/Inventory/ARIResourceReport.psm1', + 'Modules/Inventory/ARISecCenterInv.psm1', + 'Modules/Inventory/ARIPolicyInv.psm1', + 'Modules/Inventory/ARIAdvisoryInv.psm1', + 'Modules/Inventory/ARISubInv.psm1', + 'Modules/Inventory/ARIQuotaInv.psm1', + 'Modules/Extras/ARIReportCharts.psm1', + 'Modules/Diagram/ARIDrawIODiagram.psm1', + 'Modules/Diagram/ARIDiagramNetwork.psm1', + 'Modules/Diagram/ARIDiagramOrganization.psm1', + 'Modules/Diagram/ARIDiagramSubscription.psm1', + 'Modules/Inventory/ARIMGMTGroups.psm1', + 'Modules/Inventory/ARIAPIInv.psm1') + +# 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 = @('Invoke-ARI', + 'Connect-ARILoginSession', + 'Test-ARIPS', + 'Start-AzureResourceDataPull', + 'Get-ARISubscriptions', + 'Invoke-ResourceInventoryLoop', + 'Build-AzureResourceReport', + 'Invoke-ARISecCenterProcessing', + 'Build-ARISecCenterReport', + 'Invoke-ARIPolicyProcessing', + 'Build-ARIPolicyReport', + 'Invoke-ARIAdvisoryProcessing', + 'Build-ARIAdvisoryReport', + 'Invoke-ARISubsProcessing', + 'Build-ARISubsReport', + 'Build-ARIQuotaReport', + 'Build-ARIExcelChart', + 'Invoke-ARIDrawIODiagram', + 'Invoke-ARIDiagramNetwork', + 'Invoke-ARIDiagramOrganization', + 'Invoke-ARIDiagramSubscription', + 'Get-ARIManagementGroups', + 'Start-ARIResourceReporting', + 'Start-ARIResourceJobs', + 'Start-ARIExtraJobs', + 'Start-ARIExtraReports', + 'Get-ARIUnsupportedData', + 'Start-ARIQuotaJob', + 'Start-ARIAutResourceJob', + 'Get-ARIAPIResources') + +# 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 = @('Azure','Inventory','ResourceInventory','ARI','AzureResourceInventory','Resources') + + # A URL to the license for this module. + LicenseUri = 'https://github.com/microsoft/ARI/blob/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/microsoft/ARI' + + # A URL to an icon representing this module. + IconUri = 'https://github.com/microsoft/ARI/blob/main/images/ARI_Logo.png' + + # 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 = '' + +} + diff --git a/AzureResourceInventory.psm1 b/AzureResourceInventory.psm1 new file mode 100644 index 0000000..a3a9e58 --- /dev/null +++ b/AzureResourceInventory.psm1 @@ -0,0 +1,363 @@ +<# +.SYNOPSIS + This script creates Excel file to Analyze Azure Resources inside a Tenant + +.DESCRIPTION + Do you want to analyze your Azure Advisories in a table format? Document it in xlsx format. + +.PARAMETER TenantID + Specify the tenant ID you want to create a Resource Inventory. + + >>> IMPORTANT: YOU NEED TO USE THIS PARAMETER FOR TENANTS WITH MULTI-FACTOR AUTHENTICATION. <<< + +.PARAMETER SubscriptionID + Use this parameter to collect a specific Subscription in a Tenant + +.PARAMETER ManagementGroup + Use this parameter to collect a all Subscriptions in a Specific Management Group in a Tenant + +.PARAMETER Lite + Use this parameter to use only the Import-Excel module and don't create the charts (using Excel's API) + +.PARAMETER SecurityCenter + Use this parameter to collect Security Center Advisories + +.PARAMETER SkipAdvisory + Use this parameter to skip the capture of Azure Advisories + +.PARAMETER SkipPolicy + Use this parameter to skip the capture of Azure Policies + +.PARAMETER QuotaUsage + Use this parameter to include Quota information + +.PARAMETER IncludeTags + Use this parameter to include Tags of every Azure Resources + +.PARAMETER Debug + Output detailed debug information. + +.EXAMPLE + Default utilization. Read all tenants you have privileges, select a tenant in menu and collect from all subscriptions: + PS C:\> Invoke-ARI + + Define the Tenant ID: + PS C:\> Invoke-ARI -TenantID + + Define the Tenant ID and for a specific Subscription: + PS C:\> Invoke-ARI -TenantID -SubscriptionID + +.NOTES + AUTHORS: Claudio Merola and Renato Gregio | Azure Infrastucture/Automation/Devops/Governance + + Copyright (c) 2018 Microsoft Corporation. All rights reserved. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +.LINK + Official Repository: https://github.com/microsoft/ARI +#> +Function Invoke-ARI { +param ([ValidateSet('AzureCloud', 'AzureUSGovernment')] + $AzureEnvironment = 'AzureCloud', + $TenantID, + $SubscriptionID, + $ManagementGroup, + [string[]]$ResourceGroup, + $TagKey, + $TagValue, + [switch]$SecurityCenter, + [switch]$SkipAdvisory, + [switch]$SkipPolicy, + [switch]$SkipAPIs, + [switch]$IncludeTags, + [switch]$QuotaUsage, + [switch]$SkipDiagram, + [switch]$Automation, + $StorageAccount, + $StorageContainer, + [switch]$Lite, + [switch]$Debug, + [switch]$Help, + [switch]$DeviceLogin, + [switch]$DiagramFullEnvironment, + $ReportName = 'AzureResourceInventory', + $ReportDir) + + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Debbuging Mode: On. ErrorActionPreference was set to "Continue", every error will be presented.') + + if ($IncludeTags.IsPresent) { $InTag = $true } else { $InTag = $false } + + if ($Lite.IsPresent -or $Automation.IsPresent) { $RunLite = $true }else { $RunLite = $false } + if ($DiagramFullEnvironment.IsPresent) {$FullEnv = $true}else{$FullEnv = $false} + + <######################################################### Help ######################################################################> + + Function Get-UsageMode() { + Write-Host "" + Write-Host "Parameters" + Write-Host "" + Write-Host " -TenantID : Specifies the Tenant to be inventoried. " + Write-Host " -SubscriptionID : Specifies Subscription(s) to be inventoried. " + Write-Host " -ResourceGroup : Specifies one (or more) unique Resource Group to be inventoried, This parameter requires the -SubscriptionID to work. " + Write-Host " -TagKey : Specifies the tag key to be inventoried, This parameter requires the -SubscriptionID to work. " + Write-Host " -TagValue : Specifies the tag value be inventoried, This parameter requires the -SubscriptionID to work. " + Write-Host " -SkipAdvisory : Do not collect Azure Advisory. " + Write-Host " -SkipPolicy : Do not collect Azure Policies. " + Write-Host " -SecurityCenter : Include Security Center Data. " + Write-Host " -IncludeTags : Include Resource Tags. " + Write-Host " -Online : Use Online Modules. " + Write-Host " -Debug : Run in a Debug mode. " + Write-Host " -AzureEnvironment : Change the Azure Cloud Environment. " + Write-Host " -ReportName : Change the Default Name of the report. " + Write-Host " -ReportDir : Change the Default Path of the report. " + Write-Host "" + Write-Host "" + Write-Host "" + Write-Host "Usage Mode and Examples: " + Write-Host "If you do not specify Resource Inventory will be performed on all subscriptions for the selected tenant. " + Write-Host "e.g. /> Invoke-ARI" + Write-Host "" + Write-Host "To perform the inventory in a specific Tenant and subscription use <-TenantID> and <-SubscriptionID> parameter " + Write-Host "e.g. /> Invoke-ARI -TenantID -SubscriptionID " + Write-Host "" + Write-Host "Including Tags:" + Write-Host " By Default Azure Resource inventory do not include Resource Tags." + Write-Host " To include Tags at the inventory use <-IncludeTags> parameter. " + Write-Host "e.g. /> Invoke-ARI -TenantID -IncludeTags" + Write-Host "" + Write-Host "Skipping Azure Advisor:" + Write-Host " By Default Azure Resource inventory collects Azure Advisor Data." + Write-Host " To ignore this use <-SkipAdvisory> parameter. " + Write-Host "e.g. /> Invoke-ARI -TenantID -SubscriptionID -SkipAdvisory" + Write-Host "" + Write-Host "Using the latest modules :" + Write-Host " You can use the latest modules. For this use <-Online> parameter." + Write-Host " It's a pre-requisite to have internet access for ARI GitHub repo" + Write-Host "e.g. /> Invoke-ARI -TenantID -Online" + Write-Host "" + Write-Host "Running in Debug Mode :" + Write-Host " To run in a Debug Mode use <-Debug> parameter." + Write-Host ".e.g. /> Invoke-ARI -TenantID -Debug" + Write-Host "" + } + + <######################################################### END OF FUNCTIONS ######################################################################> + + $TotalRunTime = Measure-Command -Expression { + + if ($Help.IsPresent) { + Get-UsageMode + Exit + } + else { + + Write-Host ('Checking for Powershell Module Updates..') + Update-Module -Name AzureResourceInventory -AcceptLicense + + $PlatOS = Test-ARIPS -Debug $Debug + + if ($PlatOS -ne 'Azure CloudShell' -and !$Automation.IsPresent) + { + $TenantID = Connect-ARILoginSession -AzureEnvironment $AzureEnvironment -TenantID $TenantID -SubscriptionID $SubscriptionID -DeviceLogin $DeviceLogin + } + elseif ($Automation.IsPresent) + { + try { + $AzureConnection = (Connect-AzAccount -Identity).context + + Set-AzContext -SubscriptionName $AzureConnection.Subscription -DefaultProfile $AzureConnection + + $StorageContext = New-AzStorageContext -StorageAccountName $StorageAccount -UseConnectedAccount + } + catch { + Write-Output "Failed to set Automation Account requirements. Aborting." + exit + } + } + + $Subscriptions = Get-ARISubscriptions -TenantID $TenantID -SubscriptionID $SubscriptionID + + if ($PlatOS -eq 'Azure CloudShell') + { + $DefaultPath = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/"} + $DiagramCache = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/DiagramCache/"} + if($ReportDir) + { + try + { + Resolve-Path $ReportDir -ErrorAction STOP + if ($ReportDir -notmatch '/$') + { + $ReportDir = $ReportDir + '/' + } + } + catch + { + Write-Output "ReportDir Parameter must contain the full path." + Exit + } + } + } + elseif ($PlatOS -eq 'PowerShell Unix') + { + $DefaultPath = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/"} + $DiagramCache = if($ReportDir) {$ReportDir} else {"$HOME/AzureResourceInventory/DiagramCache/"} + if($ReportDir) + { + try + { + Resolve-Path $ReportDir -ErrorAction STOP + if ($ReportDir -notmatch '/$') + { + $ReportDir = $ReportDir + '/' + } + } + catch + { + Write-Output "ReportDir Parameter must contain the full path." + Exit + } + } + } + elseif ($PlatOS -eq 'PowerShell Desktop') + { + $DefaultPath = if($ReportDir) {$ReportDir} else {"C:\AzureResourceInventory\"} + $DiagramCache = if($ReportDir) {($ReportDir+'DiagramCache\')} else {"C:\AzureResourceInventory\DiagramCache\"} + if($ReportDir) + { + try + { + Resolve-Path $ReportDir -ErrorAction STOP + if ($ReportDir -notlike '*\') + { + $ReportDir = $ReportDir + '\' + } + } + catch + { + Write-Output "ReportDir Parameter must contain the full path." + Exit + } + } + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking report folder: ' + $DefaultPath ) + if ((Test-Path -Path $DefaultPath -PathType Container) -eq $false) { + New-Item -Type Directory -Force -Path $DefaultPath | Out-Null + } + if ((Test-Path -Path $DiagramCache -PathType Container) -eq $false) { + New-Item -Type Directory -Force -Path $DiagramCache | Out-Null + } + + Write-Host "Starting Resource Extraction.." + + $ExtractionData = Start-AzureResourceDataPull -ManagementGroup $ManagementGroup -Subscriptions $Subscriptions -SubscriptionID $SubscriptionID -ResourceGroup $ResourceGroup -SecurityCenter $SecurityCenter -SkipAdvisory $SkipAdvisory -IncludeTags $IncludeTags -QuotaUsage $QuotaUsage -TagKey $TagKey -TagValue $TagValue -Debug $Debug + + $ExtractionRuntime = $ExtractionData.ExtractionRunTime + $Resources = $ExtractionData.Resources + $ResourceContainers = $ExtractionData.ResourceContainers + $Advisories = $ExtractionData.Advisories + $Security = $ExtractionData.Security + + Clear-Variable -Name ExtractionData + + $ResourcesCount = [string]$Resources.Count + $advco = [string]$Advisories.Count + $Secadvco = [string]$Security.Count + + if(!$SkipAPIs.IsPresent) + { + $APIResults = Get-ARIAPIResources -Subscriptions $Subscriptions -AzureEnvironment $AzureEnvironment -SkipPolicy $SkipPolicy -Debug $Debug + $Resources += $APIResults.ResourceHealth + $Resources += $APIResults.SupportTickets + $Resources += $APIResults.ManagedIdentities + $Resources += $APIResults.AdvisorScore + $Resources += $APIResults.ReservationRecomen + $PolicyAssign = $APIResults.PolicyAssign + $PolicyDef = $APIResults.PolicyDef + $PolicySetDef = $APIResults.PolicySetDef + } + + $polco = [string]$PolicyAssign.policyAssignments.Count + + #### Creating Excel file variable: + if ($Automation.IsPresent) + { + $Date = get-date -Format "yyyy-MM-dd_HH_mm" + + $File = ("ARI_Automation_Report_"+$Date+".xlsx") + } + else + { + $File = ($DefaultPath + $ReportName + "_Report_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".xlsx") + #$Global:DFile = ($DefaultPath + $Global:ReportName + "_Diagram_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".vsdx") + $DDFile = ($DefaultPath + $ReportName + "_Diagram_" + (get-date -Format "yyyy-MM-dd_HH_mm") + ".xml") + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Excel file: ' + $File) + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Default Jobs.') + + Start-ARIExtraJobs -SkipDiagram $SkipDiagram -SkipAdvisory $SkipAdvisory -SkipPolicy $SkipPolicy -SecurityCenter $SecurityCenter -Subscriptions $Subscriptions -Resources $Resources -Advisories $Advisories -DDFile $DDFile -DiagramCache $DiagramCache -FullEnv $FullEnv -ResourceContainers $ResourceContainers -Security $Security -PolicyAssign $PolicyAssign -PolicySetDef $PolicySetDef -PolicyDef $PolicyDef -Automation $Automation -Debug $Debug + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Resources Report Function.') + + Build-AzureResourceReport -Subscriptions $Subscriptions -ExtractionRunTime $ExtractionRuntime -Resources $Resources -SecurityCenter $SecurityCenter -File $File -DDFile $DDFile -SkipDiagram $SkipDiagram -RunLite $RunLite -PlatOS $PlatOS -InTag $InTag -SkipPolicy $SkipPolicy -SkipAdvisory $SkipAdvisory -Automation $Automation -SkipAPIs $SkipAPIs -Debug $Debug + + if ($Automation.IsPresent) + { + Set-AzStorageBlobContent -File $File -Container $StorageContainer -Context $StorageContext | Out-Null + } + } +} + +$Measure = $TotalRunTime.Totalminutes.ToString('#######.##') + +Write-Host ('Report Complete. Total Runtime was: ') -NoNewline +Write-Host $Measure -NoNewline -ForegroundColor Cyan +Write-Host (' Minutes') +Write-Host ('Total Resources: ') -NoNewline +Write-Host $ResourcesCount -ForegroundColor Cyan +if (!$SkipAdvisory.IsPresent) + { + Write-Host ('Total Advisories: ') -NoNewline + write-host $advco -ForegroundColor Cyan + } +if (!$SkipPolicy.IsPresent -and !$SkipAPIs.IsPresent) + { + Write-Host ('Total Policies: ') -NoNewline + write-host $polco -ForegroundColor Cyan + } +if ($SecurityCenter.IsPresent) + { + Write-Host ('Total Security Advisories: ' + $Secadvco) + } + +Write-Host '' +Write-Host ('Excel file saved at: ') -NoNewline +write-host $File -ForegroundColor Cyan +Write-Host '' + +if(!$SkipDiagram.IsPresent) + { + Write-Host ('Draw.io Diagram file saved at: ') -NoNewline + write-host $DDFile -ForegroundColor Cyan + Write-Host '' + } +} \ No newline at end of file diff --git a/Extras/Advisory.ps1 b/Extras/Advisory.ps1 deleted file mode 100644 index 9532c2f..0000000 --- a/Extras/Advisory.ps1 +++ /dev/null @@ -1,77 +0,0 @@ -<# -.Synopsis -Advisory Module - -.DESCRIPTION -This script process and creates the Advisory sheet based on advisorresources. - -.Link -https://github.com/microsoft/ARI/Extras/Advisory.ps1 - -.COMPONENT - This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.0.0 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($Advisories, $Task ,$File, $Adv, $TableStyle) - -If ($Task -eq 'Processing') -{ - $obj = '' - $tmp = @() - - foreach ($1 in $Advisories) - { - if($1) - { - $data = $1.PROPERTIES - - if($null -eq $data.extendedProperties.annualSavingsAmount){$Savings = 0}Else{$Savings = $data.extendedProperties.annualSavingsAmount} - if($null -eq $data.extendedProperties.savingsCurrency){$SavingsCurrency = 'USD'}Else{$SavingsCurrency = $data.extendedProperties.savingsCurrency} - $obj = @{ - 'ResourceGroup' = $1.RESOURCEGROUP; - 'Affected Resource Type' = $data.impactedField; - 'Name' = $data.impactedValue; - 'Category' = $data.category; - 'Impact' = $data.impact; - #'Score' = $data.extendedproperties.score; - 'Problem' = $data.shortDescription.problem; - 'Savings Currency' = $SavingsCurrency; - 'Annual Savings' = "=$Savings"; - 'Savings Region' = $data.extendedProperties.location; - 'Current SKU' = $data.extendedProperties.currentSku; - 'Target SKU' = $data.extendedProperties.targetSku - } - $tmp += $obj - } - } - $tmp -} -Else -{ - $condtxtadv = $(New-ConditionalText High -Range E:E - New-ConditionalText Security -Range D:D -BackgroundColor Wheat) - - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '#,##0.00' -Range H:H - - $Adv | - ForEach-Object { [PSCustomObject]$_ } | - Select-Object 'ResourceGroup', - 'Affected Resource Type', - 'Name', - 'Category', - 'Impact', - #'Score', - 'Problem', - 'Savings Currency', - 'Annual Savings', - 'Savings Region', - 'Current SKU', - 'Target SKU' | - Export-Excel -Path $File -WorksheetName 'Advisory' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzureAdvisory' -MoveToStart -TableStyle $tableStyle -Style $Style -ConditionalText $condtxtadv -KillExcel - -} diff --git a/Extras/Charts.ps1 b/Extras/Charts.ps1 deleted file mode 100644 index 8576a5d..0000000 --- a/Extras/Charts.ps1 +++ /dev/null @@ -1,805 +0,0 @@ -<# -.Synopsis -Module for Main Dashboard - -.DESCRIPTION -This script process and creates the Overview sheet. - -.Link -https://github.com/microsoft/ARI/Extras/Charts.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 3.1.3 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($File, $TableStyle, $PlatOS, $Subscriptions, $Resources, $ExtractionRunTime, $ReportingRunTime, $RunLite) - -if(!$RunLite) - { - $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File - $Worksheets = $Excel.Workbook.Worksheets - - $Order = $Worksheets | Where-Object { $_.Name -notin 'Policy', 'Advisory', 'Security Center', 'Subscriptions', 'Quota Usage' } | Select-Object -Property Index, name, @{N = "Dimension"; E = { $_.dimension.Rows - 1 } } | Sort-Object -Property Dimension -Descending - - $Order0 = $Order | Where-Object { $_.Name -ne $Order[0].name -and $_.Name -ne ($Order | select-object -Last 1).Name } - - $Worksheets.MoveAfter($Order[0].Name, 'Advisory') - $Worksheets.MoveAfter($Order[0].Name, 'Policy') - $Worksheets.MoveBefore(($Order | select-object -Last 1).Name, 'Subscriptions') - - $Loop = 0 - - Foreach ($Ord in $Order0) { - if ($Ord.Index -and $Loop -ne 0) { - $Worksheets.MoveAfter($Ord.Name, $Order0[$Loop - 1].Name) - } - if ($Loop -eq 0) { - $Worksheets.MoveAfter($Ord.Name, $Order[0].Name) - } - $Loop++ - } - - $Excel.Save() - $Excel.Dispose() - } - -"" | Export-Excel -Path $File -WorksheetName 'Overview' -MoveToStart - - if($RunLite) - { - $excel = Open-ExcelPackage -Path $file -KillExcel - } - else - { - $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File - } - $Worksheets = $Excel.Workbook.Worksheets - $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } - - $WS.SetValue(75,70,'') - $WS.SetValue(76,70,'') - $WS.View.ShowGridLines = $false - - if($RunLite) - { - Close-ExcelPackage $excel - } - else - { - $Excel.Save() - $Excel.Dispose() - } - - - $TableStyleEx = if($PlatOS -eq 'PowerShell Desktop'){'Medium1'}else{$TableStyle} - $TableStyle = if($PlatOS -eq 'PowerShell Desktop'){'Medium15'}else{$TableStyle} - #$TableStyle = 'Medium22' - $Font = 'Segoe UI' - - if($RunLite) - { - $excel = Open-ExcelPackage -Path $file -KillExcel - } - else - { - $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File - } - $Worksheets = $Excel.Workbook.Worksheets | Where-Object { $_.name -notin 'Overview', 'Subscriptions', 'Advisory', 'Policy', 'Security Center' } - $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } - - - $TabDraw = $WS.Drawings.AddShape('TP00', 'RoundRect') - $TabDraw.SetSize(130 , 78) - $TabDraw.SetPosition(1, 0, 0, 0) - $TabDraw.TextAlignment = 'Center' - - - $Table = @() - Foreach ($WorkS in $Worksheets) { - $Number = $WorkS.Tables.Name.split('_') - $tmp = @{ - 'Name' = $WorkS.name; - 'Size' = [int]$Number[1] - } - $Table += $tmp - } - - if($RunLite) - { - Close-ExcelPackage $excel - } - else - { - $Excel.Save() - $Excel.Dispose() - } - - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 - - $Table | - ForEach-Object { [PSCustomObject]$_ } | Sort-Object -Property 'Size' -Descending | - Select-Object -Unique 'Name', - 'Size' | Export-Excel -Path $File -WorksheetName 'Overview' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzureTabs' -TableStyle $TableStyleEx -Style $Style -StartRow 6 -StartColumn 1 - - $Date = (get-date -Format "MM/dd/yyyy") - - $ExtractTime = if($ExtractionRunTime.Totalminutes -lt 1){($ExtractionRunTime.Seconds.ToString()+' Seconds')}else{($ExtractionRunTime.Totalminutes.ToString('#######.##')+' Minutes')} - $ReportTime = ($ReportingRunTime.Totalminutes.ToString('#######.##')+' Minutes') - - $User = $Subscriptions[0].user.name - $TotalRes = $Resources - - - if($RunLite) - { - $excel = Open-ExcelPackage -Path $file -KillExcel - } - else - { - $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File - } - $Worksheets = $Excel.Workbook.Worksheets - $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } - - - $cell = $WS.Cells | Where-Object {$_.Address -like 'A*' -and $_.Address -notin 'A1','A2','A3','A4','A5','A6'} - foreach ($item in $cell) { - $Works = $Item.Text - $Link = New-Object -TypeName OfficeOpenXml.ExcelHyperLink ("'"+$Works+"'"+'!A1'),$Works - $Item.Hyperlink = $Link - } - - - $Egg = $WS.Cells | Where-Object {$_.Address -eq 'BR75'} - $Egg.AddComment('Created with alot of effort and hard work, we hope you enjoy it.','.') | Out-Null - $Egg = $WS.Cells | Where-Object {$_.Address -eq 'BR76'} - $Egg.AddComment('By: Claudio Merola and Renato Gregio','.') | Out-Null - - - $TabDraw = $WS.Drawings.AddShape('TP0', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 52, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP1', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 55, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP2', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 58, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP3', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 61, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP4', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 64, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP5', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 67, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP6', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 70, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP7', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 73, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP8', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 76, 0) - $TabDraw.TextAlignment = 'Center' - - $TabDraw = $WS.Drawings.AddShape('TP9', 'RoundRect') - $TabDraw.SetSize(125, 25) - $TabDraw.SetPosition(0, 10, 79, 0) - $TabDraw.TextAlignment = 'Center' - - $Draw = $WS.Drawings.AddShape('ARI', 'RoundRect') - $Draw.SetSize(445, 240) - $Draw.SetPosition(1, 0, 2, 5) - - $txt = $Draw.RichText.Add('Azure Resource Inventory v3.1' + "`n") - $txt.Size = 14 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('https://github.com/microsoft/ARI' + "`n" + "`n") - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('Report Date: ') - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add($Date + "`n") - $txt.Size = 12 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('Extraction Time: ') - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add($ExtractTime + "`n") - $txt.Size = 12 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('Reporting Time: ') - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add($ReportTime + "`n") - $txt.Size = 12 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('User Session: ') - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add($User + "`n") - $txt.Size = 12 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add('Environment: ') - $txt.Size = 11 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $txt = $Draw.RichText.Add($PlatOS) - $txt.Size = 12 - $txt.ComplexFont = $Font - $txt.LatinFont = $Font - - $Draw.TextAlignment = 'Center' - - $RGD = $WS.Drawings.AddShape('RGs', 'RoundRect') - $RGD.SetSize(124, 115) - $RGD.SetPosition(21, 5, 9, 5) - $RGD.TextAlignment = 'Center' - $RGD.RichText.Add('Total Resources' + "`n").Size = 12 - $RGD.RichText.Add($TotalRes).Size = 22 - - - $DrawP00 = $WS.Drawings | Where-Object { $_.Name -eq 'TP00' } - $P00Name = 'Reported Resources' - $DrawP00.RichText.Add($P00Name).Size = 16 - - $DrawP0 = $WS.Drawings | Where-Object { $_.Name -eq 'TP0' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisory' }) { - $P0Name = 'Advisories' - } - else { - $P0Name = 'Public IPs' - } - $DrawP0.RichText.Add($P0Name) | Out-Null - - - $P1Name = 'Subscriptions' - $DrawP1 = $WS.Drawings | Where-Object { $_.Name -eq 'TP1' } - $DrawP1.RichText.Add($P1Name) | Out-Null - - - $DrawP2 = $WS.Drawings | Where-Object { $_.Name -eq 'TP2' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'SecurityCenter' }) { - $P2Name = 'Security Center' - } - elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisory' }) { - $P2Name = 'Annual Savings' - } - else { - $P2Name = 'Virtual Networks' - } - - $DrawP2.RichText.Add($P2Name) | Out-Null - - $DrawP3 = $WS.Drawings | Where-Object { $_.Name -eq 'TP3' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'AKS' }) { - $P3Name = 'Azure Kubernetes' - } - else { - $P3Name = 'Storage Accounts' - } - $DrawP3.RichText.Add($P3Name) | Out-Null - - $DrawP4 = $WS.Drawings | Where-Object { $_.Name -eq 'TP4' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Quota Usage' }) { - $P4Name = 'Quota Usage' - } - else { - $P4Name = 'VM Disks' - } - $DrawP4.RichText.Add($P4Name) | Out-Null - - $DrawP5 = $WS.Drawings | Where-Object { $_.Name -eq 'TP5' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { - $P5Name = 'Virtual Machines' - } - $DrawP5.RichText.Add($P5Name) | Out-Null - - $DrawP6 = $WS.Drawings | Where-Object { $_.Name -eq 'TP6' } - $P6Name = 'Resources by Location' - $DrawP6.RichText.Add($P6Name) | Out-Null - - $DrawP7 = $WS.Drawings | Where-Object { $_.Name -eq 'TP7' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { - $P7Name = 'Virtual Machines' - } - $DrawP7.RichText.Add($P7Name) | Out-Null - - $DrawP8 = $WS.Drawings | Where-Object { $_.Name -eq 'TP8' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisory' }) { - $P8Name = 'Advisories' - } - $DrawP8.RichText.Add($P8Name) | Out-Null - - $DrawP9 = $WS.Drawings | Where-Object { $_.Name -eq 'TP9' } - if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { - $P9Name = 'Virtual Machines' - } - $DrawP9.RichText.Add($P9Name) | Out-Null - - if($RunLite) - { - Close-ExcelPackage $excel - } - else - { - $Excel.Save() - $Excel.Dispose() - } - - - -$excel = Open-ExcelPackage -Path $file -KillExcel - -Add-ExcelChart -Worksheet $excel.Overview -ChartType Area3D -XRange "AzureTabs[Name]" -YRange "AzureTabs[Size]" -SeriesHeader 'Resources', 'Count' -Column 9 -Row 1 -Height 400 -Width 950 -RowOffSetPixels 0 -ColumnOffSetPixels 5 -NoLegend - - -if ($P0Name -eq 'Advisories') { - $PTParams = @{ - PivotTableName = "P0" - Address = $excel.Overview.cells["BA5"] # top-left corner of the table - SourceWorkSheet = $excel.Advisory - PivotRows = @("Category") - PivotData = @{"Category" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "BarStacked3D" - ChartRow = 13 # place the chart below row 22nd - ChartColumn = 2 - Activate = $true - PivotFilter = 'Impact' - ChartTitle = 'Advisories' - ShowPercent = $true - ChartHeight = 275 - ChartWidth = 445 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - Add-PivotTable @PTParams -NoLegend -} -else { - $PTParams = @{ - PivotTableName = "P0" - Address = $excel.Overview.cells["BA5"] # top-left corner of the table - SourceWorkSheet = $excel.'Public IPs' - PivotRows = @("Use") - PivotData = @{"Use" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "BarStacked3D" - ChartRow = 13 # place the chart below row 22nd - ChartColumn = 2 - Activate = $true - PivotFilter = 'location' - ChartTitle = 'Public IPs' - ShowPercent = $true - ChartHeight = 275 - ChartWidth = 445 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -NoLegend -} - -$PTParams = @{ - PivotTableName = "P1" - Address = $excel.Overview.cells["BD6"] # top-left corner of the table - SourceWorkSheet = $excel.Subscriptions - PivotRows = @("Subscription") - PivotData = @{"Resources" = "sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "BarClustered" - ChartRow = 27 # place the chart below row 22nd - ChartColumn = 2 - Activate = $true - PivotFilter = 'Resource Group', 'Resource Type' - ChartTitle = 'Resources by Subscription' - NoLegend = $true - ShowPercent = $true - ChartHeight = 655 - ChartWidth = 570 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 -} -Add-PivotTable @PTParams - - -if ($P2Name -eq 'Security Center') { - $PTParams = @{ - PivotTableName = "P2" - Address = $excel.Overview.cells["BG5"] # top-left corner of the table - SourceWorkSheet = $excel.SecurityCenter - PivotRows = @("Severity") - PivotData = @{"Resource Name" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 21 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - ChartTitle = 'Security Center' - PivotFilter = 'Categories' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -NoLegend -} -elseif ($P2Name -eq 'Annual Savings') { - $PTParams = @{ - PivotTableName = "P2" - Address = $excel.Overview.cells["BG5"] # top-left corner of the table - SourceWorkSheet = $excel.Advisory - PivotRows = @("Savings Currency") - PivotData = @{"Annual Savings" = "Sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 21 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - ChartTitle = 'Potential Savings' - PivotFilter = 'Savings Region' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - PivotNumberFormat = '#,##0.00' - } - - Add-PivotTable @PTParams -NoLegend -} -else { - $PTParams = @{ - PivotTableName = "P2" - Address = $excel.Overview.cells["BG5"] # top-left corner of the table - SourceWorkSheet = $excel.'Virtual Networks' - PivotRows = @("Location") - PivotData = @{"Location" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 21 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - ChartTitle = 'Virtual Networks' - PivotFilter = 'Subscription' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -NoLegend -} - - -if ($P3Name -eq 'Azure Kubernetes') { - $PTParams = @{ - PivotTableName = "P3" - Address = $excel.Overview.cells["BJ5"] # top-left corner of the table - SourceWorkSheet = $excel.AKS - PivotRows = @("Kubernetes Version") - PivotData = @{"Clusters" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "Pie3D" - ChartRow = 34 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - ChartTitle = 'AKS Versions' - PivotFilter = 'Node Size' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -} -else { - $PTParams = @{ - PivotTableName = "P3" - Address = $excel.Overview.cells["BJ5"] # top-left corner of the table - SourceWorkSheet = $excel.'Storage Acc' - PivotRows = @("Tier") - PivotData = @{"Tier" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "Pie3D" - ChartRow = 34 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - PivotFilter = 'SKU' - ChartTitle = 'Storage Accounts' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -} - - - -if ($P4Name -eq 'Quota Usage') { - $PTParams = @{ - PivotTableName = "P4" - Address = $excel.Overview.cells["BM5"] # top-left corner of the table - SourceWorkSheet = $excel.'Quota Usage' - PivotRows = @("Region") - PivotData = @{"vCPUs Available" = "Sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 47 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - PivotFilter = 'Limit' - ChartTitle = 'Available Quota (vCPUs)' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -NoLegend -} -else { - $PTParams = @{ - PivotTableName = "P4" - Address = $excel.Overview.cells["BM5"] # top-left corner of the table - SourceWorkSheet = $excel.Disks - PivotRows = @("Disk State") - PivotData = @{"Disk State" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 47 # place the chart below row 22nd - ChartColumn = 11 - Activate = $true - PivotFilter = 'SKU' - ChartTitle = 'VM Disks' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -NoLegend -} - - - -if ($P5Name -eq 'Virtual Machines') { - $PTParams = @{ - PivotTableName = "P5" - Address = $excel.Overview.cells["BP7"] # top-left corner of the table - SourceWorkSheet = $excel.'Virtual Machines' - PivotRows = @("VM Size") - PivotData = @{"Resource U" = "Sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "BarClustered" - ChartRow = 21 # place the chart below row 22nd - ChartColumn = 16 - Activate = $true - NoLegend = $true - ChartTitle = 'Virtual Machines by Serie' - PivotFilter = 'OS Type', 'Location', 'Power State' - ShowPercent = $true - ChartHeight = 775 - ChartWidth = 502 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 5 - } - - Add-PivotTable @PTParams -} - -$PTParams = @{ - PivotTableName = "P6" - Address = $excel.Overview.cells["BS5"] # top-left corner of the table - SourceWorkSheet = $excel.Subscriptions - PivotRows = @("Location") - PivotData = @{"Resources" = "sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "ColumnStacked3D" - ChartRow = 1 # place the chart below row 22nd - ChartColumn = 24 - Activate = $true - PivotFilter = 'Resource Type' - ChartTitle = 'Resources by Location' - NoLegend = $true - ShowPercent = $true - ChartHeight = 400 - ChartWidth = 315 - ChartRowOffSetPixels = 0 - ChartColumnOffSetPixels = 0 -} - -Add-PivotTable @PTParams - - -if ($P7Name -eq 'Virtual Machines') { - $PTParams = @{ - PivotTableName = "P7" - Address = $excel.Overview.cells["BV5"] # top-left corner of the table - SourceWorkSheet = $excel.'Virtual Machines' - PivotRows = @("OS Type") - PivotData = @{"Resource U" = "Sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "Pie3D" - ChartRow = 21 # place the chart below row 22nd - ChartColumn = 24 - Activate = $true - NoLegend = $true - ChartTitle = 'VMs by OS' - PivotFilter = 'Location' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 0 - } - - Add-PivotTable @PTParams -} - -if ($P8Name -eq 'Advisories') { - $PTParams = @{ - PivotTableName = "P8" - Address = $excel.Overview.cells["BY5"] # top-left corner of the table - SourceWorkSheet = $excel.Advisory - PivotRows = @("Impact") - PivotData = @{"Impact" = "Count" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "BarStacked3D" - ChartRow = 34 - ChartColumn = 24 - Activate = $true - PivotFilter = 'Category' - ChartTitle = 'Advisories' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 0 - } - Add-PivotTable @PTParams -NoLegend -} - -if ($P9Name -eq 'Virtual Machines') { - $PTParams = @{ - PivotTableName = "P9" - Address = $excel.Overview.cells["CB5"] # top-left corner of the table - SourceWorkSheet = $excel.'Virtual Machines' - PivotRows = @("Boot Diagnostics") - PivotData = @{"Resource U" = "Sum" } - PivotTableStyle = $tableStyle - IncludePivotChart = $true - ChartType = "Pie3D" - ChartRow = 47 - ChartColumn = 24 - Activate = $true - NoLegend = $true - ChartTitle = 'Boot Diagnostics' - PivotFilter = 'Location' - ShowPercent = $true - ChartHeight = 255 - ChartWidth = 315 - ChartRowOffSetPixels = 5 - ChartColumnOffSetPixels = 0 - } - - Add-PivotTable @PTParams -} - - - -Close-ExcelPackage $excel - - -if(!$RunLite) - { - $application = New-Object -ComObject Excel.Application - if ($application) { - $Ex = $application.Workbooks.Open($File) - Start-Sleep -Seconds 2 - $WS = $ex.Worksheets | Where-Object { $_.Name -eq 'Overview' } - - $NoChangeChart = ('ChartP0', 'ChartP1', 'ChartP2', 'ChartP3', 'ChartP4', 'ChartP5', 'ChartP6', 'ChartP7', 'ChartP8', 'ChartP9', 'ARI', 'RGs', 'TP00', 'TP0', 'TP1', 'TP2', 'TP3', 'TP4', 'TP5','TP6','TP7','TP8','TP9') - $ChangeChart = ('ARI', 'RGs', 'TP00', 'TP0', 'TP1', 'TP2', 'TP3', 'TP4', 'TP5', 'TP6', 'TP7','TP8','TP9') - - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartStyle = 294 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartStyle = 222 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP2' }).DrawingObject.Chart.ChartStyle = 294 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP3' }).DrawingObject.Chart.ChartStyle = 268 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP4' }).DrawingObject.Chart.ChartStyle = 294 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP5' }).DrawingObject.Chart.ChartStyle = 222 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP6' }).DrawingObject.Chart.ChartStyle = 294 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP7' }).DrawingObject.Chart.ChartStyle = 268 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP8' }).DrawingObject.Chart.ChartStyle = 294 - ($WS.Shapes | Where-Object { $_.name -eq 'ChartP9' }).DrawingObject.Chart.ChartStyle = 268 - ($WS.Shapes | Where-Object { $_.name -notin $NoChangeChart -and $_.name -like 'Chart*' }).DrawingObject.Chart.ChartStyle = 315 - - Foreach ($Changer in $ChangeChart) { - ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.interior.color = 2500134 - ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.color = 16777215 - ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.ColorIndex = -4142 - ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.LineStyle = -4142 - } - - #$WS.Cells.Interior.Color = 0 - - $Draw = ($WS.Shapes | Where-Object {$_.name -eq 'ARI'}) - $Draw.Adjustments(1) = 0.07 - - $Ex.Save() - $Ex.Close() - $application.Quit() - Get-Process -Name "excel" -ErrorAction Ignore | Stop-Process - } - } - diff --git a/Extras/DrawIODiagram.ps1 b/Extras/DrawIODiagram.ps1 deleted file mode 100644 index c5b77ff..0000000 --- a/Extras/DrawIODiagram.ps1 +++ /dev/null @@ -1,5945 +0,0 @@ -<# -.Synopsis -Diagram Module for Draw.io - -.DESCRIPTION -This script process and creates a Draw.io Diagram based on resources present in the extraction variable $Resources. - -.Link -https://github.com/microsoft/ARI/Extras/DrawIODiagram.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 3.1.15 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($Subscriptions, $Resources, $Advisories, $DDFile, $DiagramCache, $FullEnvironment, $ResourceContainers) - -$Global:DiagramCache = $DiagramCache - -$Global:FullEnvironment = $FullEnvironment - -$TempPath = $DiagramCache.split("DiagramCache\")[0] - -$Global:Logfile = ($TempPath+'DiagramLogFile.log') - -Function Network { - Param($Subscriptions,$Resources,$Advisories,$DiagramCache,$FullEnvironment,$DDFile,$XMLFiles) - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Network Diagram Job...') | Out-File -FilePath $LogFile -Append - - Start-Job -Name 'Diagram_NetworkTopology' -ScriptBlock { - - $Global:jobs = @() - $Global:jobs2 = @() - $Global:Subscriptions = $($args[0]) - $Global:Resources = $($args[1]) - $Global:Advisories = $($args[2]) - $Global:DiagramCache = $($args[3]) - $Global:FullEnvironment = $($args[4]) - $Global:DDFile = $($args[5]) - $Global:XMLFiles = $($args[6]) - $Global:Logfile = $($args[7]) - - Function Icon { - Param($Style,$x,$y,$w,$h,$p) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', $Style) - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function VNETContainer { - Param($x,$y,$w,$h,$title) - $Global:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;swimlaneFillColor=#D5E8D4;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function HubContainer { - Param($x,$y,$w,$h,$title) - $Global:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;rounded=1;swimlaneFillColor=#DAE8FC;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function BrokenContainer { - Param($x,$y,$w,$h,$title) - $Global:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#fad9d5;strokeColor=#ae4132;swimlaneFillColor=#FAD9D5;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Connect { - Param($Source,$Target,$Parent) - - if($Parent){$Parent = $Parent}else{$Parent = 1} - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - $Global:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") - $Global:XmlWriter.WriteAttributeString('edge', "1") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $Parent) - $Global:XmlWriter.WriteAttributeString('source', $Source) - $Global:XmlWriter.WriteAttributeString('target', $Target) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('relative', "1") - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - } - - <# Function to create the Visio document and import each stencil #> - Function Stensils { - $Global:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" - - $Global:IconConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" - $Global:IconExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" - $Global:IconVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" - $Global:IconVGW2 = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" - $Global:IconVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" - $Global:IconTraffic = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Local_Network_Gateways.svg;" #width="68" height="68" - $Global:IconNIC = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;" #width="68" height="60" - $Global:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" - $Global:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" - $Global:IconNSG = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Network_Security_Groups.svg;" # width="26.35" height="32" - $Global:IconUDR = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Route_Tables.svg;" #width="30.97" height="30" - $Global:IconDDOS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;" # width="23" height="28" - $Global:IconPIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" - $Global:IconNAT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/NAT.svg;" # width="65" height="52" - - <########################## Azure Generic Stencils #############################> - - $Global:SymError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="50" height="50" - $Global:SymInfo = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Information.svg;" #width="64" height="64" - $Global:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" - $GLobal:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" - $Global:IconBastions = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/general/Launch_Portal.svg;" #width="68" height="67" - $Global:IconContain = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Container_Instances.svg;" #width="64" height="68" - $Global:IconVWAN = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_WANs.svg;" #width="65" height="64" - $Global:IconCostMGMT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Cost_Analysis.svg;" #width="60" height="70" - - <########################## Azure Computing Stencils #############################> - - $Global:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" - $Global:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" - $Global:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" - $Global:IconARO = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/mscae/OpenShift.svg;" #width="50" height="46" - $Global:IconFunApps = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Function_Apps.svg;" # width="68" height="60" - - <########################## Azure Service Stencils #############################> - - $Global:IconAPIMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/app_services/API_Management_Services.svg;" #width="65" height="60" - $Global:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" - - <########################## Azure Storage Stencils #############################> - - $Global:IconNetApp = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;" #width="65" height="52" - - <########################## Azure Storage Stencils #############################> - - $Global:IconDataExplorer = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;" #width="68" height="68" - - <########################## Other Stencils #############################> - - $Global:IconFWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;" #width="71" height="60" - $Global:IconDet = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/other/Detonation.svg;" #width="42.63" height="44" - $Global:IconAppGWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;" #width="64" height="64" - $Global:IconBricks = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;" #width="60" height="68" - $Global:IconError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="30" height="30" - $Global:OnPrem = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/mscae/Exchange_On_premises_Access.svg;" #width="168.2" height="290" - $Global:Signature = "aspect=fixed;html=1;points=[];align=left;image;fontSize=22;image=img/lib/azure2/general/Dev_Console.svg;" #width="27.5" height="22" - $Global:CloudOnly = "aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;" #width="380.77" height="275" - - } - - <# Function to begin OnPrem environment drawing. Will begin by Local network Gateway, then Express Route.#> - Function OnPremNet { - $Global:VNETHistory = @() - $Global:RoutsW = $AZVNETs | Select-Object -Property Name, @{N="Subnets";E={$_.properties.subnets.properties.addressPrefix.count}} | Sort-Object -Property Subnets -Descending - - $Global:Alt = 0 - - ##################################### Local Network Gateway ############################################# - - foreach($GTW in $AZLGWs) - { - if($GTW.properties.provisioningState -ne 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'This Local Network Gateway has Errors') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconError 40 ($Global:Alt+25) "25" "25" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Con1 = $AZCONs | Where-Object {$_.properties.localNetworkGateway2.id -eq $GTW.id} - - if(!$Con1 -and $GTW.properties.provisioningState -eq 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'No Connections were found in this Local Network Gateway') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SymInfo 40 ($Global:Alt+30) "20" "20" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Name = $GTW.name - $IP = $GTW.properties.gatewayIpAddress - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name + "`n" + [string]$IP)) - $Global:XmlWriter.WriteAttributeString('Local_Address_Space', [string]$GTW.properties.localNetworkAddressSpace.addressPrefixes) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconTraffic 50 $Global:Alt "67" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:GTWAddress = ($Global:CellID+'-'+($Global:IDNum-1)) - $Global:ConnSourceResource = 'GTW' - - OnPrem $Con1 - - $Global:Alt = $Global:Alt + 150 - } - - ##################################### ERS ############################################# - - Foreach($ERs in $AZEXPROUTEs) - { - if($ERs.properties.provisioningState -ne 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'This Express Route has Errors') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconError 51 ($Global:Alt+25) "25" "25" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Con1 = $AZCONs | Where-Object {$_.properties.peer.id -eq $ERs.id} - - if(!$Con1 -and $ERs.properties.circuitProvisioningState -eq 'Enabled') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'No Connections were found in this Express Route') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SymInfo 51 ($Global:Alt+30) "20" "20" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Name = $ERs.name - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" +[string]$Name)) - $Global:XmlWriter.WriteAttributeString('Provider', [string]$ERs.properties.serviceProviderProperties.serviceProviderName) - $Global:XmlWriter.WriteAttributeString('Peering_location', [string]$ERs.properties.serviceProviderProperties.peeringLocation) - $Global:XmlWriter.WriteAttributeString('Bandwidth', [string]$ERs.properties.serviceProviderProperties.bandwidthInMbps) - $Global:XmlWriter.WriteAttributeString('SKU', [string]$ERs.sku.tier) - $Global:XmlWriter.WriteAttributeString('Billing_model', $ERs.sku.family) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconExpressRoute "61.5" $Global:Alt "44" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:ERAddress = ($Global:CellID+'-'+($Global:IDNum-1)) - $Global:ConnSourceResource = 'ER' - - OnPrem $Con1 - - $Global:Alt = $Global:Alt + 150 - - } - - ##################################### VWAN VPNSITES ############################################# - - foreach($GTW in $AZVPNSITES) - { - if($GTW.properties.provisioningState -ne 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'This VPN Site has Errors') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconError 40 ($Global:Alt+25) "25" "25" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $wan1 = $AZVWAN | Where-Object {$_.properties.vpnSites.id -eq $GTW.id} - - if(!$wan1 -and $GTW.properties.provisioningState -eq 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'No vWANs were found in this VPN Site') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SymInfo 40 ($Global:Alt+30) "20" "20" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Name = $GTW.name - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name)) - $Global:XmlWriter.WriteAttributeString('Address_Space', [string]$GTW.properties.addressSpace.addressPrefixes) - $Global:XmlWriter.WriteAttributeString('Link_Speed_In_Mbps', [string]$GTW.properties.deviceProperties.linkSpeedInMbps) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconNAT 50 $Global:Alt "67" "40" 1 - - $Global:XmlWriter.WriteEndElement() - #$tt = $tt + 200 - - vWan $wan1 - - $Global:Alt = $Global:Alt + 150 - } - - ##################################### VWAN ERs ############################################# - - foreach($GTW in $AZVERs) - { - if($GTW.properties.provisioningState -ne 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'This Express Route Circuit has Errors') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconError 40 ($Global:Alt+25) "25" "25" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $wan1 = $AZVWAN | Where-Object {$_.properties.vpnSites.id -eq $GTW.id} - - if(!$wan1 -and $GTW.properties.provisioningState -eq 'Succeeded') - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Status', 'No vWANs were found in this Express Route Circuit') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SymInfo 40 ($Global:Alt+30) "20" "20" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Name = $GTW.name - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name)) - $Global:XmlWriter.WriteAttributeString('Address_Space', [string]$GTW.properties.addressSpace.addressPrefixes) - $Global:XmlWriter.WriteAttributeString('LinkSpeed_In_Mbps', [string]$GTW.properties.deviceProperties.linkSpeedInMbps) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconNAT 50 $Global:Alt "67" "40" 1 - - $Global:XmlWriter.WriteEndElement() - #$tt = $tt + 200 - - vWan $wan1 - - $Global:Alt = $Global:Alt + 150 - } - - ##################################### LABELs ############################################# - - if(!$Global:FullEnvironment) - { - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Ret -520 -100 "500" ($Global:Alt + 100) 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ('On Premises'+ "`n" +'Environment')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $OnPrem -351 (($Global:Alt + 100)/2) "168.2" "290" 1 - - $Global:XmlWriter.WriteEndElement() - - label - - Icon $Signature -520 ($Global:Alt + 100) "27.5" "22" 1 - - $Global:XmlWriter.WriteEndElement() - } - - } - - Function OnPrem { - Param($Con1) - foreach ($Con2 in $Con1) - { - if([string]::IsNullOrEmpty($Global:vnetLoc)) - { - $Global:vnetLoc = 700 - } - $VGT = $AZVGWs | Where-Object {$_.id -eq $Con2.properties.virtualNetworkGateway1.id} - $VGTPIP = $PIPs | Where-Object {$_.properties.ipConfiguration.id -eq $VGT.properties.ipConfigurations.id} - - $Name2 = $Con2.Name - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', [string]$Name2) - $Global:XmlWriter.WriteAttributeString('Connection_Type', [string]$Con2.properties.connectionType) - $Global:XmlWriter.WriteAttributeString('Use_Azure_Private_IP_Address', [string]$Con2.properties.useLocalAzureIpAddress) - $Global:XmlWriter.WriteAttributeString('Routing_Weight', [string]$Con2.properties.routingWeight) - $Global:XmlWriter.WriteAttributeString('Connection_Protocol', [string]$Con2.properties.connectionProtocol) - $Global:Source = ($Global:CellID+'-'+($Global:IDNum-1)) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconConnections 250 $Global:Alt "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - if($Global:ConnSourceResource -eq 'ER') - { - Connect $Global:ERAddress $Global:Target - } - elseif($Global:ConnSourceResource -eq 'GTW') - { - Connect $Global:GTWAddress $Global:Target - } - - $Global:Source = $Global:Target - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" +[string]$VGT.Name + "`n" + [string]$VGTPIP.properties.ipAddress)) - $Global:XmlWriter.WriteAttributeString('VPN_Type', [string]$VGT.properties.vpnType) - $Global:XmlWriter.WriteAttributeString('Generation', [string]$VGT.properties.vpnGatewayGeneration ) - $Global:XmlWriter.WriteAttributeString('SKU', [string]$VGT.properties.sku.name) - $Global:XmlWriter.WriteAttributeString('Gateway_Type', [string]$VGT.properties.gatewayType) - $Global:XmlWriter.WriteAttributeString('Active_active_mode', [string]$VGT.properties.activeActive) - $Global:XmlWriter.WriteAttributeString('Gateway_Private_IPs', [string]$VGT.properties.enablePrivateIpAddress) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVGW2 425 ($Global:Alt-4) "31.34" "48" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - Connect $Global:Source $Global:Target - - $Global:Source = $Global:Target - - foreach($AZVNETs2 in $AZVNETs) - { - foreach($VNETTEMP in $AZVNETs2.properties.subnets.properties.ipconfigurations.id) - { - $VV4 = $VNETTEMP.Split("/") - $VNETTEMP1 = ($VV4[0] + '/' + $VV4[1] + '/' + $VV4[2] + '/' + $VV4[3] + '/' + $VV4[4] + '/' + $VV4[5] + '/' + $VV4[6] + '/' + $VV4[7]+ '/' + $VV4[8]) - if($VNETTEMP1 -eq $VGT.id) - { - $Global:VNET2 = $AZVNETs2 - - $Global:Alt0 = $Global:Alt - if($VNET2.id -notin $VNETHistory.vnet) - { - if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) - { - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' - }Else{ - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) - if($VNET2.properties.dhcpoptions.dnsServers) - { - $Global:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - else - { - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVNET 600 $Global:Alt "65" "39" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:VNETDrawID = ($Global:CellID+'-'+($Global:IDNum-1)) - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - Connect $Global:Source $Global:Target - - if($VNET2.properties.enableDdosProtection -eq $true) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDDOS 580 ($Global:Alt + 15) "23" "28" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Global:Source = $Global:Target - - VNETCreator $Global:VNET2 - - if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) - { - PeerCreator $Global:VNET2 - } - - $tmp =@{ - 'VNETid' = $Global:VNETDrawID; - 'VNET' = $AZVNETs2.id - } - $Global:VNETHistory += $tmp - - } - else - { - - $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $AZVNETs2.id} - - Connect $Global:Source $VNETDID.VNETid - - } - - } - } - - } - - if($Con1.count -gt 1) - { - $Global:Alt = $Global:Alt + 250 - } - } - - } - - Function vWan { - Param($wan1) - - if([string]::IsNullOrEmpty($Global:vnetLoc)) - { - $Global:vnetLoc = 700 - } - - $Name2 = $wan1.Name - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', [string]$Name2) - $Global:XmlWriter.WriteAttributeString('allow_VnetToVnet_Traffic', [string]$wan1.properties.allowVnetToVnetTraffic) - $Global:XmlWriter.WriteAttributeString('allow_BranchToBranch_Traffic', [string]$wan1.properties.allowBranchToBranchTraffic) - $Global:Source = ($Global:CellID+'-'+($Global:IDNum-1)) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVWAN 250 $Global:Alt "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - Connect $Global:Source $Global:Target - - $Global:Source1 = $Global:Target - - foreach ($Con2 in $wan1.properties.virtualHubs.id) - { - $VHUB = $AZVHUB | Where-Object {$_.id -eq $Con2} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ("`n" +[string]$VHUB.Name)) - $Global:XmlWriter.WriteAttributeString('Address_Prefix', [string]$VHUB.properties.addressPrefix) - $Global:XmlWriter.WriteAttributeString('Preferred_Routing_Gateway', [string]$VHUB.properties.preferredRoutingGateway) - $Global:XmlWriter.WriteAttributeString('Virtual_Router_Asn', [string]$VHUB.properties.virtualRouterAsn) - $Global:XmlWriter.WriteAttributeString('Allow_BranchToBranch_Traffic', [string]$VHUB.properties.allowBranchToBranchTraffic) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVWAN 425 $Global:Alt "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - Connect $Global:Source1 $Global:Target - - $Global:Source = $Global:Target - - foreach($AZVNETs2 in $AZVNETs) - { - foreach($VNETTEMP in $AZVNETs2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) - { - $VV4 = $VNETTEMP.Split("/") - $VNETTEMP1 = $VV4[8] - if($VNETTEMP1 -like ('HV_'+$VHUB.name+'_*')) - { - $Global:VNET2 = $AZVNETs2 - - $Global:Alt0 = $Global:Alt - if($VNET2.id -notin $VNETHistory.vnet) - { - if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) - { - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' - }Else{ - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) - if($VNET2.properties.dhcpoptions.dnsServers) - { - $Global:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - else - { - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVNET 600 $Global:Alt "65" "39" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:VNETDrawID = ($Global:CellID+'-'+($Global:IDNum-1)) - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - Connect $Global:Source $Global:Target - - if($VNET2.properties.enableDdosProtection -eq $true) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDDOS 580 ($Global:Alt + 15) "23" "28" 1 - - $Global:XmlWriter.WriteEndElement() - } - - VNETCreator $Global:VNET2 - - if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id -and $VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id -notlike ('*/HV_'+$VHUB.name+'_*')) - { - PeerCreator $Global:VNET2 - } - - $tmp =@{ - 'VNETid' = $Global:VNETDrawID; - 'VNET' = $AZVNETs2.id - } - $Global:VNETHistory += $tmp - - } - else - { - $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $AZVNETs2.id} - - Connect $Global:Source $VNETDID.VNETid - } - } - } - } - - if($Con1.count -gt 1) - { - $Global:Alt = $Global:Alt + 250 - } - } - - } - - <# Function for Cloud Only Environments #> - Function CloudOnly { - $Global:RoutsW = $AZVNETs | Select-Object -Property Name, @{N="Subnets";E={$_.properties.subnets.properties.addressPrefix.count}} | Sort-Object -Property Subnets -Descending - - $Global:VNETHistory = @() - if([string]::IsNullOrEmpty($Global:vnetLoc)) - { - $Global:vnetLoc = 700 - } - $Global:Alt = 2 - - foreach($AZVNETs2 in $AZVNETs) - { - $Global:VNET2 = $AZVNETs2 - - $Global:Alt0 = $Global:Alt - if($VNET2.id -notin $VNETHistory.vnet) - { - - if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) - { - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' - }Else{ - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) - if($VNET2.properties.dhcpoptions.dnsServers) - { - $Global:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - else - { - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVNET 600 $Global:Alt "65" "39" 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:VNETDrawID = ($Global:CellID+'-'+($Global:IDNum-1)) - - $Global:Target = ($Global:CellID+'-'+($Global:IDNum-1)) - - if($VNET2.properties.enableDdosProtection -eq $true) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDDOS 580 ($Global:Alt + 15) "23" "28" 1 - - $Global:XmlWriter.WriteEndElement() - } - - $Global:Source = $Global:Target - - VNETCreator $Global:VNET2 - - if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) - { - PeerCreator $Global:VNET2 - } - - $tmp =@{ - 'VNETid' = $Global:VNETDrawID; - 'VNET' = $AZVNETs2.id - } - $Global:VNETHistory += $tmp - - } - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Ret -520 -100 "500" ($Global:Alt + 100) 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ('Cloud Only'+ "`n" +'Environment')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Global:CloudOnly -460 (($Global:Alt + 100)/2) "380" "275" 1 - - $Global:XmlWriter.WriteEndElement() - - label - - Icon $Signature -520 ($Global:Alt + 100) "27.5" "22" 1 - - $Global:XmlWriter.WriteEndElement() - - } - - Function FullEnvironment { - foreach($AZVNETs2 in $AZVNETs) - { - $Global:VNET2 = $AZVNETs2 - - if($VNET2.id -notin $VNETHistory.vnet) - { - if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) - { - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' - }Else{ - $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) - if($VNET2.properties.dhcpoptions.dnsServers) - { - $Global:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - else - { - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) - } - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVNET 600 $Global:Alt "65" "39" 1 - - $Global:XmlWriter.WriteEndElement() - - VNETCreator $Global:VNET2 - - if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) - { - PeerCreator $Global:VNET2 - } - } - - $Global:Alt = $Global:Alt + 250 - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Ret -520 -100 "500" ($Global:Alt + 100) 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ('On Premises'+ "`n" +'Environment')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $OnPrem -351 (($Global:Alt + 100)/2) "168.2" "290" 1 - - $Global:XmlWriter.WriteEndElement() - - label - - Icon $Signature -520 ($Global:Alt + 100) "27.5" "22" 1 - - $Global:XmlWriter.WriteEndElement() - - } - - <# Function for VNET creation #> - Function VNETCreator { - Param($VNET2) - $Global:sizeL = $VNET2.properties.subnets.properties.addressPrefix.count - - [System.GC]::GetTotalMemory($true) | out-null - - if($VNET2.id -notin $VNETHistory.vnet) - { - if ($Global:sizeL -gt 5) - { - $Global:sizeL = $Global:sizeL / 2 - $Global:sizeL = [math]::ceiling($Global:sizeL) - $Global:sizeC = $Global:sizeL - $Global:sizeL = (($Global:sizeL * 210) + 30) - - if('gatewaysubnet' -in $VNET2.properties.subnets.name) - { - HubContainer ($Global:vnetLoc) ($Global:Alt0 - 20) $Global:sizeL "490" $VNET2.Name - } - else - { - VNETContainer ($Global:vnetLoc) ($Global:Alt0 - 20) $Global:sizeL "490" $VNET2.Name - } - - - - $Global:VNETSquare = ($Global:CellID+'-'+($Global:IDNum-1)) - - $SubName = $Subscriptions | Where-Object {$_.id -eq $VNET2.subscriptionId} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $SubName.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconSubscription $Global:sizeL 460 "67" "40" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $ADVS = '' - $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} - If($ADVS) - { - $Count = 1 - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - foreach ($ADV in $ADVS) - { - $Attr1 = ('Recommendation'+[string]$Count) - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconCostMGMT ($Global:sizeL + 150) 460 "30" "35" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - } - - Subnet ($Global:vnetLoc + 15) $VNET2 $Global:IDNum $Global:DiagramCache $Global:ContID - - if($Global:VNETPIP) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $Count = 1 - Foreach ($PIPDetail in $Global:VNETPIP) - { - $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) - $Global:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDet ($Global:sizeL + 500) 225 "42.63" "44" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - Connect ($Global:CellID+'-'+($Global:IDNum-1)) $Global:ContID $Global:ContID - } - - $Global:Alt = $Global:Alt + 650 - } - else - { - $Global:sizeL = (($Global:sizeL * 210) + 30) - - if('gatewaysubnet' -in $VNET2.properties.subnets.name) - { - HubContainer ($Global:vnetLoc) ($Global:Alt0 - 15) $Global:sizeL "260" $VNET2.Name - } - else - { - VNETContainer ($Global:vnetLoc) ($Global:Alt0 - 15) $Global:sizeL "260" $VNET2.Name - } - - - $Global:VNETSquare = ($Global:CellID+'-'+($Global:IDNum-1)) - - $SubName = $Subscriptions | Where-Object {$_.id -eq $VNET2.subscriptionId} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $SubName.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconSubscription $Global:sizeL 225 "67" "40" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $ADVS = '' - $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} - If($ADVS) - { - $Count = 1 - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - foreach ($ADV in $ADVS) - { - $Attr1 = ('Recommendation'+[string]$Count) - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconCostMGMT ($Global:sizeL + 150) 225 "30" "35" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - } - - Subnet ($Global:vnetLoc + 15) $VNET2 $Global:IDNum $Global:DiagramCache $Global:ContID - - if($Global:VNETPIP) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $Count = 1 - Foreach ($PIPDetail in $Global:VNETPIP) - { - $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) - $Global:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDet ($Global:sizeL + 500) 107 "42.63" "44" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - Connect ($Global:CellID+'-'+($Global:IDNum-1)) $Global:ContID $Global:ContID - } - $Global:Alt = $Global:Alt + 350 - } - } - - [System.GC]::GetTotalMemory($true) | out-null - } - - <# Function for create peered VNETs #> - Function PeerCreator { - Param($VNET2) - - $Global:vnetLoc1 = $Global:Alt - - Foreach ($Peer in $VNET2.properties.virtualNetworkPeerings) - { - $VNETSUB = $AZVNETs | Where-Object {$_.id -eq $Peer.properties.remoteVirtualNetwork.id} - - if($VNETSUB.id -in $VNETHistory.VNET) - { - $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $VNETSUB.id} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Peering_Name', $Peer.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") - $Global:XmlWriter.WriteAttributeString('edge', "1") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - $Global:XmlWriter.WriteAttributeString('source', $Global:VNETDrawID) - $Global:XmlWriter.WriteAttributeString('target', $VNETDID.VNETid) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('relative', "1") - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - else - { - $Global:sizeL = $VNETSUB.properties.subnets.properties.addressPrefix.count - $BrokenVNET = if($VNETSUB.properties.subnets.properties.addressPrefix.count){'Not Broken'}else{'Broken'} - - if($VNETSUB.properties.addressSpace.addressPrefixes.count -ge 10) - { - $AddSpace = ($VNETSUB.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' - }Else{ - $AddSpace = ($VNETSUB.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) - } - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ($VNETSUB.name + "`n" + $AddSpace)) - if($VNETSUB.properties.dhcpoptions.dnsServers) - { - $Global:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNETSUB.properties.dhcpoptions.dnsServers) - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNETSUB.properties.enableDdosProtection) - } - else - { - $Global:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNETSUB.properties.enableDdosProtection) - } - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVNET $Global:vnetLoc $Global:vnetLoc1 "67" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - - $TwoTarget = ($Global:CellID+'-'+($Global:IDNum-1)) - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('Peering_Name', $Peer.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") - $Global:XmlWriter.WriteAttributeString('edge', "1") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - $Global:XmlWriter.WriteAttributeString('source', $Global:Source) - $Global:XmlWriter.WriteAttributeString('target', $TwoTarget) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('relative', "1") - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - - if($VNETSUB.properties.enableDdosProtection -eq $true) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDDOS ($Global:vnetLoc - 20) ($Global:vnetLoc1 + 15) "23" "28" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - if ($Global:sizeL -gt 5) - { - $Global:sizeL = $Global:sizeL / 2 - $Global:sizeL = [math]::ceiling($Global:sizeL) - $Global:sizeC = $Global:sizeL - $Global:sizeL = (($Global:sizeL * 210) + 30) - - if('gatewaysubnet' -in $VNETSUB.properties.subnets.name) - { - HubContainer ($Global:vnetLoc + 100) ($Global:vnetLoc1 - 20) $Global:sizeL "490" $VNETSUB.name - } - else - { - VNETContainer ($Global:vnetLoc + 100) ($Global:vnetLoc1 - 20) $Global:sizeL "490" $VNETSUB.name - } - - $Global:VNETSquare = ($Global:CellID+'-'+($Global:IDNum-1)) - - $SubName = $Subscriptions | Where-Object {$_.id -eq $VNETSUB.subscriptionId} - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $SubName.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconSubscription $Global:sizeL 460 "67" "40" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $ADVS = '' - $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} - If($ADVS) - { - $Count = 1 - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - foreach ($ADV in $ADVS) - { - $Attr1 = ('Recommendation'+[string]$Count) - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconCostMGMT ($Global:sizeL + 150) 460 "30" "35" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - } - - Subnet ($Global:vnetLoc + 120) $VNETSUB $Global:IDNum $Global:DiagramCache $Global:ContID - - $Global:vnetLoc1 = $Global:vnetLoc1 + 230 - - if($Global:VNETPIP) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $Count = 1 - Foreach ($PIPDetail in $Global:VNETPIP) - { - $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) - $Global:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDet ($Global:sizeL + 500) 225 "42.63" "44" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - Connect ($Global:CellID+'-'+($Global:IDNum-1)) $Global:ContID $Global:ContID - } - - $Global:Alt = $Global:Alt + 650 - } - else - { - $Global:sizeL = (($Global:sizeL * 210) + 30) - - if($BrokenVNET -eq 'Not Broken') - { - if('gatewaysubnet' -in $VNETSUB.properties.subnets.name) - { - HubContainer ($Global:vnetLoc + 100) ($Global:vnetLoc1 - 20) $Global:sizeL "260" $VNETSUB.name - } - else - { - VNETContainer ($Global:vnetLoc + 100) ($Global:vnetLoc1 - 20) $Global:sizeL "260" $VNETSUB.name - } - } - else - { - BrokenContainer ($Global:vnetLoc + 100) ($Global:vnetLoc1 - 20) "250" "260" 'Broken Peering' - $Global:sizeL = '250' - } - - $Global:VNETSquare = ($Global:CellID+'-'+($Global:IDNum-1)) - - $SubName = $Subscriptions | Where-Object {$_.id -eq $VNETSUB.subscriptionId} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $SubName.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconSubscription $Global:sizeL 225 "67" "40" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $ADVS = '' - $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} - If($ADVS) - { - $Count = 1 - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - foreach ($ADV in $ADVS) - { - $Attr1 = ('Recommendation'+[string]$Count) - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconCostMGMT ($Global:sizeL + 150) 225 "30" "35" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - } - - Subnet ($Global:vnetLoc + 120) $VNETSUB $Global:IDNum $Global:DiagramCache $Global:ContID - - if($Global:VNETPIP) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $Count = 1 - Foreach ($PIPDetail in $Global:VNETPIP) - { - $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') - $Global:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) - $Global:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) - - $Count ++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconDet ($Global:sizeL+ 500) 107 "42.63" "44" $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - Connect ($Global:CellID+'-'+($Global:IDNum-1)) $Global:ContID $Global:ContID - - } - - } - - $tmp =@{ - 'VNETid' = $TwoTarget; - 'VNET' = $VNETSUB.id - } - $Global:VNETHistory += $tmp - - $Global:vnetLoc1 = $Global:vnetLoc1 + 350 - } - } - $Global:Alt = $Global:vnetLoc1 - } - - Function Subnet { - Param($subloc,$VNET,$IDNum,$DiagramCache,$ContID) - - $NameString = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - New-Variable -Name ('Run_'+$NameString) -Scope Global - - Set-Variable -name ('Run_'+$NameString) -Value ([PowerShell]::Create()).AddScript({param($subloc,$VNET,$IDNum,$DiagramCache,$ContID,$Resources) - - $etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $IDNum++ - - $SubFile = ($DiagramCache+$CellID+'.xml') - - ###################################################### STENCILS #################################################### - - Function Stensils { - $Global:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" - - $Global:IconConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" - $Global:IconExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" - $Global:IconVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" - $Global:IconVGW2 = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" - $Global:IconVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" - $Global:IconTraffic = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Local_Network_Gateways.svg;" #width="68" height="68" - $Global:IconNIC = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;" #width="68" height="60" - $Global:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" - $Global:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" - $Global:IconNSG = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Network_Security_Groups.svg;" # width="26.35" height="32" - $Global:IconUDR = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Route_Tables.svg;" #width="30.97" height="30" - $Global:IconDDOS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;" # width="23" height="28" - $Global:IconPIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" - $Global:IconNAT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/NAT.svg;" # width="65" height="52" - - <########################## Azure Generic Stencils #############################> - - $Global:SymError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="50" height="50" - $Global:SymInfo = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Information.svg;" #width="64" height="64" - $Global:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" - $GLobal:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" - $Global:IconBastions = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/general/Launch_Portal.svg;" #width="68" height="67" - $Global:IconContain = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Container_Instances.svg;" #width="64" height="68" - $Global:IconVWAN = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_WANs.svg;" #width="65" height="64" - $Global:IconCostMGMT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Cost_Analysis.svg;" #width="60" height="70" - - <########################## Azure Computing Stencils #############################> - - $Global:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" - $Global:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" - $Global:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" - $Global:IconARO = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/mscae/OpenShift.svg;" #width="50" height="46" - $Global:IconFunApps = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Function_Apps.svg;" # width="68" height="60" - - <########################## Azure Service Stencils #############################> - - $Global:IconAPIMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/app_services/API_Management_Services.svg;" #width="65" height="60" - $Global:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" - - <########################## Azure Storage Stencils #############################> - - $Global:IconNetApp = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;" #width="65" height="52" - - <########################## Azure Storage Stencils #############################> - - $Global:IconDataExplorer = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;" #width="68" height="68" - - <########################## Other Stencils #############################> - - $Global:IconFWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;" #width="71" height="60" - $Global:IconDet = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/other/Detonation.svg;" #width="42.63" height="44" - $Global:IconAppGWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;" #width="64" height="64" - $Global:IconBricks = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;" #width="60" height="68" - $Global:IconError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="30" height="30" - $Global:OnPrem = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/mscae/Exchange_On_premises_Access.svg;" #width="168.2" height="290" - $Global:Signature = "aspect=fixed;html=1;points=[];align=left;image;fontSize=22;image=img/lib/azure2/general/Dev_Console.svg;" #width="27.5" height="22" - $Global:CloudOnly = "aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;" #width="380.77" height="275" - - } - - ####################################################### PROCTYPE #################################################### - - - Function ProcType { - Param($sub,$subloc,$Alt0,$ContainerID) - - $temp = '' - remove-variable TrueTemp -ErrorAction SilentlyContinue - remove-variable RESNames -ErrorAction SilentlyContinue - - <####################################################### FIND THE RESOURCES IN THE SUBNET ###################################################################> - - if($sub.properties.resourceNavigationLinks.properties.linkedResourceType -eq 'Microsoft.ApiManagement/service') - { - $TrueTemp = 'APIM' - } - if($sub.properties.serviceAssociationLinks.properties.link -and $null -eq $TrueTemp) - { - if($sub.properties.serviceAssociationLinks.properties.link.split("/")[6] -eq 'Microsoft.Web') - { - $TrueTemp = 'App Service' - } - } - if($sub.properties.applicationGatewayIPConfigurations.id -and $null -eq $TrueTemp) - { - if($sub.properties.applicationGatewayIPConfigurations.id.split("/")[7] -eq 'applicationGateways') - { - $TrueTemp = 'applicationGateways' - } - } - if($sub.properties.ipconfigurations.id.count -eq 1 -and $null -eq $TrueTemp) - { - if($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'virtualNetworkGateways') - { - $TrueTemp = 'virtualNetworkGateways' - } - elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'loadBalancers') - { - $TrueTemp = 'loadBalancers' - } - elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'applicationGateways') - { - $TrueTemp = 'applicationGateways' - } - elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'bastionHosts') - { - $TrueTemp = 'bastionHosts' - } - elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'azureFirewalls') - { - $TrueTemp = 'azureFirewalls' - } - } - if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Databricks/workspaces' -and $null -eq $TrueTemp) - { - $TrueTemp = 'DataBricks' - } - if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Web/serverfarms' -and $null -eq $TrueTemp) - { - $TrueTemp = 'App Service' - } - if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.ContainerInstance/containerGroups' -and $null -eq $TrueTemp) - { - $TrueTemp = 'Container Instance' - } - if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Netapp/volumes' -and $null -eq $TrueTemp) - { - $TrueTemp = 'NetApp' - } - if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Kusto/clusters' -and $null -eq $TrueTemp) - { - $TrueTemp = 'Data Explorer Clusters' - } - - if([string]::IsNullOrEmpty($TrueTemp)) - { - $AKS = $Global:AKS - if($sub.id -in $AKS.properties.agentPoolProfiles.vnetSubnetID) - { - $TrueTemp = 'AKS' - } - } - if([string]::IsNullOrEmpty($TrueTemp)) - { - $Types = @() - - Foreach($type in $sub.properties.ipconfigurations.id) - { - if($type.Split("/")[8] -like 'aks-*') - { - $Types += 'AKS' - } - if($type.Split("/")[8] -like 'gwhost*') - { - $Types += 'APIM' - } - else - { - $Types += $type.Split("/")[7] - } - } - $temp = $Types | Group-Object | Sort-Object -Property Count -Descending - if($temp) - { - $TrueTemp = $temp[0].name - } - } - - if([string]::IsNullOrEmpty($TrueTemp)) - { - if ($sub.id -in ($Global:VMSS).properties.virtualMachineProfile.networkprofile.networkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id) - { - $TrueTemp = 'virtualMachineScaleSets' - } - } - - <#################################################### FIND RESOURCE NAME AND DETAILS #################################################################> - - if($TrueTemp -eq 'networkInterfaces') - { - $NIcNames = $Global:NIC | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id} - - if($sub.properties.privateEndpoints.id) - { - $PrivEndNames = $Global:PrivEnd | Where-Object {$_.properties.networkInterfaces.id -in $NIcNames.id} - $TrueTemp = 'privateLinkServices' - $RESNames = $PrivEndNames - } - else - { - $VMNamesAro = $Global:VM | Where-Object {$_.properties.networkprofile.networkInterfaces.id -in $NIcNames.id} - if($VMNamesAro.properties.storageprofile.imageReference.offer -like 'aro*') - { - $ARONames = $Global:ARO | Where-Object {$_.properties.masterprofile.subnetId -eq $sub.id -or $_.properties.workerProfiles.subnetId -eq $sub.id} - $TrueTemp = 'Open Shift' - $RESNames = $ARONames - } - if($TrueTemp -ne 'Open Shift') - { - $VMs = @() - $VMNames = ($Global:VM).properties.networkprofile.networkInterfaces.id | Where-Object {$_ -in $NIcNames.id} - $VMs = foreach($NIC in $VMNames) - { - $Global:VM| Where-Object {$NIC -in $_.properties.networkprofile.networkInterfaces.id} - } - if($VMs) - { - $TrueTemp = 'Virtual Machine' - $RESNames = $VMs - } - } - if($TrueTemp -eq 'networkInterfaces') - { - $TrueTemp = 'Network Interface' - $RESNames = $NIcNames - } - } - } - if($TrueTemp -eq 'AKS') - { - $AKSNames = $Global:AKS | Where-Object {$_.properties.agentPoolProfiles.vnetSubnetID -eq $sub.id} - $RESNames = $AKSNames - } - if($TrueTemp -eq 'Data Explorer Clusters') - { - $KustoNames = $Global:Kusto | Where-Object {$_.properties.virtualNetworkConfiguration.subnetid -eq $sub.id} - $RESNames = $KustoNames - } - if($TrueTemp -eq 'applicationGateways') - { - $AppGTWNames = $Global:AppGtw| Where-Object {$_.properties.gatewayIPConfigurations.id -in $sub.properties.applicationGatewayIPConfigurations.id} - $RESNames = $AppGTWNames - } - if($TrueTemp -eq 'DataBricks') - { - $DatabriksNames = @() - $Databricks = $Global:Databricks - $DatabriksNames = Foreach($Data in $Databricks) - { - if($Data.properties.parameters.customVirtualNetworkId.value+'/subnets/'+$Data.properties.parameters.customPrivateSubnetName.value -eq $sub.id -or $Data.properties.parameters.customVirtualNetworkId.value+'/subnets/'+$Data.properties.parameters.custompublicSubnetName.value -eq $sub.id) - { - $Data - } - } - $RESNames = $DatabriksNames - } - if($TrueTemp -eq 'App Service') - { - $Apps = $Global:AppWeb | Where-Object {$_.properties.virtualNetworkSubnetId -eq $Sub.id} - if($Apps.kind -like 'functionapp*') - { - $FuntionAppNames = $Apps - $TrueTemp = 'Function App' - $RESNames = $FuntionAppNames - } - else - { - $ServiceAppNames = $Apps - $RESNames = $Apps - } - } - if($TrueTemp -eq 'APIM') - { - $APIMNames = $Global:APIM | Where-Object {$_.properties.virtualNetworkConfiguration.subnetResourceId -eq $sub.id} - $RESNames = $APIMNames - } - if($TrueTemp -eq 'loadBalancers') - { - $LBNames = $Global:LB | Where-Object {$_.properties.frontendIPConfigurations.id -in $sub.properties.ipconfigurations.id} - $RESNames = $LBNames - } - if($TrueTemp -eq 'virtualMachineScaleSets') - { - $VMSSNames = $Global:VMSS | Where-Object {$_.properties.virtualMachineProfile.networkProfile.networkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id -eq $sub.id } - $RESNames = $VMSSNames - } - if($TrueTemp -eq 'virtualNetworkGateways') - { - $VPNGTWNames = $Global:AZVGWs | Where-Object {$_.properties.ipconfigurations.properties.subnet.id -eq $sub.id } - $RESNames = $VPNGTWNames - } - if($TrueTemp -eq 'bastionHosts') - { - $BastionNames = $Global:Bastion | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id } - $RESNames = $BastionNames - } - if($TrueTemp -eq 'azureFirewalls') - { - $AzFWNames = $Global:FW | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id } - $RESNames = $AzFWNames - } - if($TrueTemp -eq 'Container Instance') - { - $ContainerNames = '' - $ContNICs = $Global:NetProf | Where-Object {$_.properties.containerNetworkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id -eq $sub.id} - $ContainerNames = $Global:Container | Where-Object {$_.properties.networkprofile.id -in $ContNICs.id} - $RESNames = $ContainerNames - if([string]::IsNullOrEmpty($ContainerNames)) - { - $ARONames = $Global:ARO | Where-Object {$_.properties.masterprofile.subnetId -eq $sub.id -or $_.properties.workerProfiles.subnetId -eq $sub.id} - $TrueTemp = 'Open Shift' - $RESNames = $ARONames - } - } - if($TrueTemp -eq 'NetApp') - { - $NetAppNames = $Global:ANF | Where-Object {$_.properties.subnetId -eq $sub.id } - $RESNames = $NetAppNames - } - - <###################################################### DROP THE ICONS ######################################################> - - switch ($TrueTemp) - { - 'Virtual Machine' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' VMs')) - - $Count = 1 - foreach ($VMName in $RESNames.Name) - { - $Attr1 = ('VirtualMachine-'+[string]("{0:d3}" -f $Count)) - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$VMName) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVMs ($subloc+64) ($Alt0+40) "69" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - $Global:XmlTempWriter.WriteAttributeString('VM_Size', [string]$RESNames.properties.hardwareProfile.vmSize) - $Global:XmlTempWriter.WriteAttributeString('OS', [string]$RESNames.properties.storageProfile.osDisk.osType) - $Global:XmlTempWriter.WriteAttributeString('OS_Disk_Size_GB', [string]$RESNames.properties.storageProfile.osDisk.diskSizeGB) - $Global:XmlTempWriter.WriteAttributeString('Image_Publisher', [string]$RESNames.properties.storageProfile.imageReference.publisher) - $Global:XmlTempWriter.WriteAttributeString('Image_SKU', [string]$RESNames.properties.storageProfile.imageReference.sku) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVMs ($subloc+64) ($Alt0+40) "69" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - 'AKS' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' AKS Clusters')) - - $Count = 1 - foreach ($AKSName in $RESNames.Name) - { - $Attr1 = ('Kubernetes_Cluster-'+[string]("{0:d3}" -f $Count)) - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$AKSName) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAKS ($subloc+65) ($Alt0+40) "68" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) - - $Count = 1 - foreach($Pool in $RESNames.properties.agentPoolProfiles) - { - $Attr1 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Count') - $Attr3 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Size') - $Attr4 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Version') - $Attr5 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Mode') - $Attr6 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Max_Pods') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$Pool.name) - $Global:XmlTempWriter.WriteAttributeString($Attr2, [string]($Pool | Select-Object -Property 'count').count) - $Global:XmlTempWriter.WriteAttributeString($Attr3, [string]$Pool.vmSize) - $Global:XmlTempWriter.WriteAttributeString($Attr4, [string]$Pool.orchestratorVersion) - $Global:XmlTempWriter.WriteAttributeString($Attr5, [string]$Pool.mode) - $Global:XmlTempWriter.WriteAttributeString($Attr6, [string]$Pool.maxPods) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAKS ($subloc+65) ($Alt0+40) "68" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - 'virtualMachineScaleSets' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Virtual Machine Scale Sets')) - - $Count = 1 - foreach ($ResName in $RESNames.Name) - { - $Attr1 = ('VMSS-'+[string]("{0:d3}" -f $Count)) - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVMSS ($subloc+65) ($Alt0+40) "68" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) - - $Global:XmlTempWriter.WriteAttributeString('VMSS_Name', [string]$RESNames.name) - $Global:XmlTempWriter.WriteAttributeString('Instances', [string]$temp[0].Count) - $Global:XmlTempWriter.WriteAttributeString('VMSS_SKU_Tier', [string]$RESNames.sku.tier) - $Global:XmlTempWriter.WriteAttributeString('VMSS_Upgrade_Policy', [string]$RESNames.Properties.upgradePolicy.mode) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVMSS ($subloc+65) ($Alt0+40) "68" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'loadBalancers' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Load Balancers')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('LB-'+[string]("{0:d3}" -f $Count)+'-SKU') - $Attr3 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Backends') - $Attr4 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Frontends') - $Attr5 = ('LB-'+[string]("{0:d3}" -f $Count)+'-LB_Rules') - $Attr6 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Probes') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - $Global:XmlTempWriter.WriteAttributeString($Attr2, [string]$ResName.sku.name) - $Global:XmlTempWriter.WriteAttributeString($Attr3, [string]$ResName.properties.backendAddressPools.properties.backendIPConfigurations.id.count) - $Global:XmlTempWriter.WriteAttributeString($Attr4, [string]$ResName.properties.frontendIPConfigurations.properties.count) - $Global:XmlTempWriter.WriteAttributeString($Attr5, [string]$ResName.properties.loadBalancingRules.count) - $Global:XmlTempWriter.WriteAttributeString($Attr6, [string]$ResName.properties.probes.count) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconLBs ($subloc+65) ($Alt0+40) "72" "72" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $Global:XmlTempWriter.WriteAttributeString('Load_Balancer_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Load_Balancer_SKU', [string]$ResNames.sku.name) - $Global:XmlTempWriter.WriteAttributeString('Backends', [string]$ResNames.properties.backendAddressPools.properties.backendIPConfigurations.id.count) - $Global:XmlTempWriter.WriteAttributeString('Frontends', [string]$ResNames.properties.frontendIPConfigurations.properties.count) - $Global:XmlTempWriter.WriteAttributeString('LB_Rules', [string]$ResNames.properties.loadBalancingRules.count) - $Global:XmlTempWriter.WriteAttributeString('Probes', [string]$ResNames.properties.probes.count) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconLBs ($subloc+65) ($Alt0+40) "72" "72" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - 'virtualNetworkGateways' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Virtual Network Gateways')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Network_Gateway-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVGW ($subloc+80) ($Alt0+40) "52" "69" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconVGW ($subloc+80) ($Alt0+40) "52" "69" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'azureFirewalls' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Firewalls')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-SKU') - $Attr3 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-Threat_Intel_Mode') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - $Global:XmlTempWriter.WriteAttributeString($Attr2, [string]$ResName.properties.sku.tier) - $Global:XmlTempWriter.WriteAttributeString($Attr3, [string]$ResName.properties.threatIntelMode) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconFWs ($subloc+65) ($Alt0+40) "71" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) - - - $Global:XmlTempWriter.WriteAttributeString('Firewall_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('SKU_Tier', [string]$ResNames.properties.sku.tier) - $Global:XmlTempWriter.WriteAttributeString('Threat_Intel_Mode', [string]$ResNames.properties.threatIntelMode) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconFWs ($subloc+65) ($Alt0+40) "71" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'privateLinkServices' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Private Endpoints')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('PVE-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconPVTs ($subloc+65) ($Alt0+40) "72" "66" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconPVTs ($subloc+65) ($Alt0+40) "72" "66" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'applicationGateways' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Application Gateways')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Name') - $Attr2 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-SKU') - $Attr3 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Min_Capacity') - $Attr4 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Max_Capacity') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - $Global:XmlTempWriter.WriteAttributeString($Attr2, [string]$RESName.Properties.sku.tier) - $Global:XmlTempWriter.WriteAttributeString($Attr3, [string]$RESName.Properties.autoscaleConfiguration.minCapacity) - $Global:XmlTempWriter.WriteAttributeString($Attr4, [string]$RESName.Properties.autoscaleConfiguration.maxCapacity) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAppGWs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $Global:XmlTempWriter.WriteAttributeString('App_Gateway_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('App_Gateway_SKU', [string]$RESNames.Properties.sku.tier) - $Global:XmlTempWriter.WriteAttributeString('Autoscale_Min_Capacity', [string]$RESNames.Properties.autoscaleConfiguration.minCapacity) - $Global:XmlTempWriter.WriteAttributeString('Autoscale_Max_Capacity', [string]$RESNames.Properties.autoscaleConfiguration.maxCapacity) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAppGWs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'bastionHosts' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Bastion Hosts')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Bastion-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconBastions ($subloc+65) ($Alt0+40) "68" "67" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconBastions ($subloc+65) ($Alt0+40) "68" "67" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - 'APIM' { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $APIMHost = [string]($RESNames.properties.hostnameConfigurations | Where-Object {$_.defaultSslBinding -eq $true}).hostname - - $Global:XmlTempWriter.WriteAttributeString('APIM_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.sku.name) - $Global:XmlTempWriter.WriteAttributeString('VNET_Type', [string]$RESNames.properties.virtualNetworkType) - $Global:XmlTempWriter.WriteAttributeString('Default_Hostname', $APIMHost) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAPIMs ($subloc+65) ($Alt0+40) "65" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - 'App Service' { - if($ServiceAppNames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' App Services')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('AppService-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAPPs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$ResNames.name) - - $Global:XmlTempWriter.WriteAttributeString('App_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Default_Hostname', [string]$RESNames.properties.defaultHostName) - $Global:XmlTempWriter.WriteAttributeString('Enabled', [string]$RESNames.properties.enabled) - $Global:XmlTempWriter.WriteAttributeString('State', [string]$RESNames.properties.state) - $Global:XmlTempWriter.WriteAttributeString('Inbound_IP_Address', [string]$RESNames.properties.inboundIpAddress) - $Global:XmlTempWriter.WriteAttributeString('Kind', [string]$RESNames.properties.kind) - $Global:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.properties.sku) - $Global:XmlTempWriter.WriteAttributeString('Workers', [string]$RESNames.properties.siteConfig.numberOfWorkers) - $Global:XmlTempWriter.WriteAttributeString('Min_Workers', [string]$RESNames.properties.siteConfig.minimumElasticInstanceCount) - $Global:XmlTempWriter.WriteAttributeString('Site_Properties', [string]$RESNames.properties.siteProperties.properties.value) - - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconAPPs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - } - 'Function App' { - if($FuntionAppNames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Function Apps')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('FunctionApp-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconFunApps ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$ResNames.name) - - $Global:XmlTempWriter.WriteAttributeString('App_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Default_Hostname', [string]$RESNames.properties.defaultHostName) - $Global:XmlTempWriter.WriteAttributeString('Enabled', [string]$RESNames.properties.enabled) - $Global:XmlTempWriter.WriteAttributeString('State', [string]$RESNames.properties.state) - $Global:XmlTempWriter.WriteAttributeString('Inbound_IP_Address', [string]$RESNames.properties.inboundIpAddress) - $Global:XmlTempWriter.WriteAttributeString('Kind', [string]$RESNames.properties.kind) - $Global:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.properties.sku) - $Global:XmlTempWriter.WriteAttributeString('Workers', [string]$RESNames.properties.siteConfig.numberOfWorkers) - $Global:XmlTempWriter.WriteAttributeString('Min_Workers', [string]$RESNames.properties.siteConfig.minimumElasticInstanceCount) - $Global:XmlTempWriter.WriteAttributeString('Site_Properties', [string]$RESNames.properties.siteProperties.properties.value) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconFunApps ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - } - 'DataBricks' { - if($DatabriksNames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Databricks')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Databrick-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconBricks ($subloc+65) ($Alt0+40) "60" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $Global:XmlTempWriter.WriteAttributeString('Databrick_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Workspace_URL', [string]$RESNames.properties.workspaceUrl ) - $Global:XmlTempWriter.WriteAttributeString('Pricing_Tier', [string]$RESNames.sku.name) - $Global:XmlTempWriter.WriteAttributeString('Storage_Account', [string]$RESNames.properties.parameters.storageAccountName.value) - $Global:XmlTempWriter.WriteAttributeString('Storage_Account_SKU', [string]$RESNames.properties.parameters.storageAccountSkuName.value) - $Global:XmlTempWriter.WriteAttributeString('Relay_Namespace', [string]$RESNames.properties.parameters.relayNamespaceName.value) - $Global:XmlTempWriter.WriteAttributeString('Require_Infrastructure_Encryption', [string]$RESNames.properties.parameters.requireInfrastructureEncryption.value) - $Global:XmlTempWriter.WriteAttributeString('Enable_Public_IP', [string]$RESNames.properties.parameters.enableNoPublicIp.value) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconBricks ($subloc+65) ($Alt0+40) "60" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - } - 'Open Shift' { - if($ARONames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' OpenShift Clusters')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('OpenShift_Cluster-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconARO ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - - $Global:XmlTempWriter.WriteAttributeString('ARO_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('OpenShift_Version', [string]$RESNames.properties.clusterProfile.version) - $Global:XmlTempWriter.WriteAttributeString('OpenShift_Console', [string]$RESNames.properties.consoleProfile.url) - $Global:XmlTempWriter.WriteAttributeString('Worker_VM_Count', [string]$RESNames.properties.workerprofiles.Count) - $Global:XmlTempWriter.WriteAttributeString('Worker_VM_Size', [string]$RESNames.properties.workerprofiles.vmSize[0]) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconARO ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - } - 'Container Instance' { - if($ContainerNames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Container Intances')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Container_Intance-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconContain ($subloc+65) ($Alt0+40) "64" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconContain ($subloc+65) ($Alt0+40) "64" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - } - 'NetApp' { - if($NetAppNames) - { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' NetApp Volumes')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('NetApp_Volume-'+[string]("{0:d3}" -f $Count)) - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconNetApp ($subloc+65) ($Alt0+40) "65" "52" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]1+' NetApp Volume')) - $Global:XmlTempWriter.WriteAttributeString('NetApp_Volume_Name', [string]$ResName.name) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconNetApp ($subloc+65) ($Alt0+40) "65" "52" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - } - 'Data Explorer Clusters' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Data Explorer Clusters')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('Data_Cluster-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconDataExplorer ($subloc+65) ($Alt0+40) "68" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) - $Global:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_Name', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_URI', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_State', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('SKU_Tier', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('Computer_Specifications', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('AutoScale_Enabled', [string]$ResNames.name) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconDataExplorer ($subloc+65) ($Alt0+40) "68" "68" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - } - 'Network Interface' { - if($RESNames.count -gt 1) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Network Interfaces')) - - $Count = 1 - foreach ($ResName in $RESNames) - { - $Attr1 = ('NIC-'+[string]("{0:d3}" -f $Count)+'-Name') - - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Count ++ - } - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconNIC ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - else - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ([string]1+' Network Interface')) - - $Attr1 = ('NIC-Name') - $Global:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) - - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconNIC ($subloc+65) ($Alt0+40) "68" "60" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - } - '' {} - default {} - } - if($sub.properties.networkSecurityGroup.id) - { - $NSG = $sub.properties.networkSecurityGroup.id.split('/')[8] - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', '') - $Global:XmlTempWriter.WriteAttributeString('Network_Security_Group', [string]$NSG) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconNSG ($subloc+160) ($Alt0+15) "26.35" "32" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - } - if($sub.properties.routeTable.id) - { - $UDR = $sub.properties.routeTable.id.split('/')[8] - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', '') - $Global:XmlTempWriter.WriteAttributeString('Route_Table', [string]$UDR) - $Global:XmlTempWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon2 $IconUDR ($subloc+15) ($Alt0+15) "30.97" "30" $ContainerID - - $Global:XmlTempWriter.WriteEndElement() - - } - if($sub.properties.ipconfigurations.id) - { - Foreach($SubIPs in $sub.properties.ipconfigurations) - { - $Global:VNETPIP += $Global:CleanPIPs | Where-Object {$_.properties.ipConfiguration.id -eq $SubIPs.id} - } - } - } - - ######################################################### ICON ####################################################### - - Function Icon2 { - Param($Style,$x,$y,$w,$h,$p) - - $Global:XmlTempWriter.WriteStartElement('mxCell') - $Global:XmlTempWriter.WriteAttributeString('style', $Style) - $Global:XmlTempWriter.WriteAttributeString('vertex', "1") - $Global:XmlTempWriter.WriteAttributeString('parent', $p) - - $Global:XmlTempWriter.WriteStartElement('mxGeometry') - $Global:XmlTempWriter.WriteAttributeString('x', $x) - $Global:XmlTempWriter.WriteAttributeString('y', $y) - $Global:XmlTempWriter.WriteAttributeString('width', $w) - $Global:XmlTempWriter.WriteAttributeString('height', $h) - $Global:XmlTempWriter.WriteAttributeString('as', "geometry") - $Global:XmlTempWriter.WriteEndElement() - - $Global:XmlTempWriter.WriteEndElement() - } - - ######################################################## SUBNET ####################################################### - - Stensils - - $Global:XmlTempWriter = New-Object System.XMl.XmlTextWriter($SubFile,$Null) - - $Global:XmlTempWriter.Formatting = 'Indented' - $Global:XmlTempWriter.Indentation = 2 - - $Global:XmlTempWriter.WriteStartDocument() - - $Global:XmlTempWriter.WriteStartElement('mxfile') - $Global:XmlTempWriter.WriteAttributeString('host', 'Electron') - $Global:XmlTempWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') - $Global:XmlTempWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') - $Global:XmlTempWriter.WriteAttributeString('etag', $etag) - $Global:XmlTempWriter.WriteAttributeString('version', '15.4.0') - $Global:XmlTempWriter.WriteAttributeString('type', 'device') - - $Global:XmlTempWriter.WriteStartElement('diagram') - $Global:XmlTempWriter.WriteAttributeString('id', $DiagID) - $Global:XmlTempWriter.WriteAttributeString('name', 'Network Topology') - - $Global:XmlTempWriter.WriteStartElement('mxGraphModel') - $Global:XmlTempWriter.WriteAttributeString('dx', "1326") - $Global:XmlTempWriter.WriteAttributeString('dy', "798") - $Global:XmlTempWriter.WriteAttributeString('grid', "1") - $Global:XmlTempWriter.WriteAttributeString('gridSize', "10") - $Global:XmlTempWriter.WriteAttributeString('guides', "1") - $Global:XmlTempWriter.WriteAttributeString('tooltips', "1") - $Global:XmlTempWriter.WriteAttributeString('connect', "1") - $Global:XmlTempWriter.WriteAttributeString('arrows', "1") - $Global:XmlTempWriter.WriteAttributeString('fold', "1") - $Global:XmlTempWriter.WriteAttributeString('page', "1") - $Global:XmlTempWriter.WriteAttributeString('pageScale', "1") - $Global:XmlTempWriter.WriteAttributeString('pageWidth', "850") - $Global:XmlTempWriter.WriteAttributeString('pageHeight', "1100") - $Global:XmlTempWriter.WriteAttributeString('math', "0") - $Global:XmlTempWriter.WriteAttributeString('shadow', "0") - - $Global:XmlTempWriter.WriteStartElement('root') - - $Global:XmlTempWriter.WriteStartElement('mxCell') - $Global:XmlTempWriter.WriteAttributeString('id', "0") - $Global:XmlTempWriter.WriteEndElement() - - $Global:XmlTempWriter.WriteStartElement('mxCell') - $Global:XmlTempWriter.WriteAttributeString('id', "1") - $Global:XmlTempWriter.WriteAttributeString('parent', "0") - $Global:XmlTempWriter.WriteEndElement() - - $sizeL = $VNET.properties.subnets.properties.addressPrefix.count - if ($sizeL -gt 5) - { - $sizeL = $sizeL / 2 - $sizeL = [math]::ceiling($sizeL) - $sizeC = $sizeL - $sizeL = (($sizeL * 210) + 30) - - $subloc0 = 20 - $SubC = 0 - $alt1 = 40 - $Global:VNETPIP = @() - foreach($Sub in $VNET.properties.subnets) - { - if ($SubC -eq $sizeC) - { - $Alt1 = $Alt1 + 230 - $subloc0 = 20 - $SubC = 0 - } - - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ("`n" + "`n" + "`n" + "`n" + "`n" + "`n" +[string]$sub.Name + "`n" + [string]$sub.properties.addressPrefix)) - $Global:XmlTempWriter.WriteAttributeString('id', ($CellID+'-'+($IDNum++))) - - Icon2 "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" $subloc0 $Alt1 "200" "200" $ContID - - $Global:XmlTempWriter.WriteEndElement() - - ProcType $sub $subloc0 $Alt1 $ContID - - $subloc = $subloc + 210 - $subloc0 = $subloc0 + 210 - $SubC ++ - } - - } - Else - { - $sizeL = (($sizeL * 210) + 30) - $subloc0 = 20 - $Global:VNETPIP = @() - foreach($Sub in $VNET.properties.subnets) - { - $Global:XmlTempWriter.WriteStartElement('object') - $Global:XmlTempWriter.WriteAttributeString('label', ("`n" + "`n" + "`n" + "`n" + "`n" + "`n" +[string]$sub.Name + "`n" + [string]$sub.properties.addressPrefix)) - $Global:XmlTempWriter.WriteAttributeString('id', ($CellID+'-'+($IDNum++))) - - Icon2 "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" $subloc0 40 "200" "200" $ContID - - $Global:XmlTempWriter.WriteEndElement() - - ProcType $sub $subloc0 40 $ContID - - $subloc = $subloc + 210 - $subloc0 = $subloc0 + 210 - } - } - - $Global:XmlTempWriter.WriteEndElement() - - $Global:XmlTempWriter.WriteEndElement() - - $Global:XmlTempWriter.WriteEndElement() - $Global:XmlTempWriter.WriteEndElement() - - $Global:XmlTempWriter.WriteEndDocument() - $Global:XmlTempWriter.Flush() - $Global:XmlTempWriter.Close() - - }).AddArgument($subloc).AddArgument($VNET).AddArgument($IDNum).AddArgument($DiagramCache).AddArgument($ContID).AddArgument($Resources) - - New-Variable -Name ('Job_'+$NameString) -Scope Global - - Set-Variable -Name ('Job_'+$NameString) -Value ((get-variable -name ('Run_'+$NameString)).Value).BeginInvoke() - - $Global:jobs2 += (get-variable -name ('Job_'+$NameString)).Value - - $Global:jobs += $NameString - - #New-Variable -Name ('End_'+$NameString) - #Set-Variable -Name ('End_'+$NameString) -Value (((get-variable -name ('Run_'+$NameString)).Value).EndInvoke((get-variable -name ('Job_'+$NameString)).Value)) - - #((get-variable -name ('Run_'+$NameString)).Value).Dispose() - - #while ($Job.Runspace.IsCompleted -contains $false) {} - - KillJobs - - } - - Function KillJobs { - - foreach($job in $Global:jobs) - { - if((get-variable -name ('Job_'+$job) -Scope Global).Value.IsCompleted -eq $true) - { - #((get-variable -name ('Run_'+$job)).Value).EndInvoke((get-variable -name ('Job_'+$job)).Value) - ((get-variable -name ('Run_'+$job)).Value).Dispose() - Remove-Variable -Name ('Run_'+$job) -Scope Global -Force - Remove-Variable -Name ('Job_'+$job) -Scope Global -Force - } - } - } - - <# Function to create the Label of Version #> - Function label { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ('Powered by:'+ "`n" +'Azure Resource Inventory v3.0'+ "`n" +'https://github.com/microsoft/ARI')) - $Global:XmlWriter.WriteAttributeString('author', 'Claudio Merola') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - } - - Function Icon { - Param($Style,$x,$y,$w,$h,$p) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', $Style) - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Container { - Param($x,$y,$w,$h,$title) - $Global:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Connect { - Param($Source,$Target,$Parent) - - if($Parent){$Parent = $Parent}else{$Parent = 1} - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - $Global:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") - $Global:XmlWriter.WriteAttributeString('edge', "1") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $Parent) - $Global:XmlWriter.WriteAttributeString('source', $Source) - $Global:XmlWriter.WriteAttributeString('target', $Target) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('relative', "1") - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - } - - Function Variables0 { - Start-Job -Name 'DiagramVariables' -ScriptBlock { - $job = @() - - $AZVGWs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualnetworkgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZLGWs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/localnetworkgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVNETs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualnetworks'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZCONs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/connections'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZEXPROUTEs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/expressroutecircuits'} | Select-Object -Property * -Unique }).AddArgument($($args[0])) - $PIPs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/publicipaddresses'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVWAN = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualwans'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVHUB = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualhubs'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVPNSITES = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/vpnsites'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVERs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/expressroutegateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - - $AZAKS = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.containerservice/managedclusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVMSS = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Compute/virtualMachineScaleSets'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZNIC = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/networkinterfaces'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZPrivEnd = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/privateendpoints'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZVM = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.compute/virtualmachines'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZARO = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.redhatopenshift/openshiftclusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZKusto = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Kusto/clusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZAppGW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/applicationgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZDW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Databricks/workspaces'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZAppWeb = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.web/sites'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZAPIM = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.ApiManagement/service'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZLB = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/loadbalancers'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZBastion = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/bastionhosts'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZFW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/azurefirewalls'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZNetProf = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/networkprofiles'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZCont = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.ContainerInstance/containerGroups'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - $AZANF = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.netapp/netappaccounts/capacitypools/volumes'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) - - $jobAZVGWs = $AZVGWs.BeginInvoke() - $jobAZLGWs = $AZLGWs.BeginInvoke() - $jobAZVNETs = $AZVNETs.BeginInvoke() - $jobAZCONs = $AZCONs.BeginInvoke() - $jobAZEXPROUTEs = $AZEXPROUTEs.BeginInvoke() - $jobPIPs = $PIPs.BeginInvoke() - $jobAZVWAN = $AZVWAN.BeginInvoke() - $jobAZVHUB = $AZVHUB.BeginInvoke() - $jobAZVERs = $AZVERs.BeginInvoke() - $jobAZVPNSITES = $AZVPNSITES.BeginInvoke() - $jobAZAKS = $AZAKS.BeginInvoke() - $jobAZVMSS = $AZVMSS.BeginInvoke() - $jobAZNIC = $AZNIC.BeginInvoke() - $jobAZPrivEnd = $AZPrivEnd.BeginInvoke() - $jobAZVM = $AZVM.BeginInvoke() - $jobAZARO = $AZARO.BeginInvoke() - $jobAZKusto = $AZKusto.BeginInvoke() - $jobAZAppGW = $AZAppGW.BeginInvoke() - $jobAZDW = $AZDW.BeginInvoke() - $jobAZAppWeb = $AZAppWeb.BeginInvoke() - $jobAZAPIM = $AZAPIM.BeginInvoke() - $jobAZLB = $AZLB.BeginInvoke() - $jobAZBastion = $AZBastion.BeginInvoke() - $jobAZFW = $AZFW.BeginInvoke() - $jobAZNetProf = $AZNetProf.BeginInvoke() - $jobAZCont = $AZCont.BeginInvoke() - $jobAZANF = $AZANF.BeginInvoke() - - $job += $jobAZVGWs - $job += $jobAZLGWs - $job += $jobAZVNETs - $job += $jobAZCONs - $job += $jobAZEXPROUTEs - $job += $jobPIPs - $job += $jobAZVWAN - $job += $jobAZVHUB - $job += $jobAZVPNSITES - $job += $jobAZVERs - $job += $jobAZAKS - $job += $jobAZVMSS - $job += $jobAZNIC - $job += $jobAZPrivEnd - $job += $jobAZVM - $job += $jobAZARO - $job += $jobAZKusto - $job += $jobAZAppGW - $job += $jobAZDW - $job += $jobAZAppWeb - $job += $jobAZAPIM - $job += $jobAZLB - $job += $jobAZBastion - $job += $jobAZFW - $job += $jobAZNetProf - $job += $jobAZCont - $job += $jobAZANF - - while ($Job.Runspace.IsCompleted -contains $false) {} - - $AZVGWsS = $AZVGWs.EndInvoke($jobAZVGWs) - $AZLGWsS = $AZLGWs.EndInvoke($jobAZLGWs) - $AZVNETsS = $AZVNETs.EndInvoke($jobAZVNETs) - $AZCONsS = $AZCONs.EndInvoke($jobAZCONs) - $AZEXPROUTEsS = $AZEXPROUTEs.EndInvoke($jobAZEXPROUTEs) - $PIPsS = $PIPs.EndInvoke($jobPIPs) - $AZVWANS = $AZVWAN.EndInvoke($jobAZVWAN) - $AZVHUBS = $AZVHUB.EndInvoke($jobAZVHUB) - $AZVPNSITESS = $AZVPNSITES.EndInvoke($jobAZVPNSITES) - $AZVERsS = $AZVERs.EndInvoke($jobAZVERs) - $AZAKSs = $AZAKS.EndInvoke($jobAZAKS) - $AZVMSSs = $AZVMSS.EndInvoke($jobAZVMSS) - $AZNICs = $AZNIC.EndInvoke($jobAZNIC) - $AZPrivEnds = $AZPrivEnd.EndInvoke($jobAZPrivEnd) - $AZVMs = $AZVM.EndInvoke($jobAZVM) - $AZAROs = $AZARO.EndInvoke($jobAZARO) - $AZKustos = $AZKusto.EndInvoke($jobAZKusto) - $AZAppGWs = $AZAppGW.EndInvoke($jobAZAppGW) - $AZDWs = $AZDW.EndInvoke($jobAZDW) - $AZAppWebs = $AZAppWeb.EndInvoke($jobAZAppWeb) - $AZAPIMs = $AZAPIM.EndInvoke($jobAZAPIM) - $AZLBs = $AZLB.EndInvoke($jobAZLB) - $AZBastions = $AZBastion.EndInvoke($jobAZBastion) - $AZFWs = $AZFW.EndInvoke($jobAZFW) - $AZNetProfs = $AZNetProf.EndInvoke($jobAZNetProf) - $AZConts = $AZCont.EndInvoke($jobAZCont) - $AZANFs = $AZANF.EndInvoke($jobAZANF) - - - $AZVGWs.Dispose() - $AZLGWs.Dispose() - $AZVNETs.Dispose() - $AZCONs.Dispose() - $AZEXPROUTEs.Dispose() - $PIPs.Dispose() - $AZVWAN.Dispose() - $AZVHUB.Dispose() - $AZVPNSITES.Dispose() - $AZVERs.Dispose() - $AZAKS.Dispose() - $AZVMSS.Dispose() - $AZNIC.Dispose() - $AZPrivEnd.Dispose() - $AZVM.Dispose() - $AZARO.Dispose() - $AZKusto.Dispose() - $AZAppGW.Dispose() - $AZDW.Dispose() - $AZAppWeb.Dispose() - $AZAPIM.Dispose() - $AZLB.Dispose() - $AZBastion.Dispose() - $AZFW.Dispose() - $AZNetProf.Dispose() - $AZCont.Dispose() - $AZANF.Dispose() - - $CleanPIPs = $PIPsS | Where-Object {$_.id -notin $AZVGWsS.properties.ipConfigurations.properties.publicIPAddress.id} - - $Variables = @{ - 'AZVGWs' = $AZVGWsS; - 'AZLGWs' = $AZLGWsS; - 'AZVNETs' = $AZVNETsS; - 'AZCONs' = $AZCONsS; - 'AZEXPROUTEs' = $AZEXPROUTEsS; - 'PIPs' = $PIPsS; - 'AZVWAN' = $AZVWANS; - 'AZVHUB' = $AZVHUBS; - 'AZVPNSITES' = $AZVPNSITESS; - 'AZVERs' = $AZVERsS; - 'CleanPIPs' = $CleanPIPs; - 'AKS' = $AZAKSs; - 'VMSS' = $AZVMSSs; - 'NIC' = $AZNICs; - 'PrivEnd' = $AZPrivEnds; - 'VM' = $AZVMs; - 'ARO' = $AZAROs; - 'Kusto' = $AZKustos; - 'AppGtw' = $AZAppGWs; - 'DW' = $AZDWs; - 'AppWeb' = $AZAppWebs; - 'APIM' = $AZAPIMs; - 'LB' = $AZLBs; - 'Bastion' = $AZBastions; - 'FW' = $AZFWs; - 'NetProf' = $AZNetProfs; - 'Container' = $AZConts; - 'ANF' = $AZANFs - } - - $Variables - - } -ArgumentList $resources, $null - - } - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting Subnet files') | Out-File -FilePath $LogFile -Append - - $Subnetfiles = Get-ChildItem -Path $DiagramCache - - foreach($SubFile in $Subnetfiles) - { - if($SubFile.FullName -notin $XMLFiles) - { - Remove-Item -Path $SubFile.FullName - } - } - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Variables0 Function') | Out-File -FilePath $LogFile -Append - - Variables0 - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting Variables Job to complete') | Out-File -FilePath $LogFile -Append - - Get-Job -Name 'DiagramVariables' | Wait-Job - - $Job = Receive-Job -Name 'DiagramVariables' - - Get-Job -Name 'DiagramVariables' | Remove-Job - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting Variables') | Out-File -FilePath $LogFile -Append - - $Global:AZVGWs = $Job.AZVGWs - $Global:AZLGWs = $Job.AZLGWs - $Global:AZVNETs = $Job.AZVNETs - $Global:AZCONs = $Job.AZCONs - $Global:AZEXPROUTEs = $Job.AZEXPROUTEs - $Global:PIPs = $Job.PIPs - $Global:AZVWAN = $Job.AZVWAN - $Global:AZVHUB = $Job.AZVHUB - $Global:AZVPNSITES = $Job.AZVPNSITES - $Global:AZVERs = $Job.AZVERs - $Global:CleanPIPs = $Job.CleanPIPs - $Global:AKS = $Job.AKS - $Global:VMSS = $Job.VMSS - $Global:NIC = $Job.NIC - $Global:PrivEnd = $Job.PrivEnd - $Global:VM = $Job.VM - $Global:ARO = $Job.ARO - $Global:Kusto = $Job.Kusto - $Global:AppGtw = $Job.AppGtw - $Global:Databricks = $Job.DW - $Global:AppWeb = $Job.AppWeb - $Global:APIM = $Job.APIM - $Global:LB = $Job.LB - $Global:Bastion = $Job.Bastion - $Global:FW = $Job.FW - $Global:NetProf = $Job.NetProf - $Global:Container = $Job.Container - $Global:ANF = $Job.ANF - - $Global:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $Global:DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $Global:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $Global:IDNum = 0 - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Defining XML file') | Out-File -FilePath $LogFile -Append - - $Global:XmlWriter = New-Object System.XMl.XmlTextWriter($DDFile,$Null) - - $Global:XmlWriter.Formatting = 'Indented' - $Global:XmlWriter.Indentation = 2 - - $Global:XmlWriter.WriteStartDocument() - - $Global:XmlWriter.WriteStartElement('mxfile') - $Global:XmlWriter.WriteAttributeString('host', 'Electron') - $Global:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') - $Global:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') - $Global:XmlWriter.WriteAttributeString('etag', $etag) - $Global:XmlWriter.WriteAttributeString('version', '15.4.0') - $Global:XmlWriter.WriteAttributeString('type', 'device') - - $Global:XmlWriter.WriteStartElement('diagram') - $Global:XmlWriter.WriteAttributeString('id', $DiagID) - $Global:XmlWriter.WriteAttributeString('name', 'Network Topology') - - $Global:XmlWriter.WriteStartElement('mxGraphModel') - $Global:XmlWriter.WriteAttributeString('dx', "1326") - $Global:XmlWriter.WriteAttributeString('dy', "798") - $Global:XmlWriter.WriteAttributeString('grid', "1") - $Global:XmlWriter.WriteAttributeString('gridSize', "10") - $Global:XmlWriter.WriteAttributeString('guides', "1") - $Global:XmlWriter.WriteAttributeString('tooltips', "1") - $Global:XmlWriter.WriteAttributeString('connect', "1") - $Global:XmlWriter.WriteAttributeString('arrows', "1") - $Global:XmlWriter.WriteAttributeString('fold', "1") - $Global:XmlWriter.WriteAttributeString('page', "1") - $Global:XmlWriter.WriteAttributeString('pageScale', "1") - $Global:XmlWriter.WriteAttributeString('pageWidth', "850") - $Global:XmlWriter.WriteAttributeString('pageHeight', "1100") - $Global:XmlWriter.WriteAttributeString('math', "0") - $Global:XmlWriter.WriteAttributeString('shadow', "0") - - $Global:XmlWriter.WriteStartElement('root') - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "0") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "1") - $Global:XmlWriter.WriteAttributeString('parent', "0") - $Global:XmlWriter.WriteEndElement() - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Stensils') | Out-File -FilePath $LogFile -Append - - Stensils - - if($AZLGWs -or $AZEXPROUTEs -or $AZVERs -or $AZVPNSITES) - { - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling OnPremNet') | Out-File -FilePath $LogFile -Append - - OnPremNet - if($Global:FullEnvironment) - { - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling as FullEnvironment') | Out-File -FilePath $LogFile -Append - - FullEnvironment - } - } - else - { - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling CloudOnly Function') | Out-File -FilePath $LogFile -Append - CloudOnly - } - - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndDocument() - $Global:XmlWriter.Flush() - $Global:XmlWriter.Close() - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting Job2 to complete') | Out-File -FilePath $LogFile -Append - - while ($Global:jobs2.IsCompleted -contains $false) {} - - #$VNetFile = ($DiagramCache+'Network.xml') - - $Subnetfiles = Get-ChildItem -Path $DiagramCache - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Processing Subnet files') | Out-File -FilePath $LogFile -Append - - foreach($SubFile in $Subnetfiles) - { - if($SubFile.FullName -notin $XMLFiles) - { - $newxml = New-Object XML - $newxml.Load($SubFile.FullName) - - $Innerxml = $newxml.mxfile.diagram.mxGraphModel.root.InnerXml - - $Innerxml2 = $Innerxml.Replace('','') - - #force the config into an XML - $xml = [xml](get-content $DDFile) - - $xmlFrag=$xml.CreateDocumentFragment() - $xmlFrag.InnerXml=$Innerxml2 - - $xml.mxfile.diagram.mxGraphModel.root.AppendChild($xmlFrag) - - #save file - $xml.Save($DDFile) - - Remove-Item -Path $SubFile.FullName - } - } - - ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - End of Network Diagram') | Out-File -FilePath $LogFile -Append - - } -ArgumentList $Subscriptions,$Resources,$Advisories,$DiagramCache,$FullEnvironment,$DDFile,$XMLFiles,$Logfile -} - -Function Subscription { - Param($Subscriptions,$Resources,$DiagramCache) - - Start-Job -Name 'Diagram_Subscriptions' -ScriptBlock { - $Global:Subscriptions = $($args[0]) - $Global:Resources = $($args[1]) - $Global:DiagramCache = $($args[2]) - - Function Icon { - Param($Style,$x,$y,$w,$h,$p) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', $Style) - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - function variables { - - $Global:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" - $Global:RetRound = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" - - ############# Azure AI - $Global:AzureBotServices = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Bot_Services.svg;' - $Global:AzureMachineLearning = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Machine_Learning.svg;' - $Global:AzureCognitive = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Cognitive_Services.svg;' - - ############# Azure Analytics - $Global:AzureDatabricks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;' - $Global:AzureAnalysis = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Analysis_Services.svg;' - $Global:AzureSynapses = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Azure_Synapse_Analytics.svg;' - - ############# Azure App Service - $Global:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" - $Global:AppSvcPlan = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/app_services/App_Service_Plans.svg;' #width="43.5" height="43.5" - $Global:AzureAppDomain = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/app_services/App_Service_Domains.svg;' - - - ############# Azure VMware - $Global:AzureAVSPrivateCloud = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/azure_vmware_solution/AVS.svg;' - - - ############# Azure Compute - $Global:SvcFabric = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Service_Fabric_Clusters.svg;' #width="49.47" height="47.25" - $Global:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" - $Global:Disks = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Disks.svg;' #width="40.72" height="40" - $Global:RestorePoint = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Restore_Points_Collections.svg;' - $Global:AzureCloudSvc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;' - $Global:AvSet = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Availability_Sets.svg;' #width="43.5" height="43.5" - $Global:AzureVMImage = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Images.svg;' - $Global:AzureAVDWorkspace = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Workspaces.svg;' - $Global:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" - - ############ Azure Container - $Global:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" - $Global:ContRegis = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/containers/Container_Registries.svg;' - $Global:AzureContainerInstances = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/containers/Container_Instances.svg;' - - ############ Azure Database - $Global:AzureSQLDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Database.svg;' - $Global:AzureSQLDBServer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Server.svg;' - $Global:AzureDataExplorer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;' - $Global:AzureDBforPostgre = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_PostgreSQL_Server.svg;' - $Global:AzureDBforPostgreFlex = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_PostgreSQL_Server_Group.svg;' - $Global:AzureRedisCa = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Cache_Redis.svg;' - $Global:AzureDataFactory = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Azure_DevOps.svg;' - $Global:AzureCosmos = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Cosmos_DB.svg;' - $Global:AzureElastic = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Elastic_Pools.svg;' - $Global:AzureElasticJobAgent = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Elastic_Job_Agents.svg;' - $Global:AzureDB4MySQL = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_MySQL_Server.svg;' - $Global:AzureSQLManagedInstances = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Managed_Instance.svg;' - $Global:AzureSQLManagedInstancesDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Managed_Database.svg;' - $Global:AzureSQLVM = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_SQL_VM.svg;' - $Global:AzureSQLVirtualCluster = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Virtual_Clusters.svg;' - $Global:AzureDBMigration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_Migration_Services.svg;' - $Global:AzurePurviewAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Purview_Accounts.svg;' - $Global:AzureMariaDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_MariaDB_Server.svg;' - - ############ Azure DevOps - $Global:Insight = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Application_Insights.svg;' #width="44" height="63" - $Global:AzureDevOpsOrg = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Azure_DevOps.svg;' - - ############ Azure General - $Global:AzureError = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Error.svg;' #width="50.12" height="48" - $Global:AzureWebSlot = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Web_Slots.svg;' - $Global:AzureWorkbooks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Workbooks.svg;' - $Global:AzureWebTest = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Web_Test.svg;' - $Global:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" - $GLobal:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" - - ############ Azure Identity - $Global:AzureB2C = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/identity/Azure_AD_B2C.svg;' - - ########### Azure Integration - $Global:SvcBus = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Service_Bus.svg;' #width="45.05" height="39.75" - $Global:AzureAPIConnections = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Logic_Apps_Custom_Connector.svg;' - $Global:AzureLogicApp = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Logic_Apps.svg;' - $Global:AzureDataCatalog = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Azure_Data_Catalog.svg;' - $Global:AzureEventGridSymtopics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/System_Topic.svg;' - $Global:AzureAppConfiguration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/App_Configuration.svg;' - $Global:AzureIntegrationAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Integration_Accounts.svg;' - $Global:AzureEvtGridTopics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Event_Grid_Topics.svg;' - $Global:AzureAPIMangement = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/API_Management_Services.svg;' - $Global:AzureEvtGridDomain = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Event_Grid_Subscriptions.svg;' - - ########### Azure IoT - $Global:AzureEvtHubs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/iot/Event_Hubs.svg;' - $Global:AzureIoTHubs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/iot/Event_Hubs.svg;' - - ########### Azure Management Governance - $Global:RecoveryVault = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/Recovery_Services_Vaults.svg;' #width="43.7" height="38" - $Global:AutAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/Automation_Accounts.svg;' - $Global:AzureArcServer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/MachinesAzureArc.svg;' - - - ########### Azure Migrate - $Global:AzureMigration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/migrate/Azure_Migrate.svg;' - - - ########### Azure Networking - $Global:AzureConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" - $Global:AzureExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" - $Global:AzureVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" - $Global:AzureVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" - $Global:AzurePIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" - $Global:Azureproximityplacementgroups = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Proximity_Placement_Groups.svg;' - $Global:AzureUDRs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Route_Tables.svg;' - $Global:AzureRouteFilters = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Route_Filters.svg;' - $Global:AzureBastionHost = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Bastions.svg;' - $Global:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" - $Global:NetWatcher = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Watcher.svg;' - $Global:AzurePvtLinks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Private_Link_Service.svg;' - $Global:AzureIPGroups = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/IP_Groups.svg;' - $Global:AzureFW = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;' - $Global:AzureLNG = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Local_Network_Gateways.svg;' - $Global:AzureFrontDoor = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Front_Doors.svg;' - $Global:AzurePIPPrefixes = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Public_IP_Prefixes.svg;' - $Global:AzureNATGateways = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/NAT.svg;' - $Global:AzureCDN = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/CDN_Profiles.svg;' - $Global:AzureNSG = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Security_Groups.svg;' - $Global:AzureSvcEndpointPol = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Service_Endpoint_Policies.svg;' - $Global:AzureVMNIC = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;' - $Global:AzureWAFPolicies = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Web_Application_Firewall_Policies_WAF.svg;' - $Global:AzureDNSZone = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/DNS_Zones.svg;' - $Global:AzureAppGateway = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;' - $Global:AzureDDOS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;' - $Global:AzureTrafficManager = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Traffic_Manager_Profiles.svg;' - $Global:AzurePvtLink = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Private_Link.svg;' - $Global:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" - $Global:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" - - ########### Azure Other - $Global:Dashboard = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Dashboard_Hub.svg;' #width="50.02" height="38.25" - $Global:TemplSpec = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Template_Specs.svg;' - $Global:AzureBackupVault = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Azure_Backup_Center.svg;' - $Global:AzureERDirect = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/ExpressRoute_Direct.svg;' - $Global:AzureAVDSessionHost = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/AVS_VM.svg;' - $Global:AzureAVDHostPool = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Windows_Virtual_Desktop.svg;' - $Global:AzureGrafana = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Grafana.svg;' - $Global:AzureNetworkManager = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Azure_Network_Manager.svg;' - - - ########### Azure Security - $Global:KeyVault = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Key_Vaults.svg;' #width="49.5" height="49.5" - $Global:AzureAppSecGroup = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Application_Security_Groups.svg;' - $Global:AzureDefender = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Azure_Defender.svg;' - - - ########### Azure Storage - $Global:StorageAcc = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Storage_Accounts.svg;' #width="43.75" height="35" - $Global:AzureNetApp = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;' - $Global:AzureDatalakeGen1 = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Data_Lake_Storage_Gen1.svg;' - - - ########### Azure Web - $Global:AzureMediaServices = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/web/Azure_Media_Service.svg;' - - ########### MSCAE - $Global:Certificate = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Certificate.svg;' #width="50" height="42" - $Global:LogAnalytics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Log_Analytics_Workspaces.svg;' #width="40" height="40" - $Global:PvtDNS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/DNS_Private_Zones.svg;' #width="50" height="50" - $Global:AzureSaaS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Software_as_a_Service.svg;' - $Global:AzureRelay = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Service_Bus_Relay.svg;' - $Global:AzureLogAlertRule = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Notification.svg;' - $Global:AzureSignalR = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/SignalR.svg;' - - - } - - function ResourceTypes { - Param($TempResourceType,$TempResLeft,$TempResTop) - - switch ($TempResourceType.Name) - { - <########## AZURE AI ############> - - 'microsoft.botservice/botservices' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Bot' + "`n" + 'Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureBotServices $TempResLeft $TempResTop "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.machinelearningservices/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Machine' + "`n" + 'Learning')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureMachineLearning $TempResLeft $TempResTop "40" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.cognitiveservices/accounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cognitive' + "`n" + 'Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureCognitive $TempResLeft $TempResTop "58" "38" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE ANALYTICS ############> - - 'microsoft.databricks/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Databricks')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDatabricks $TempResLeft $TempResTop "48" "52" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.analysisservices/servers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Analysis' + "`n" + 'Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAnalysis $TempResLeft $TempResTop "53" "41" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.synapse/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Synapse' + "`n" + 'Analytics')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSynapses $TempResLeft $TempResTop "45" "54" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE APP ############> - - 'microsoft.web/sites' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web App')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconAPPs $TempResLeft $TempResTop "45" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.web/serverfarms' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Service Plan')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AppSvcPlan $TempResLeft $TempResTop "43.5" "43.5" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.domainregistration/domains' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App Service' + "`n" + 'Domain')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAppDomain $TempResLeft $TempResTop "50" "38" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE VMWARE ############> - - 'microsoft.avs/privateclouds' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VMware' + "`n" + 'Private Cloud')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAVSPrivateCloud $TempResLeft $TempResTop "60" "46" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE COMPUTE ############> - - 'microsoft.desktopvirtualization/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Workspaces')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAVDWorkspace $TempResLeft $TempResTop "48" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/virtualmachinescalesets' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VMSS')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVMSS $TempResLeft $TempResTop "45" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.servicefabric/clusters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Fabric')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SvcFabric $TempResLeft $TempResTop "49.4" "47.2" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/disks' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Disk')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Disks $TempResLeft $TempResTop "40.72" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/virtualmachines' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Virtual' + "`n" + 'Machine')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconVMs $TempResLeft $TempResTop "43" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/availabilitysets' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Availability' + "`n" + 'Set')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AvSet $TempResLeft $TempResTop "43.5" "43.5" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/restorepointcollections' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Restore' + "`n" + 'Point Collection')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $RestorePoint $TempResLeft $TempResTop "50" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.classiccompute/domainnames' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cloud' + "`n" + 'Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureCloudSvc $TempResLeft $TempResTop "51" "37" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/images' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Images')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureVMImage $TempResLeft $TempResTop "47" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - <########## AZURE CONTAINERS ############> - - 'microsoft.containerservice/managedclusters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AKS')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconAKS $TempResLeft $TempResTop "51" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.containerregistry/registries' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Container' + "`n" + 'Registry')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $ContRegis $TempResLeft $TempResTop "45" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.kubernetes/connectedclusters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Kubernetes' + "`n" + 'Azure Arc')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconAKS $TempResLeft $TempResTop "51" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.containerinstance/containergroups' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Container' + "`n" + 'Instances')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureContainerInstances $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - <########## AZURE DATABASES ############> - - 'microsoft.sql/servers/databases' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Database')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLDB $TempResLeft $TempResTop "36" "49" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/servers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLDBServer $TempResLeft $TempResTop "49" "49" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.kusto/clusters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Explorer Cluster')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDataExplorer $TempResLeft $TempResTop "41" "41" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dbforpostgresql/servers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'PostgreSQL')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDBforPostgre $TempResLeft $TempResTop "38" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dbforpostgresql/flexibleservers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' PostgreSQL' + "`n" + 'Flexible Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDBforPostgreFlex $TempResLeft $TempResTop "37.94" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.cache/redis' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Redis' + "`n" + 'Cache')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureRedisCa $TempResLeft $TempResTop "55" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.datafactory/factories' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Factory')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDataFactory $TempResLeft $TempResTop "44" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.documentdb/databaseaccounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cosmos' + "`n" + 'Database')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureCosmos $TempResLeft $TempResTop "51" "51" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/servers/elasticpools' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Elastic Pool')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureElastic $TempResLeft $TempResTop "51" "51" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/servers/jobagents' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Elastic' + "`n" + 'Job Agent')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureElasticJobAgent $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dbformysql/servers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MySQL' + "`n" + 'Database Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDB4MySQL $TempResLeft $TempResTop "35" "46" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dbformysql/flexibleservers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MySQL' + "`n" + 'Flexible Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDB4MySQL $TempResLeft $TempResTop "35" "46" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/managedinstances/databases' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Managed Instances' + "`n" + 'Database')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLManagedInstancesDB $TempResLeft $TempResTop "51" "47" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/managedinstances' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Managed Instances')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLManagedInstances $TempResLeft $TempResTop "50" "49" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sqlvirtualmachine/sqlvirtualmachines' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Virtual Machine')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLVM $TempResLeft $TempResTop "50" "46" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.sql/virtualclusters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Virtual Cluster')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSQLVirtualCluster $TempResLeft $TempResTop "50" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.datamigration/sqlmigrationservices' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Service')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.datamigration/services' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Service')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.datamigration/services/projects' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Project')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.purview/accounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Purview' + "`n" + 'Account')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzurePurviewAcc $TempResLeft $TempResTop "58" "32" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dbformariadb/servers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MariaDB' + "`n" + 'Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureMariaDB $TempResLeft $TempResTop "34" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE DEVOPS ############> - - 'microsoft.insights/metricalerts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Insight' + "`n" + 'Metrics')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Insight $TempResLeft $TempResTop "33" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.insights/components' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Insights')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Insight $TempResLeft $TempResTop "50" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.visualstudio/account' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DevOps' + "`n" + 'Organization')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDevOpsOrg $TempResLeft $TempResTop "41" "41" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE GENERAL ############> - - 'microsoft.web/sites/slots' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web' + "`n" + 'Slots')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWebSlot $TempResLeft $TempResTop "44" "49" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.insights/workbooks' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Workbooks')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWorkbooks $TempResLeft $TempResTop "39" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.insights/webtests' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web' + "`n" + 'Test')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWebTest $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE IDENTITY ############> - - 'microsoft.azureactivedirectory/b2cdirectories' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' B2C' + "`n" + 'Directories')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureB2C $TempResLeft $TempResTop "49" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE INTEGRATION ############> - - 'microsoft.servicebus/namespaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Bus')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $SvcBus $TempResLeft $TempResTop "45.05" "39.75" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.web/connections' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' API' + "`n" + 'Connections')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAPIConnections $TempResLeft $TempResTop "43" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.logic/workflows' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Logic' + "`n" + 'Apps')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureLogicApp $TempResLeft $TempResTop "57" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.datacatalog/catalogs' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Catalog')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDataCatalog $TempResLeft $TempResTop "46" "52" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.web/customapis' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Logic App' + "`n" + 'Custom Connector')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAPIConnections $TempResLeft $TempResTop "43" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.eventgrid/systemtopics' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'System Topics')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureEventGridSymtopics $TempResLeft $TempResTop "44" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.appconfiguration/configurationstores' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Configuration')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAppConfiguration $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.logic/integrationaccounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Integration' + "`n" + 'Accounts')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureIntegrationAcc $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.eventgrid/topics' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'Topics')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureEvtGridTopics $TempResLeft $TempResTop "44" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.apimanagement/service' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' API' + "`n" + 'Management')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAPIMangement $TempResLeft $TempResTop "50" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.eventgrid/domains' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'Domain')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureEvtGridDomain $TempResLeft $TempResTop "50" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE IOT ############> - - 'microsoft.eventhub/namespaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event' + "`n" + 'Hubs')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureEvtHubs $TempResLeft $TempResTop "50" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.devices/iothubs' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' IoT' + "`n" + 'Hubs')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureIoTHubs $TempResLeft $TempResTop "50" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - <########## AZURE MANAGEMENT GOVERNANCE ############> - - 'microsoft.recoveryservices/vaults' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Recovery' + "`n" + 'Services Vault')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $RecoveryVault $TempResLeft $TempResTop "43.5" "38" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.automation/automationaccounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Automation' + "`n" + 'Account')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AutAcc $TempResLeft $TempResTop "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'Microsoft.HybridCompute/machines' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Arc' + "`n" + 'Server')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureArcServer $TempResLeft $TempResTop "30" "54" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE MIGRATE ############> - - 'microsoft.migrate/projects' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Migration' + "`n" + 'Project')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureMigration $TempResLeft $TempResTop "62" "34" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE NETWORKING ############> - - 'microsoft.network/privateendpoints' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'Endpoint')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconPVTs $TempResLeft $TempResTop "44" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/loadbalancers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Load' + "`n" + 'Balancer')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconLBs $TempResLeft $TempResTop "41" "41" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/publicipaddresses' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Public IPs')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzurePIP $TempResLeft $TempResTop "51" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/virtualnetworks' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Virtual' + "`n" + 'Network')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureVNET $TempResLeft $TempResTop "62" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/networkwatchers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Watcher')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $NetWatcher $TempResLeft $TempResTop "44" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/virtualnetworkgateways' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VPN' + "`n" + 'Gateway')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureVGW $TempResLeft $TempResTop "36" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/connections' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Connection')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureConnections $TempResLeft $TempResTop "44" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/expressroutecircuits' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Express' + "`n" + 'Route')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureExpressRoute $TempResLeft $TempResTop "45" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/networksecuritygroups' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Security Group')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureNSG $TempResLeft $TempResTop "37" "46" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/routetables' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' User Defined' + "`n" + 'Route Tables')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureUDRs $TempResLeft $TempResTop "43" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/routefilters' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Route' + "`n" + 'Filters')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureRouteFilters $TempResLeft $TempResTop "54" "34" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/bastionhosts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Bastion' + "`n" + 'Host')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureBastionHost $TempResLeft $TempResTop "31" "37" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.compute/proximityplacementgroups' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Proximity' + "`n" + 'Placement Groups')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Azureproximityplacementgroups $TempResLeft $TempResTop "47" "45" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/privatelinkservices' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'Link Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzurePvtLinks $TempResLeft $TempResTop "56" "33" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/ipgroups' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' IP' + "`n" + 'Groups')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureIPGroups $TempResLeft $TempResTop "56" "33" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/azurefirewalls' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Firewall')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureFW $TempResLeft $TempResTop "64" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/localnetworkgateways' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Local' + "`n" + 'Network Gateway')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureLNG $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/frontdoors' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Front Door')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureFrontDoor $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/natgateways' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' NAT' + "`n" + 'Gateways')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureNATGateways $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/publicipprefixes' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Public IP' + "`n" + 'Prefixes')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzurePIPPrefixes $TempResLeft $TempResTop "51" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.cdn/profiles' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' CDN' + "`n" + 'Profile')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureCDN $TempResLeft $TempResTop "64" "36" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/serviceendpointpolicies' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Endpoint Polices')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSvcEndpointPol $TempResLeft $TempResTop "48" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.Network/networkInterfaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Interface')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureVMNIC $TempResLeft $TempResTop "50" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/frontdoorwebapplicationfirewallpolicies' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(FrontDoor)')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.cdn/cdnwebapplicationfirewallpolicies' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(CDN)')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(App Gateway)')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/dnszones' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DNS' + "`n" + 'Zone')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDNSZone $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/applicationgateways' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Application' + "`n" + 'Gateway')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAppGateway $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/ddosprotectionplans' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DDOS' + "`n" + 'Protection')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDDOS $TempResLeft $TempResTop "38" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/trafficmanagerprofiles' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Traffic Manager' + "`n" + 'Profiles')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureTrafficManager $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.hybridcompute/privatelinkscopes' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Arc Private' + "`n" + 'Link Scope')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzurePvtLink $TempResLeft $TempResTop "50" "44" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - <########## AZURE OTHER ############> - - 'microsoft.portal/dashboards' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Shared' + "`n" + 'Dashboard')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Dashboard $TempResLeft $TempResTop "50.02" "38.25" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.resources/templatespecs' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Template' + "`n" + 'Specs')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $TemplSpec $TempResLeft $TempResTop "33" "39" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dataprotection/backupvaults' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Backup' + "`n" + 'Services Vault')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureBackupVault $TempResLeft $TempResTop "40" "36" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/expressrouteports' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' ExpressRoute' + "`n" + 'Direct')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureBackupVault $TempResLeft $TempResTop "45" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.desktopvirtualization/hostpools/sessionhosts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Session Host')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAVDSessionHost $TempResLeft $TempResTop "51" "51" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.desktopvirtualization/hostpools' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Host Pool')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAVDHostPool $TempResLeft $TempResTop "51" "51" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.dashboard/grafana' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Grafana')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureGrafana $TempResLeft $TempResTop "50" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/networkmanagers' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Manager')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureNetworkManager $TempResLeft $TempResTop "46" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE SECURITY ############> - - 'microsoft.keyvault/vaults' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Key' + "`n" + 'Vault')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $KeyVault $TempResLeft $TempResTop "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/applicationsecuritygroups' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Application' + "`n" + 'Security Group')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureAppSecGroup $TempResLeft $TempResTop "35" "43" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.easm/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Defender' + "`n" + 'EASM')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDefender $TempResLeft $TempResTop "50" "38" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE STORAGE ############> - - 'microsoft.storage/storageaccounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Storage' + "`n" + 'Account')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $StorageAcc $TempResLeft $TempResTop "49.94" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.netapp/netappaccounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' NetApp' + "`n" + 'Account')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureNetApp $TempResLeft $TempResTop "40" "32" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'Microsoft.DataLakeStore/accounts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data Lake' + "`n" + 'Storage Gen1')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureDatalakeGen1 $TempResLeft $TempResTop "54" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## AZURE WEB ############> - - 'microsoft.media/mediaservices' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Media' + "`n" + 'Services')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureMediaServices $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - - <########## MSCAE ############> - - 'microsoft.web/certificates' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Certificate')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $Certificate $TempResLeft $TempResTop "50" "42" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.operationalinsights/workspaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Log' + "`n" + 'Analytics')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $LogAnalytics $TempResLeft $TempResTop "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.network/privatednszones' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'DNS Zone')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $PvtDNS $TempResLeft $TempResTop "40" "40" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.saas/resources' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SaaS' + "`n" + 'Resource')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSaaS $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.relay/namespaces' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Relay')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureRelay $TempResLeft $TempResTop "50" "50" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.Insights/ActivityLogAlerts' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Activity Log' + "`n" + 'Alert Rule')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'Microsoft.AlertsManagement/smartDetectorAlertRules' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Smart Detector' + "`n" + 'Alert Rule')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'microsoft.insights/scheduledqueryrules' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Log Search' + "`n" + 'Alert Rule')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - 'Microsoft.SignalRService/SignalR' - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SignalR')) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureSignalR $TempResLeft $TempResTop "48" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - - - default - { - $TempName = [string]$TempResourceType.Name - $TempName = $TempName.Replace('microsoft.','') - $TempName = $TempName.split('/') - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' ' + $TempName[0]+ "`n" + $TempName[1])) - #$Global:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Name)) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $AzureError $TempResLeft $TempResTop "50" "48" 1 - - $Global:XmlWriter.WriteEndElement() - } - } - - } - - - $Global:NonTypes = ('microsoft.compute/virtualmachines/extensions', - 'microsoft.operationsmanagement/solutions', - 'microsoft.network/privatednszones/virtualnetworklinks', - 'microsoft.devtestlab/schedules', - 'microsoft.managedidentity/userassignedidentities', - 'microsoft.compute/virtualmachines/runcommands', - 'microsoft.compute/sshpublickeys', - 'microsoft.resources/templatespecs/versions', - 'microsoft.containerregistry/registries/replications', - 'microsoft.automation/automationaccounts/runbooks', - 'microsoft.compute/snapshots', - 'microsoft.insights/autoscalesettings', - 'microsoft.insights/actiongroups', - 'microsoft.network/networkwatchers/flowlogs', - 'microsoft.compute/diskencryptionsets', - 'microsoft.insights/datacollectionrules', - 'microsoft.netapp/netappaccounts/capacitypools', - 'microsoft.netapp/netappaccounts/capacitypools/volumes', - 'microsoft.network/firewallpolicies', - 'microsoft.web/connectiongateways', - 'microsoft.security/automations', - 'microsoft.datacatalog/catalogs', - 'microsoft.hybridcompute/machines/extensions', - 'microsoft.compute/galleries/images', - 'microsoft.compute/galleries/images/versions', - 'microsoft.desktopvirtualization/applicationgroups', - 'microsoft.network/networkintentpolicies', - 'microsoft.resourcegraph/queries', - 'microsoft.cdn/profiles/endpoints', - 'microsoft.network/networkwatchers/connectionmonitors', - 'microsoft.compute/galleries', - 'microsoft.synapse/workspaces/sqlpools', - 'microsoft.containerregistry/registries/webhooks', - 'microsoft.migrate/movecollections', - 'microsoft.databricks/accessconnectors', - 'microsoft.insights/datacollectionendpoints', - 'microsoft.synapse/workspaces/bigdatapools', - 'microsoft.media/mediaservices/streamingendpoints', - 'microsoft.security/customentitystoreassignments', - 'microsoft.security/securityconnectors', - 'microsoft.security/customassessmentautomations', - 'microsoft.datashare/accounts', - 'microsoft.cdn/profiles/afdendpoints', - 'microsoft.securitydevops/azuredevopsconnectors', - 'microsoft.securitydevops/githubconnectors', - 'microsoft.security/datascanners', - 'microsoft.offazure/importsites', - 'microsoft.offazure/vmwaresites', - 'microsoft.migrate/migrateprojects', - 'microsoft.migrate/assessmentprojects', - 'microsoft.offazure/mastersites', - 'microsoft.automation/automationaccounts/configurations', - 'microsoft.alertsmanagement/actionrules', - 'microsoft.resourceconnector/appliances', - 'microsoft.automanage/configurationprofiles', - 'microsoft.offazure/hypervsites', - 'microsoft.machinelearningservices/registries', - 'microsoft.machinelearningservices/workspaces/onlineendpoints/deployments', - 'microsoft.machinelearningservices/workspaces/onlineendpoints', - 'microsoft.serviceshub/connectors', - 'microsoft.containerregistry/registries/tasks', - 'microsoft.web/staticsites', - 'microsoft.security/standards', - 'microsoft.security/iotsecuritysolutions', - 'microsoft.security/assignments', - 'microsoft.connectedvmwarevsphere/virtualmachines', - 'microsoft.connectedvmwarevsphere/vcenters', - 'microsoft.extendedlocation/customlocations', - 'microsoft.offazure/serversites', - 'microsoft.signalrservice/webpubsub', - 'microsoft.eventgrid/partnerconfigurations') - - - $Subs = $Resources | group-object -Property subscriptionId | Sort-Object -Property Count -Descending - - $DDDFile = ($DiagramCache+'Subscriptions.xml') - - $XLeft = 100 - $XTop = 100 - $CelNum = 0 - - $Global:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $Global:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $Global:IDNum = 0 - - $Global:XmlWriter = New-Object System.XMl.XmlTextWriter($DDDFile,$Null) - - $Global:XmlWriter.Formatting = 'Indented' - $Global:XmlWriter.Indentation = 2 - - $Global:XmlWriter.WriteStartDocument() - - $Global:XmlWriter.WriteStartElement('mxfile') - $Global:XmlWriter.WriteAttributeString('host', 'Electron') - $Global:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') - $Global:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') - $Global:XmlWriter.WriteAttributeString('etag', $etag) - $Global:XmlWriter.WriteAttributeString('version', '15.4.0') - $Global:XmlWriter.WriteAttributeString('type', 'device') - - foreach($Sub in $Subs.Name) - { - $RGLeft = $XLeft + 40 - $RGTop = $XTop + 40 - $Resource = $Resources | Where-Object {$_.subscriptionId -eq $Sub} - $SubName = $Subscriptions | Where-Object {$_.id -eq $Sub} - $Resource0 = $Resource | Group-Object -Property resourceGroup | Sort-Object -Property Count -Descending - $SubName = $SubName.Name - - $DiagID1 = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $Global:XmlWriter.WriteStartElement('diagram') - $Global:XmlWriter.WriteAttributeString('id', $DiagID1) - $Global:XmlWriter.WriteAttributeString('name', $SubName) - - $Global:XmlWriter.WriteStartElement('mxGraphModel') - $Global:XmlWriter.WriteAttributeString('dx', "1326") - $Global:XmlWriter.WriteAttributeString('dy', "798") - $Global:XmlWriter.WriteAttributeString('grid', "1") - $Global:XmlWriter.WriteAttributeString('gridSize', "10") - $Global:XmlWriter.WriteAttributeString('guides', "1") - $Global:XmlWriter.WriteAttributeString('tooltips', "1") - $Global:XmlWriter.WriteAttributeString('connect', "1") - $Global:XmlWriter.WriteAttributeString('arrows', "1") - $Global:XmlWriter.WriteAttributeString('fold', "1") - $Global:XmlWriter.WriteAttributeString('page', "1") - $Global:XmlWriter.WriteAttributeString('pageScale', "1") - $Global:XmlWriter.WriteAttributeString('pageWidth', "850") - $Global:XmlWriter.WriteAttributeString('pageHeight', "1100") - $Global:XmlWriter.WriteAttributeString('math', "0") - $Global:XmlWriter.WriteAttributeString('shadow', "0") - - $Global:XmlWriter.WriteStartElement('root') - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "0") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "1") - $Global:XmlWriter.WriteAttributeString('parent', "0") - $Global:XmlWriter.WriteEndElement() - - variables - - $Global:CellIDRes = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $Witd = 2060 - - $Counter = 1 - $ZCounter = 0 - foreach($RG in $Resource0.Name) - { - $Res = $Resource | Where-Object {$_.resourceGroup -eq $RG -and $_.Type -notin $NonTypes} - $Resource1 = $Res | Group-Object -Property type | Sort-Object -Property Count -Descending - - $RGHeigh = if($Resource1.name.count -le 8){1}else{[math]::ceiling($Resource1.name.count / 8)} - - if($Counter -eq 1) - { - $RGLeft = $RGLeft + $RGWitdh + 40 - $TempHeight1 = $RGTop + ($RGHeigh*120) + 40 - if($ZCounter -eq 1) - { - $RGTop = $TempHeight2 - } - } - else - { - $RGLeft = $XLeft + 40 - $TempHeight2 = $RGTop + ($RGHeigh*120) + 40 - $RGTop = $TempHeight1 - $ZCounter = 1 - } - - if($Counter -eq 1){$Counter = 2}else{$Counter = 1} - } - - if($TempHeight1 -gt $TempHeight2){$RGTop = $TempHeight1}else{$RGTop = $TempHeight2} - - $SubHeight = $RGTop - $XTop - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($CelNum++))) - - Icon $Ret $XLeft $XTop $Witd $SubHeight 1 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $SubName) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconSubscription 30 ($XTop+$SubHeight-20) "67" "40" 1 - - $Global:XmlWriter.WriteEndElement() - - - $RGLeft = $XLeft + 40 - $RGTop = $XTop + 40 - - $Counter = 1 - $ZCounter = 0 - foreach($RG in $Resource0.Name) - { - $Res = $Resource | Where-Object {$_.resourceGroup -eq $RG -and $_.subscriptionId -eq $Sub -and $_.Type -notin $NonTypes} - $Resource1 = $Res | Group-Object -Property type | Sort-Object -Property Count -Descending - - $RGWitdh = 960 - $RGHeigh = if($Resource1.name.count -le 8){1}else{[math]::ceiling($Resource1.name.count / 8)} - - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($CelNum++))) - - Icon $RetRound $RGLeft $RGTop $RGWitdh ($RGHeigh*120) 1 - - $Global:XmlWriter.WriteEndElement() - - if($Counter -eq 1) - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $RG) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconRG ($XLeft+20) ($RGTop+($RGHeigh*120)-20) "37.5" "30" 1 - - $Global:XmlWriter.WriteEndElement() - - $ResTypeLeft = $RGLeft + 60 - $ResTypeTop = $RGTop + 25 - $YCounter = 1 - - foreach($res0 in $Resource1) - { - ResourceTypes $res0 $ResTypeLeft $ResTypeTop - if($YCounter -ge 8) - { - $ResTypeLeft = $RGLeft + 60 - $ResTypeTop = $ResTypeTop + 110 - $YCounter = 1 - } - else - { - $ResTypeLeft = $ResTypeLeft + 110 - $YCounter++ - } - - } - $RGLeft = $RGLeft + $RGWitdh + 40 - $TempHeight1 = $RGTop + ($RGHeigh*120) + 40 - if($ZCounter -eq 1) - { - $RGTop = $TempHeight2 - } - } - else - { - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $RG) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - Icon $IconRG ($RGLeft + $RGWitdh - 20) ($RGTop+($RGHeigh*120)-20) "37.5" "30" 1 - - $Global:XmlWriter.WriteEndElement() - - $ResTypeLeft = $RGLeft + 60 - $ResTypeTop = $RGTop + 25 - $YCounter = 1 - - foreach($res0 in $Resource1) - { - ResourceTypes $res0 $ResTypeLeft $ResTypeTop - if($YCounter -ge 8) - { - $ResTypeLeft = $RGLeft + 60 - $ResTypeTop = $ResTypeTop + 110 - $YCounter = 1 - } - else - { - $ResTypeLeft = $ResTypeLeft + 110 - $YCounter++ - } - - } - - $RGLeft = $XLeft + 40 - $TempHeight2 = $RGTop + ($RGHeigh*120) + 40 - $RGTop = $TempHeight1 - $ZCounter = 1 - } - - if($Counter -eq 1){$Counter = 2}else{$Counter = 1} - - } - - if($TempHeight1 -gt $TempHeight2){$RGTop = $TempHeight1}else{$RGTop = $TempHeight2} - - $XTop = $RGTop + 200 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - $Global:XmlWriter.WriteEndDocument() - $Global:XmlWriter.Flush() - $Global:XmlWriter.Close() - - } -ArgumentList $Subscriptions,$Resources,$DiagramCache - -} - -Function Organization { - Param($ResourceContainers,$DiagramCache) - - Start-Job -Name 'Diagram_Organization' -ScriptBlock { - - $Global:ResourceContainers = $($args[0]) - $Global:DiagramCache = $($args[1]) - - Function Icon { - Param($Style,$x,$y,$w,$h,$p) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('style', $Style) - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Connect { - Param($Source,$Target,$Parent) - - if($Parent){$Parent = $Parent}else{$Parent = 1} - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - $Global:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") - $Global:XmlWriter.WriteAttributeString('edge', "1") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $Parent) - $Global:XmlWriter.WriteAttributeString('source', $Source) - $Global:XmlWriter.WriteAttributeString('target', $Target) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('relative', "1") - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - } - - Function Container0 { - Param($x,$y,$w,$h,$title) - $Global:ContID0 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID0) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;swimlaneFillColor=#F5F5F5;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Container1 { - Param($x,$y,$w,$h,$title) - $Global:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;swimlaneFillColor=#D5E8D4;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', "1") - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Container2 { - Param($x,$y,$w,$h,$title,$p) - $Global:ContID2 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID2) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;swimlaneFillColor=#DAE8FC;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Container3 { - Param($x,$y,$w,$h,$title,$p) - $Global:ContID3 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID3) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;swimlaneFillColor=#FFE6CC;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Container4 { - Param($x,$y,$w,$h,$title,$p) - $Global:ContID4 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', $Global:ContID4) - $Global:XmlWriter.WriteAttributeString('value', "$title") - $Global:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;swimlaneFillColor=#FFE6CC;rounded=1;") - $Global:XmlWriter.WriteAttributeString('vertex', "1") - $Global:XmlWriter.WriteAttributeString('parent', $p) - - $Global:XmlWriter.WriteStartElement('mxGeometry') - $Global:XmlWriter.WriteAttributeString('x', $x) - $Global:XmlWriter.WriteAttributeString('y', $y) - $Global:XmlWriter.WriteAttributeString('width', $w) - $Global:XmlWriter.WriteAttributeString('height', $h) - $Global:XmlWriter.WriteAttributeString('as', "geometry") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - } - - Function Stencils { - $Global:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" - $Global:IconMgmtGroup = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Management_Groups.svg;" #width="44" height="71" - $Global:Ret = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" - $Global:Ret1 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#b0e3e6;strokeColor=#0e8088;" - $Global:Ret2 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#b1ddf0;strokeColor=#10739e;" - $Global:Ret3 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#fad7ac;strokeColor=#b46504;" - $Global:Ret4 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#e1d5e7;strokeColor=#9673a6;" - - } - - Function Org { - - $OrgObjs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions'} - - $Global:1stLevel = @() - $Lvl2 = @() - $Lvl3 = @() - $Lvl4 = @() - foreach($org in $OrgObjs) - { - if($org.properties.managementgroupancestorschain.count -eq 2) - { - $Global:1stLevel += $org.properties.managementgroupancestorschain.displayname[0] - } - if($org.properties.managementgroupancestorschain.count -eq 3) - { - $Lvl2 += $org.properties.managementgroupancestorschain.name[0] - $Global:1stLevel += $org.properties.managementgroupancestorschain.displayname[1] - } - if($org.properties.managementgroupancestorschain.count -eq 4) - { - $Lvl3 += $org.properties.managementgroupancestorschain.name[0] - $Lvl2 += $org.properties.managementgroupancestorschain.name[1] - $Global:1stLevel += $org.properties.managementgroupancestorschain.displayname[2] - } - if($org.properties.managementgroupancestorschain.count -eq 5) - { - $Lvl4 += $org.properties.managementgroupancestorschain.name[0] - $Lvl3 += $org.properties.managementgroupancestorschain.name[1] - $Lvl2 += $org.properties.managementgroupancestorschain.name[2] - $Global:1stLevel += $org.properties.managementgroupancestorschain.displayname[3] - } - } - - $Global:1stLevel = $Global:1stLevel | Select-Object -Unique - $Lvl2 = $Lvl2 | Select-Object -Unique - $Lvl3 = $Lvl3 | Select-Object -Unique - $Lvl4 = $Lvl4 | Select-Object -Unique - - $Global:XLeft = 0 - $Global:XTop = 100 - $XXLeft = 100 - - $Global:XTop = $Global:XTop + 200 - - $RoundSubs00 = @() - foreach($Sub in $OrgObjs) - { - if($Sub.properties.managementgroupancestorschain[0].displayname -eq 'tenant root group') - { - $RoundSubs00 += $Sub - } - } - - $MgmtHeight0 = (($RoundSubs00.id.count * 70) + 80) - - Container0 '0' '0' '200' $MgmtHeight0 'tenant root group' - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('ManagementGroup', 'tenant root group') - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - if($RoundSubs00) - { - icon $Global:IconMgmtGroup '-30' ($MgmtHeight0-15) '50' '50' $Global:ContID0 - } - else - { - icon $Global:IconMgmtGroup '75' '27' '50' '50' $Global:ContID0 - } - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = 50 - $LocalLeft = 25 - - foreach($Sub in $RoundSubs00) - { - $RGs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $sub.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($Global:CelNum++))) - - Icon $Ret1 $LocalLeft $LocalTop '150' '70' $Global:ContID0 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $RGNum = 1 - foreach($RG in $RGs) - { - $Attr = ('ResourceGroup_'+[string]$RGNum) - $Global:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) - $RGNum++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - icon $Global:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Global:ContID0 - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = $LocalTop + 90 - - } - - - - - foreach($1stlvl in $Global:1stLevel) - { - $RoundSubs0 = @() - - foreach($Sub in $OrgObjs) - { - if($Sub.properties.managementgroupancestorschain.displayname[0] -eq $1stlvl) - { - $RoundSubs0 += $Sub - } - } - - $MgmtHeight = (($RoundSubs0.id.count * 70) + 80) - - Container1 $XLeft $XTop '200' $MgmtHeight $1stlvl $Global:ContID0 - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('ManagementGroup', [string]$1stlvl) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - if($RoundSubs0) - { - icon $Global:IconMgmtGroup '-30' ($MgmtHeight-15) '50' '50' $Global:ContID - } - else - { - icon $Global:IconMgmtGroup '75' '27' '50' '50' $Global:ContID - } - - $Global:XmlWriter.WriteEndElement() - - Connect $Global:ContID0 $Global:ContID - - $LocalTop = 50 - $LocalLeft = 25 - - foreach($Sub in $RoundSubs0) - { - $RGs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $sub.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($Global:CelNum++))) - - Icon $Ret1 $LocalLeft $LocalTop '150' '70' $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $RGNum = 1 - foreach($RG in $RGs) - { - $Attr = ('ResourceGroup_'+[string]$RGNum) - $Global:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) - $RGNum++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - icon $Global:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Global:ContID - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = $LocalTop + 90 - - } - - ######################################## 2ND LEVEL ############################################## - - $2ndLevel = @() - foreach($sub2nd in $OrgObjs) - { - if($sub2nd.properties.managementgroupancestorschain.displayname[1] -eq $1stlvl) - { - $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[0] - } - if($sub2nd.properties.managementgroupancestorschain.displayname[2] -eq $1stlvl) - { - $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[1] - } - if($sub2nd.properties.managementgroupancestorschain.displayname[3] -eq $1stlvl) - { - $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[2] - } - } - $2ndLevel = $2ndLevel | Select-Object -Unique - - $XXLeft = 0 - if($2ndLevel.count % 2 -eq 1 ) - { - $Align = $true - $loops = -[Math]::ceiling($2ndLevel.count /2 - 1) - } - else - { - $Align = $false - $loops = [Math]::ceiling($2ndLevel.count / 2) - - } - if($2ndLevel.count -eq 1) - { - $loops = 1 - } - $TempSon = 0 - - - foreach($2nd in $2ndLevel) - { - $RoundSubs = @() - $Temp3rd = @() - $Temp4rd = @() - $Temp5th = @() - - foreach($Sub in $OrgObjs) - { - if($Sub.properties.managementgroupancestorschain.name[0] -eq $2nd) - { - $RoundSubs += $Sub - } - if($Sub.properties.managementgroupancestorschain.name[1] -eq $2nd) - { - $Temp3rd += $Sub.properties.managementgroupancestorschain.name[0] - } - if($Sub.properties.managementgroupancestorschain.name[2] -eq $2nd) - { - $Temp4rd += $Sub.properties.managementgroupancestorschain.name[0] - $Temp3rd += $Sub.properties.managementgroupancestorschain.name[1] - } - if($Sub.properties.managementgroupancestorschain.name[3] -eq $2nd) - { - $Temp5th += $Sub.properties.managementgroupancestorschain.name[0] - $Temp4rd += $Sub.properties.managementgroupancestorschain.name[1] - $Temp3rd += $Sub.properties.managementgroupancestorschain.name[2] - } - } - - $Temp3rd = $Temp3rd | Select-Object -Unique - $Temp4rd = $Temp4rd | Select-Object -Unique - $Temp5th = $Temp5th | Select-Object -Unique - - if($XXLeft -eq 0 -and $Align -eq $true) - { - } - elseif($XXLeft -eq 0 -and $Align -eq $false) - { - $XXLeft = -150 + -((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) - $loops++ - } - elseif($Align -eq $false -and $loops -eq 0) - { - $XXLeft = 150 + ((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) - $loops++ - } - elseif($loops -gt 0 -and $XXLeft -eq 0) - { - $XXLeft = $XXLeft + ($2ndLevel.count*300)/2 + ((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) - $loops++ - } - elseif($XXLeft -le 0 -and $loops -lt 0) - { - $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150))} - $XXLeft = $XXLeft + -$XXTemp - $loops++ - } - elseif($XXLeft -gt 0 -and $loops -ge 0) - { - $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150))} - $XXLeft = $XXLeft + $XXTemp - $loops++ - } - else - { - $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*300)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*300))} - $XXLeft = $XXLeft + $XXTemp - $loops++ - } - write-host $XXleft - - $MgmtHeight1 = if((($RoundSubs.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs.id.count * 90) + 50)} - - $XXTop = $MgmtHeight + 200 - - Container2 $XXLeft $XXTop '200' $MgmtHeight1 $2nd $Global:ContID - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('ManagementGroup', [string]$2nd) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - if($RoundSubs) - { - icon $Global:IconMgmtGroup '-30' ($MgmtHeight1-15) '50' '50' $Global:ContID2 - } - else - { - icon $Global:IconMgmtGroup '75' '27' '50' '50' $Global:ContID2 - } - - $Global:XmlWriter.WriteEndElement() - - Connect $Global:ContID $Global:ContID2 - - $TempSon = (($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)) - - if($XXLeft -eq 0 -and $loops -lt 0) - { - $XXLeft = -1 - } - elseif($XXLeft -lt 0 -and $loops -ge 0) - { - $XXLeft = 1 - } - - $LocalTop = 50 - $LocalLeft = 25 - - foreach($Sub in $RoundSubs) - { - $RGs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $sub.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($Global:CelNum++))) - - Icon $Ret2 $LocalLeft $LocalTop '150' '70' $Global:ContID2 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $RGNum = 1 - foreach($RG in $RGs) - { - $Attr = ('ResourceGroup_'+[string]$RGNum) - $Global:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) - $RGNum++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - icon $Global:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Global:ContID2 - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = $LocalTop + 90 - } - - - ######################################## 3RD LEVEL ############################################## - - $3rdLevel = @() - foreach($sub3rd in $OrgObjs) - { - if($sub3rd.properties.managementgroupancestorschain.name[1] -eq $2nd) - { - $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[0] - } - if($sub3rd.properties.managementgroupancestorschain.name[2] -eq $2nd) - { - $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[1] - } - if($sub3rd.properties.managementgroupancestorschain.name[3] -eq $2nd) - { - $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[2] - } - } - $3rdLevel = $3rdLevel | Select-Object -Unique - - $XXXLeft = 0 - if($3rdLevel.count % 2 -eq 1 ) - { - $Align3 = $true - $loops3 = -[Math]::ceiling($3rdLevel.count / 2 - 1) - } - else - { - $Align3 = $false - $loops3 = [Math]::ceiling($3rdLevel.count / 2) - 1 - - } - if($3rdLevel.count -eq 1) - { - $loops3 = 1 - } - - - foreach($3rd in $3rdLevel) - { - $RoundSubs3 = @() - $Temp4rd3 = @() - $Temp5th3 = @() - - foreach($Sub in $OrgObjs) - { - if($Sub.properties.managementgroupancestorschain.name[0] -eq $3rd) - { - $RoundSubs3 += $Sub - } - if($Sub.properties.managementgroupancestorschain.name[1] -eq $3rd) - { - $Temp4rd3 += $Sub.properties.managementgroupancestorschain.name[0] - } - if($Sub.properties.managementgroupancestorschain.name[2] -eq $3rd) - { - $Temp5th3 += $Sub.properties.managementgroupancestorschain.name[0] - $Temp4rd3 += $Sub.properties.managementgroupancestorschain.name[1] - } - } - - $Temp4rd3 = $Temp4rd3 | Select-Object -Unique - $Temp5th3 = $Temp5th3 | Select-Object -Unique - - - if($XXXLeft -eq 0 -and $Align3 -eq $true) - { - } - elseif($XXXLeft -eq 0 -and $Align3 -eq $false) - { - $XXXLeft = -150 + -((((($Temp4rd3.count)+($Temp5th3.count)))*150)/2) - $loops3++ - } - elseif($Align3 -eq $false -and $loops3 -eq 0) - { - $XXXLeft = 150 + ((((($Temp4rd3.count)+($Temp5th3.count)))*150)/2) - $loops3++ - } - elseif($loops3 -gt 0 -and $XXXLeft -eq 0) - { - $XXXLeft = $XXXLeft + ($3rdLevel.count*300)/2 + ((((($Temp4rd3.count)+($Temp5th3.count)))*300)/2) - $loops3++ - } - elseif($XXXLeft -eq 0 -and $loops3 -lt 0) - { - $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} - $XXXLeft = $XXXLeft + -$XXXTemp - $loops3++ - } - elseif($XXXLeft -lt 0 -and $loops3 -lt 0) - { - $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} - $XXXLeft = $XXXLeft + -$XXXTemp - $loops3++ - } - elseif($XXXLeft -eq 1 -and $loops3 -gt 0) - { - $XXXLeft = 150 + ((((($Temp4rd3.count)+($Temp5th3.count)))*150)) - $loops3++ - } - else - { - $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} - $XXXLeft = $XXXLeft + $XXXTemp - $loops3++ - } - - - $MgmtHeight2 = if((($RoundSubs3.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs3.id.count * 90) + 50)} - - $XXXTop = $MgmtHeight1 + 200 - - Container3 $XXXLeft $XXXTop '200' $MgmtHeight2 $3rd $Global:ContID2 - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('ManagementGroup', [string]$3rd) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - if($RoundSubs3) - { - icon $Global:IconMgmtGroup '-30' ($MgmtHeight2-15) '50' '50' $Global:ContID3 - } - else - { - icon $Global:IconMgmtGroup '75' '27' '50' '50' $Global:ContID3 - } - - $Global:XmlWriter.WriteEndElement() - - Connect $Global:ContID2 $Global:ContID3 - - if($XXXLeft -eq 0 -and $loops3 -lt 0) - { - $XXXLeft = -1 - } - elseif($XXXLeft -lt 0 -and $loops3 -ge 0) - { - $XXXLeft = 1 - } - - $LocalTop = 50 - $LocalLeft = 25 - - foreach($Sub in $RoundSubs3) - { - - $RGs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $sub.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($Global:CelNum++))) - - Icon $Ret3 $LocalLeft $LocalTop '150' '70' $Global:ContID3 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $RGNum = 1 - foreach($RG in $RGs) - { - $Attr = ('ResourceGroup_'+[string]$RGNum) - $Global:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) - $RGNum++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - icon $Global:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Global:ContID3 - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = $LocalTop + 90 - } - - - ######################################## 4TH LEVEL ############################################## - - $4thLevel = @() - foreach($sub4th in $OrgObjs) - { - if($sub4th.properties.managementgroupancestorschain.name[1] -eq $3rd) - { - $4thLevel += $sub4th.properties.managementgroupancestorschain.name[0] - } - if($sub4th.properties.managementgroupancestorschain.name[2] -eq $3rd) - { - $4thLevel += $sub4th.properties.managementgroupancestorschain.name[1] - } - if($sub4th.properties.managementgroupancestorschain.name[3] -eq $3rd) - { - $4thLevel += $sub4th.properties.managementgroupancestorschain.name[2] - } - } - $4thLevel = $4thLevel | Select-Object -Unique - - $XXXXLeft = 0 - if($4thLevel.count % 2 -eq 1 ) - { - $Align4 = $true - $loops4 = -[Math]::ceiling($sub4th.count / 2 - 1) - } - else - { - $Align4 = $false - $loops4 = [Math]::ceiling($sub4th.count / 2) - 1 - - } - if($4thLevel.count -eq 1) - { - $loops4 = 1 - } - - - foreach($4th in $4thLevel) - { - $RoundSubs4 = @() - $Temp5th4 = @() - - foreach($Sub in $OrgObjs) - { - if($Sub.properties.managementgroupancestorschain.name[0] -eq $4th) - { - $RoundSubs4 += $Sub - } - if($Sub.properties.managementgroupancestorschain.name[1] -eq $4th) - { - $Temp5th4 += $Sub.properties.managementgroupancestorschain.name[0] - } - if($Sub.properties.managementgroupancestorschain.name[2] -eq $4th) - { - $Temp5th4 += $Sub.properties.managementgroupancestorschain.name[0] - } - } - - $Temp5th4 = $Temp5th4 | Select-Object -Unique - - if($XXXXLeft -eq 0 -and $Align4 -eq $true) - { - } - elseif($XXXXLeft -eq 0 -and $Align4 -eq $false) - { - $XXXXLeft = -150 + -((((($Temp4rd4.count)+($Temp5th4.count)))*150)/2) - $loops4++ - } - elseif($Align4 -eq $false -and $loops4 -eq 0) - { - $XXXXLeft = 150 + ((((($Temp4rd4.count)+($Temp5th4.count)))*150)/2) - $loops4++ - } - elseif($loops4 -gt 0 -and $XXXXLeft -eq 0) - { - $XXXXLeft = $XXXXLeft + ($4thLevel.count*300)/2 + ((((($Temp5th4.count)))*300)/2) - $loops4++ - } - elseif($XXXXLeft -eq 0 -and $loops4 -lt 0) - { - $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} - $XXXXLeft = $XXXXLeft + -$XXXXTemp - $loops4++ - } - elseif($XXXXLeft -lt 0 -and $loops4 -lt 0) - { - $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} - $XXXXLeft = $XXXXLeft + -$XXXXTemp - $loops4++ - } - elseif($XXXXLeft -eq 1 -and $loops4 -gt 0) - { - $XXXXLeft = 150 + ((((($Temp5th4.count)))*150)) - $loops4++ - } - else - { - $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} - $XXXXLeft = $XXXXLeft + $XXXXTemp - $loops4++ - } - - - $MgmtHeight3 = if((($RoundSubs4.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs4.id.count * 90) + 50)} - - $XXXXTop = $MgmtHeight2 + 200 - - Container4 $XXXXLeft $XXXXTop '200' $MgmtHeight3 $4th $Global:ContID3 - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - $Global:XmlWriter.WriteAttributeString('ManagementGroup', [string]$4th) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - if($RoundSubs4) - { - icon $Global:IconMgmtGroup '-30' ($MgmtHeight3-15) '50' '50' $Global:ContID4 - } - else - { - icon $Global:IconMgmtGroup '75' '27' '50' '50' $Global:ContID4 - } - - $Global:XmlWriter.WriteEndElement() - - Connect $Global:ContID3 $Global:ContID4 - - if($XXXXLeft -eq 0 -and $loops4 -lt 0) - { - $XXXXLeft = -1 - } - elseif($XXXXLeft -lt 0 -and $loops4 -ge 0) - { - $XXXXLeft = 1 - } - - $LocalTop = 50 - $LocalLeft = 25 - - foreach($Sub in $RoundSubs4) - { - - $RGs = $Global:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', $sub.name) - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellIDRes+'-'+($Global:CelNum++))) - - Icon $Ret4 $LocalLeft $LocalTop '150' '70' $Global:ContID4 - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('object') - $Global:XmlWriter.WriteAttributeString('label', '') - - $RGNum = 1 - foreach($RG in $RGs) - { - $Attr = ('ResourceGroup_'+[string]$RGNum) - $Global:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) - $RGNum++ - } - - $Global:XmlWriter.WriteAttributeString('id', ($Global:CellID+'-'+($Global:IDNum++))) - - icon $Global:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Global:ContID4 - - $Global:XmlWriter.WriteEndElement() - - $LocalTop = $LocalTop + 90 - } - - } - - } - - } - - } - - } - - Stencils - - $OrgFile = ($DiagramCache+'Organization.xml') - - $Global:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $Global:DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - $Global:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) - - $Global:IDNum = 0 - $Global:CelNum = 0 - - $Global:XmlWriter = New-Object System.XMl.XmlTextWriter($OrgFile,$Null) - - $Global:XmlWriter.Formatting = 'Indented' - $Global:XmlWriter.Indentation = 2 - - $Global:XmlWriter.WriteStartDocument() - - $Global:XmlWriter.WriteStartElement('mxfile') - $Global:XmlWriter.WriteAttributeString('host', 'Electron') - $Global:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') - $Global:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') - $Global:XmlWriter.WriteAttributeString('etag', $etag) - $Global:XmlWriter.WriteAttributeString('version', '15.4.0') - $Global:XmlWriter.WriteAttributeString('type', 'device') - - $Global:XmlWriter.WriteStartElement('diagram') - $Global:XmlWriter.WriteAttributeString('id', $DiagID) - $Global:XmlWriter.WriteAttributeString('name', 'Organization') - - $Global:XmlWriter.WriteStartElement('mxGraphModel') - $Global:XmlWriter.WriteAttributeString('dx', "1326") - $Global:XmlWriter.WriteAttributeString('dy', "798") - $Global:XmlWriter.WriteAttributeString('grid', "1") - $Global:XmlWriter.WriteAttributeString('gridSize', "10") - $Global:XmlWriter.WriteAttributeString('guides', "1") - $Global:XmlWriter.WriteAttributeString('tooltips', "1") - $Global:XmlWriter.WriteAttributeString('connect', "1") - $Global:XmlWriter.WriteAttributeString('arrows', "1") - $Global:XmlWriter.WriteAttributeString('fold', "1") - $Global:XmlWriter.WriteAttributeString('page', "1") - $Global:XmlWriter.WriteAttributeString('pageScale', "1") - $Global:XmlWriter.WriteAttributeString('pageWidth', "850") - $Global:XmlWriter.WriteAttributeString('pageHeight', "1100") - $Global:XmlWriter.WriteAttributeString('math', "0") - $Global:XmlWriter.WriteAttributeString('shadow', "0") - - $Global:XmlWriter.WriteStartElement('root') - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "0") - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteStartElement('mxCell') - $Global:XmlWriter.WriteAttributeString('id', "1") - $Global:XmlWriter.WriteAttributeString('parent', "0") - $Global:XmlWriter.WriteEndElement() - - - Org - - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndElement() - - $Global:XmlWriter.WriteEndDocument() - $Global:XmlWriter.Flush() - $Global:XmlWriter.Close() - - } -ArgumentList $ResourceContainers,$DiagramCache - -} - - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Draw.IO file') | Out-File -FilePath $LogFile -Append - -$XMLFiles = @() - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting XML files to be clean') | Out-File -FilePath $LogFile -Append - -$XMLFiles += ($DiagramCache+'Organization.xml') -$XMLFiles += ($DiagramCache+'Subscriptions.xml') - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Cleaning old files') | Out-File -FilePath $LogFile -Append - -foreach($File in $XMLFiles) - { - Remove-Item -Path $File -ErrorAction SilentlyContinue - } - - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Organization Function') | Out-File -FilePath $LogFile -Append - -Organization $ResourceContainers $DiagramCache - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Network Topology Function') | Out-File -FilePath $LogFile -Append - -Network $Subscriptions $Resources $Advisories $DiagramCache $FullEnvironment $DDFile $XMLFiles - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Subscription Function') | Out-File -FilePath $LogFile -Append - -Subscription $Subscriptions $Resources $DiagramCache - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting for Jobs to complete') | Out-File -FilePath $LogFile -Append - -(Get-Job | Where-Object {$_.name -like 'Diagram_*'}) | Wait-Job - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting to process files') | Out-File -FilePath $LogFile -Append - -foreach($File in $XMLFiles) - { - $oldxml = New-Object XML - $oldxml.Load($File) - - $newxml = New-Object XML - $newxml.Load($DDFile) - - $oldxml.DocumentElement.InsertAfter($oldxml.ImportNode($newxml.SelectSingleNode('mxfile'), $true), $afternode) - - $oldxml.Save($DDFile) - - Remove-Item -Path $File - } - -('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Cleaning old jobs') | Out-File -FilePath $LogFile -Append - -(Get-Job | Where-Object {$_.name -like 'Diagram_*'}) | Remove-Job diff --git a/Extras/Policy.ps1 b/Extras/Policy.ps1 deleted file mode 100644 index 3f9f473..0000000 --- a/Extras/Policy.ps1 +++ /dev/null @@ -1,90 +0,0 @@ -<# -.Synopsis -Policy Module - -.DESCRIPTION -This script process and creates the Policy sheet based on advisorresources. - -.Link -https://github.com/microsoft/ARI/Extras/Policy.ps1 - -.COMPONENT - This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 3.0.1 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($Policies, $Task , $Subscriptions, $File ,$Pol, $TableStyle) - -If ($Task -eq 'Processing') -{ - $obj = '' - $tmp = @() - - foreach ($1 in $Policies) - { - $data = $1.PROPERTIES - if($data.policyDefinitionId -like '/providers/microsoft.management/managementgroups/*') - { - $Definition = $data.policyDefinitionId.split('/')[8] - } - else - { - $Definition = $data.policyDefinitionId.split('/')[4] - } - $timecreated = [datetime]$data.metadata.createdon - $timecreated = $timecreated.ToString("yyyy-MM-dd HH:mm") - if($data.scope -like '/subscriptions/*') - { - $ScopeType = 'Subscription' - $Scope = ($Subscriptions | Where-Object {$_.id -eq $data.scope.split('/')[2]}).name - } - else - { - $ScopeType = 'Management Group' - $Scope = $data.scope.split('/')[4] - } - - $obj = @{ - 'ID' = $1.id; - 'Definition Id' = $Definition; - 'Name' = $data.displayName; - 'Description' = $data.description; - 'Location' = $1.location; - 'Enforcement Mode' = $data.enforcementmode; - 'Created On' = $timecreated; - 'Assigned By' = $data.metadata.assignedby; - 'Scope Type' = $ScopeType; - 'Scope' = $Scope; - 'Identity Type' = $1.identity.type; - 'Principal Id' = $1.identity.principalId - } - $tmp += $obj - } - $tmp -} -Else -{ - - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0.0 - $StyleExt = New-ExcelStyle -HorizontalAlignment Left -Range B:C -Width 70 -WrapText - - $Pol | - ForEach-Object { [PSCustomObject]$_ } | - Select-Object 'Definition Id', - 'Name', - 'Description', - 'Location', - 'Enforcement Mode', - 'Created On', - 'Assigned By', - 'Scope Type', - 'Scope', - 'Identity Type', - 'Principal Id' | - Export-Excel -Path $File -WorksheetName 'Policy' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzurePolicy' -MoveToStart -TableStyle $tableStyle -Style $Style,$StyleExt -KillExcel - -} diff --git a/Extras/QuotaUsage.ps1 b/Extras/QuotaUsage.ps1 deleted file mode 100644 index a70333c..0000000 --- a/Extras/QuotaUsage.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -<# -.Synopsis -vCPU Quotas Module - -.DESCRIPTION -This script process and creates the Quota sheet based on Quotas Used. - -.Link -https://github.com/microsoft/ARI/Extras/QuotaUsage.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.1.0 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($File, $AzQuota, $TableStyle) - -$tmp = @() -$Total = ($AzQuota.Data).count -foreach($Quota in $AzQuota) -{ - foreach($Data in $Quota.Data) - { - $FreevCPU = '' - if($Data.Name.LocalizedValue -like '*vCPUs'){$FreevCPU = $Data.limit - $Data.CurrentValue} - $obj = @{ - 'Subscription' = $Quota.Subscription; - 'Region' = $Quota.Location; - 'Current Usage' = $Data.currentValue; - 'Limit' = $Data.limit; - 'Quota' = $Data.Name.LocalizedValue; - 'vCPUs Available' = $FreevCPU; - 'Total' = $Total - } - $tmp += $obj - } -} - - $ExcelVar = $tmp - - $TableName = ('QuotaTable_'+$ExcelVar[0].Total) - $ExcelVar | - ForEach-Object { [PSCustomObject]$_ } | - Select-Object -Unique 'Subscription', - 'Region', - 'Current Usage', - 'Limit', - 'Quota', - 'vCPUs Available' | - Export-Excel -Path $File -WorksheetName 'Quota Usage' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -Numberformat '0' -MoveToEnd - - - - \ No newline at end of file diff --git a/Extras/SecurityCenter.ps1 b/Extras/SecurityCenter.ps1 deleted file mode 100644 index 5b6bee5..0000000 --- a/Extras/SecurityCenter.ps1 +++ /dev/null @@ -1,71 +0,0 @@ -<# -.Synopsis -Security Center Module - -.DESCRIPTION -This script process and creates the Security Center sheet based on securityresources. - -.Link -https://github.com/microsoft/ARI/Extras/SecurityCenter.ps1 - -.COMPONENT - This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.0.0 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($Subscriptions,$Security, $Task ,$File, $Sec, $TableStyle) - -If ($Task -eq 'Processing') -{ - $obj = '' - $tmp = @() - - foreach ($1 in $Security) { - $data = $1.PROPERTIES - - $sub1 = $($args[1]) | Where-Object { $_.id -eq $1.properties.resourceDetails.Id.Split("/")[2] } - - $obj = @{ - 'Subscription' = $sub1.Name; - 'Resource Group' = $1.RESOURCEGROUP; - 'Resource Type' = $data.resourceDetails.Id.Split("/")[7]; - 'Resource Name' = $data.resourceDetails.Id.Split("/")[8]; - 'Categories' = [string]$data.metadata.categories; - 'Control' = $data.displayName; - 'Severity' = $data.metadata.severity; - 'Status' = $data.status.code; - 'Remediation' = $data.metadata.remediationDescription; - 'Remediation Effort' = $data.metadata.implementationEffort; - 'User Impact' = $data.metadata.userImpact; - 'Threats' = [string]$data.metadata.threats - } - $tmp += $obj - } - $tmp -} -else -{ - $condtxtsec = $(New-ConditionalText High -Range G:G - New-ConditionalText High -Range L:L) - - $Sec | - ForEach-Object { [PSCustomObject]$_ } | - Select-Object 'Subscription', - 'Resource Group', - 'Resource Type', - 'Resource Name', - 'Categories', - 'Control', - 'Severity', - 'Status', - 'Remediation', - 'Remediation Effort', - 'User Impact', - 'Threats' | - Export-Excel -Path $File -WorksheetName 'SecurityCenter' -AutoSize -MaxAutoSizeRows 100 -MoveToStart -TableName 'SecurityCenter' -TableStyle $tableStyle -ConditionalText $condtxtsec -KillExcel - -} \ No newline at end of file diff --git a/Extras/Subscriptions.ps1 b/Extras/Subscriptions.ps1 deleted file mode 100644 index fbd273f..0000000 --- a/Extras/Subscriptions.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -<# -.Synopsis -Module for Subscriptions - -.DESCRIPTION -This script process and creates the Subscriptions sheet based on resources and subscriptions the resources belong. - -.Link -https://github.com/azureinventory/ARI/Extras/Subscriptions.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.2.1 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> -param($Subscriptions,$resources, $Task ,$File, $Sub, $TableStyle) - -If ($Task -eq 'Processing') -{ - $ResTable = $resources | Where-Object { $_.type -ne 'microsoft.advisor/recommendations' } - $resTable2 = $ResTable | Select-Object id, Type, location, resourcegroup, subscriptionid - $ResTable3 = $ResTable2 | Group-Object -Property type, location, resourcegroup, subscriptionid - - $tmp = @() - - foreach ($ResourcesSUB in $ResTable3) { - $ResourceDetails = $ResourcesSUB.name -split "," - $SubName = $Subscriptions | Where-Object { $_.Id -eq ($ResourceDetails[3] -replace (" ", "")) } - - $obj = @{ - 'Subscription' = $SubName.Name; - 'Resource Group' = $ResourceDetails[2]; - 'Location' = $ResourceDetails[1]; - 'Resource Type' = $ResourceDetails[0]; - 'Resources' = $ResourcesSUB.Count - } - $tmp += $obj - } - $tmp -} -else -{ - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' - - $Sub | - ForEach-Object { [PSCustomObject]$_ } | - Select-Object 'Subscription', - 'Resource Group', - 'Location', - 'Resource Type', - 'Resources' | Export-Excel -Path $File -WorksheetName 'Subscriptions' -AutoSize -MaxAutoSizeRows 100 -TableName 'Subscriptions' -TableStyle $tableStyle -Style $Style -Numberformat '0' -MoveToEnd - - -} \ No newline at end of file diff --git a/Modules/ARIResourceJobs.psm1 b/Modules/ARIResourceJobs.psm1 new file mode 100644 index 0000000..f80948c --- /dev/null +++ b/Modules/ARIResourceJobs.psm1 @@ -0,0 +1,224 @@ +function Start-ARIResourceJobs { + Param ($Resources, $Subscriptions, $InTag, $Unsupported, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + switch ($Resources.count) + { + {$_ -le 1000} + { + $EnvSizeLooper = 1000 + $DebugEnvSize = 'Small' + } + {$_ -gt 1000 -and $_ -le 30000} + { + $EnvSizeLooper = 5000 + $DebugEnvSize = 'Medium' + } + {$_ -gt 30000 -and $_ -le 60000} + { + $EnvSizeLooper = 10000 + $DebugEnvSize = 'Large' + Write-Host $DebugEnvSize -NoNewline -ForegroundColor Green + Write-Host (' Size Environment Identified.') + Write-Host ('Jobs will be run in batches to avoid CPU Overload.') + } + {$_ -gt 60000} + { + $EnvSizeLooper = 5000 + $DebugEnvSize = 'Enormous' + Write-Host $DebugEnvSize -NoNewline -ForegroundColor Green + Write-Host (' Size Environment Identified.') + Write-Host ('Jobs will be run in batches to prevent CPU Overload.') + } + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Processing Jobs in '+ $DebugEnvSize +' Mode.') + + $Loop = $Resources.count / $EnvSizeLooper + $Loop = [math]::ceiling($Loop) + $Looper = 0 + $Limit = 0 + $JobLoop = 1 + + $ResourcesCount = [string]$Resources.count + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Total Resources Being Processed: '+ $ResourcesCount) + + while ($Looper -lt $Loop) { + $Looper ++ + + $Resource = $Resources | Select-Object -First $EnvSizeLooper -Skip $Limit + + $ResourceCount = [string]$Resource.count + $LoopCountStr = [string]$Looper + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resources Being Processed in ResourceJob_'+ $LoopCountStr + ': ' + $ResourceCount) + + Start-Job -Name ('ResourceJob_'+$Looper) -ScriptBlock { + + $Job = @() + + $Subscriptions = $($args[2]) + $InTag = $($args[3]) + $Resource = $($args[4]) + $Task = $($args[5]) + $Unsupported = $($args[9]) + + if($($args[1]) -like '*\*') + { + $Modules = Get-ChildItem -Path ($($args[1]) + '\Scripts\*.ps1') -Recurse + } + else + { + $Modules = Get-ChildItem -Path ($($args[1]) + '/Scripts/*.ps1') -Recurse + } + + $job = @() + + $Modules | ForEach-Object { + $ModName = $_.Name.replace(".ps1","") + $ModuSeq0 = New-Object System.IO.StreamReader($_.FullName) + $ModuSeq = $ModuSeq0.ReadToEnd() + $ModuSeq0.Dispose() + Start-Sleep -Milliseconds 250 + + New-Variable -Name ('ModRun' + $ModName) + New-Variable -Name ('ModJob' + $ModName) + + Set-Variable -Name ('ModRun' + $ModName) -Value ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($PSScriptRoot).AddArgument($Subscriptions).AddArgument($InTag).AddArgument($Resource).AddArgument($Task).AddArgument($null).AddArgument($null).AddArgument($null).AddArgument($Unsupported) + + Set-Variable -Name ('ModJob' + $ModName) -Value ((get-variable -name ('ModRun' + $ModName)).Value).BeginInvoke() + + $job += (get-variable -name ('ModJob' + $ModName)).Value + Start-Sleep -Milliseconds 250 + Clear-Variable -Name ModName + } + + while ($Job.Runspace.IsCompleted -contains $false) { Start-Sleep -Milliseconds 1000 } + + $Modules | ForEach-Object { + $ModName = $_.Name.replace(".ps1","") + Start-Sleep -Milliseconds 250 + + New-Variable -Name ('ModValue' + $ModName) + Set-Variable -Name ('ModValue' + $ModName) -Value (((get-variable -name ('ModRun' + $ModName)).Value).EndInvoke((get-variable -name ('ModJob' + $ModName)).Value)) + + Clear-Variable -Name ('ModRun' + $ModName) + Clear-Variable -Name ('ModJob' + $ModName) + Start-Sleep -Milliseconds 250 + Clear-Variable -Name ModName + } + + [System.GC]::GetTotalMemory($true) | out-null + + $Hashtable = New-Object System.Collections.Hashtable + + $Modules | ForEach-Object { + $ModName = $_.Name.replace(".ps1","") + Start-Sleep -Milliseconds 250 + + $Hashtable["$ModName"] = (get-variable -name ('ModValue' + $ModName)).Value + + Clear-Variable -Name ('ModValue' + $ModName) + Start-Sleep -Milliseconds 100 + + Clear-Variable -Name ModName + } + + [System.GC]::GetTotalMemory($true) | out-null + + $Hashtable + } -ArgumentList $null, $PSScriptRoot, $Subscriptions, $InTag, $Resource, 'Processing', $null, $null, $null, $Unsupported | Out-Null + $Limit = $Limit + $EnvSizeLooper + Start-Sleep -Milliseconds 250 + if($DebugEnvSize -in ('Large','Enormous') -and $JobLoop -eq 5) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Waiting Batch of Jobs to Complete.') + + $coun = 0 + + $InterJobNames = (Get-Job | Where-Object {$_.name -like 'ResourceJob_*' -and $_.State -eq 'Running'}).Name + + while (get-job -Name $InterJobNames | Where-Object { $_.State -eq 'Running' }) { + $jb = get-job -Name $InterJobNames + $c = (((($jb.count - ($jb | Where-Object { $_.State -eq 'Running' }).Count)) / $jb.Count) * 100) + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'initial Jobs Running: '+[string]($jb | Where-Object { $_.State -eq 'Running' }).count) + $c = [math]::Round($coun) + Write-Progress -Id 1 -activity "Processing Initial Resource Jobs" -Status "$coun% Complete." -PercentComplete $coun + Start-Sleep -Seconds 15 + } + $JobLoop = 0 + } + $JobLoop ++ + [System.GC]::GetTotalMemory($true) | out-null + } + return $DebugEnvSize +} + + +function Start-ARIAutResourceJob { + Param($Resources,$Subscriptions,$InTag,$Unsupported) + Write-Output ('Starting Resources Processes') + Write-Output ('Total Resources Being Analyzed: '+$Resources.count) + + $Modules = Get-ChildItem -Path ($PSScriptRoot + '/Scripts/*.ps1') -Recurse + + $SmaResources = @{} + + foreach ($Module in $Modules) + { + + if($RunDebug) + { + Write-Output '' + Write-Output ('DEBUG - Running Module: '+$Module) + } + + $ModName = $Module.Name.replace(".ps1","") + $ModuSeq0 = New-Object System.IO.StreamReader($Module.FullName) + $ModuSeq = $ModuSeq0.ReadToEnd() + $ModuSeq0.Dispose() + + $ScriptBlock = [Scriptblock]::Create($ModuSeq) + + $SmaResources[$ModName] = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $PSScriptRoot, $Subscriptions, $InTag, $Resources, 'Processing', $null, $null, $null, $Unsupported + + Start-Sleep -Milliseconds 100 + + } + return $SmaResources +} + + +function Get-ARIUnsupportedData { + Param($Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + if($PSScriptRoot -like '*\*') + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Validating file: '+$PSScriptRoot + '\Extras\Support.json') + $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '\Extras\Support.json') + } + else + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Validating file: '+$PSScriptRoot + '/Extras/Support.json') + $ModuSeq0 = New-Object System.IO.StreamReader($PSScriptRoot + '/Extras/Support.json') + } + $ModuSeq = $ModuSeq0.ReadToEnd() + $ModuSeq0.Dispose() + + $Unsupported = $ModuSeq | ConvertFrom-Json + + return $Unsupported +} \ No newline at end of file diff --git a/Modules/ARIResourcesReport.psm1 b/Modules/ARIResourcesReport.psm1 new file mode 100644 index 0000000..f0b165f --- /dev/null +++ b/Modules/ARIResourcesReport.psm1 @@ -0,0 +1,72 @@ +function Start-ARIResourceReporting { + Param($InTag, $file, $SmaResources, $TableStyle, $Unsupported, $DebugEnvSize, $DataActive, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Reporting Phase.') + Write-Progress -activity $DataActive -Status "Processing Inventory" -PercentComplete 50 + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Running Offline, Gathering List Of Modules.') + if($PSScriptRoot -like '*\*') + { + $Modules = Get-ChildItem -Path ($PSScriptRoot + '\Scripts\*.ps1') -Recurse + } + else + { + $Modules = Get-ChildItem -Path ($PSScriptRoot + '/Scripts/*.ps1') -Recurse + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Modules Found: ' + $Modules.Count) + $Lops = $Modules.count + $ReportCounter = 0 + + foreach ($Module in $Modules) { + + $c = (($ReportCounter / $Lops) * 100) + $c = [math]::Round($c) + Write-Progress -Id 1 -activity "Building Report" -Status "$c% Complete." -PercentComplete $c + + $ModuSeq0 = New-Object System.IO.StreamReader($Module.FullName) + $ModuSeq = $ModuSeq0.ReadToEnd() + $ModuSeq0.Dispose() + Start-Sleep -Milliseconds 50 + $ModuleName = $Module.name.replace('.ps1','') + + $ModuleResourceCount = $SmaResources.$ModuleName.count + + if ($ModuleResourceCount -gt 0) + { + Start-Sleep -Milliseconds 100 + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Running Module: '$ModuleName'. Lines Count: $ModuleResourceCount") + + $ExcelRun = ([PowerShell]::Create()).AddScript($ModuSeq).AddArgument($PSScriptRoot).AddArgument($null).AddArgument($InTag).AddArgument($null).AddArgument('Reporting').AddArgument($file).AddArgument($SmaResources).AddArgument($TableStyle).AddArgument($Unsupported) + + $ExcelJob = $ExcelRun.BeginInvoke() + + while ($ExcelJob.IsCompleted -contains $false) { Start-Sleep -Milliseconds 100 } + + $ExcelRun.EndInvoke($ExcelJob) + + $ExcelRun.Dispose() + + [System.GC]::GetTotalMemory($true) | out-null + } + + $ReportCounter ++ + + } + + if($DebugEnvSize -in ('Large','Enormous')) + { + Clear-Variable SmaResources -Scope Global + [System.GC]::GetTotalMemory($true) | out-null + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resource Reporting Phase Done.') +} \ No newline at end of file diff --git a/Modules/Core/ARIExtraJobs.psm1 b/Modules/Core/ARIExtraJobs.psm1 new file mode 100644 index 0000000..cb9b890 --- /dev/null +++ b/Modules/Core/ARIExtraJobs.psm1 @@ -0,0 +1,314 @@ +function Start-ARIExtraJobs { + Param ($SkipDiagram, $SkipAdvisory, $SkipPolicy, $SecurityCenter, $Subscriptions, $Resources, $Advisories, $DDFile, $DiagramCache, $FullEnv, $ResourceContainers, $Security, $PolicyDef, $PolicySetDef, $PolicyAssign, $Automation, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + <######################################################### DRAW IO DIAGRAM JOB ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Draw.io Diagram Job Should be Run.') + if (!$SkipDiagram.IsPresent) { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Draw.io Diagram Processing Job.') + Start-job -Name 'DrawDiagram' -ScriptBlock { + + Import-Module AzureResourceInventory + + $DiagramCache = $($args[5]) + + $TempPath = $DiagramCache.split("DiagramCache\")[0] + + $Logfile = ($TempPath+'DiagramLogFile.log') + + ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Draw.IO Job') | Out-File -FilePath $LogFile -Append + + ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Draw.IO Thread') | Out-File -FilePath $LogFile -Append + try + { + Invoke-ARIDrawIODiagram -Subscriptions $($args[0]) -Resources $($args[1]) -Advisories $($args[2]) -DDFile $($args[3]) -DiagramCache $($args[4]) -FullEnvironment $($args[5]) -ResourceContainers $($args[6]) + + } + catch + { + ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+$_.Exception.Message) | Out-File -FilePath $LogFile -Append + } + ('DrawIOCoreJob - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Draw.IO Ended.') | Out-File -FilePath $LogFile -Append + + } -ArgumentList $Subscriptions, $Resources, $Advisories, $DDFile, $DiagramCache, $FullEnv, $ResourceContainers | Out-Null + } + + <######################################################### VISIO DIAGRAM JOB ######################################################################> + <# + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Visio Diagram Job Should be Run.') + if ($Diagram.IsPresent) { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Visio Diagram Processing Job.') + Start-job -Name 'VisioDiagram' -ScriptBlock { + + If ($($args[5]) -eq $true) { + $ModuSeq = (New-Object System.Net.WebClient).DownloadString($($args[7]) + '/Extras/VisioDiagram.ps1') + } + Else { + $ModuSeq0 = New-Object System.IO.StreamReader($($args[0]) + '\Extras\VisioDiagram.ps1') + $ModuSeq = $ModuSeq0.ReadToEnd() + $ModuSeq0.Dispose() + } + + $ScriptBlock = [Scriptblock]::Create($ModuSeq) + + $VisioRun = ([PowerShell]::Create()).AddScript($ScriptBlock).AddArgument($($args[1])).AddArgument($($args[2])).AddArgument($($args[3])).AddArgument($($args[4])) + + $VisioJob = $VisioRun.BeginInvoke() + + while ($VisioJob.IsCompleted -contains $false) {} + + $VisioRun.EndInvoke($VisioJob) + + $VisioRun.Dispose() + + } -ArgumentList $PSScriptRoot, $Subscriptions, $Resources, $Advisories, $DFile, $RunOnline, $Repo, $RawRepo | Out-Null + } + #> + + <######################################################### SECURITY CENTER JOB ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Security Center Job.') + if ($SecurityCenter.IsPresent) { + if (![string]::IsNullOrEmpty($Security)) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Security Job.') + if ($Automation.IsPresent) + { + Write-Output ('Starting SecurityCenter Job') + Start-ThreadJob -Name 'Security' -ScriptBlock { + + Import-Module AzureResourceInventory + + $SecResult = Invoke-ARISecCenterProcessing -Subscriptions $Subscriptions -Security $Security + + $SecResult + + } -ArgumentList $Subscriptions , $Security | Out-Null + } + else + { + Start-Job -Name 'Security' -ScriptBlock { + + Import-Module AzureResourceInventory + + $SecResult = Invoke-ARISecCenterProcessing -Subscriptions $Subscriptions -Security $Security + + $SecResult + + } -ArgumentList $Subscriptions , $Security | Out-Null + } + } + } + + <######################################################### POLICY JOB ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Policy Job.') + if (!$SkipPolicy.IsPresent) { + if (![string]::IsNullOrEmpty($PolicyAssign) -and ![string]::IsNullOrEmpty($PolicyDef)) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Policy Processing Job.') + if ($Automation.IsPresent) + { + Write-Output ('Starting Policy Job') + Start-ThreadJob -Name 'Policy' -ScriptBlock { + + Import-Module AzureResourceInventory + + $PolResult = Invoke-ARIPolicyProcessing -Subscriptions $($args[0]) -PolicySetDef $($args[1]) -PolicyAssign $($args[2]) -PolicyDef $($args[3]) + + $PolResult + + } -ArgumentList $Subscriptions, $PolicySetDef, $PolicyAssign, $PolicyDef | Out-Null + } + else + { + Start-Job -Name 'Policy' -ScriptBlock { + + Import-Module AzureResourceInventory + + $PolResult = Invoke-ARIPolicyProcessing -Subscriptions $($args[0]) -PolicySetDef $($args[1]) -PolicyAssign $($args[2]) -PolicyDef $($args[3]) + + $PolResult + + } -ArgumentList $Subscriptions, $PolicySetDef, $PolicyAssign, $PolicyDef | Out-Null + } + } + } + + <######################################################### ADVISORY JOB ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking If Should Run Advisory Job.') + if (!$SkipAdvisory.IsPresent) { + if (![string]::IsNullOrEmpty($Advisories)) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Advisory Processing Job.') + if ($Automation.IsPresent) + { + Write-Output ('Starting Advisory Job') + Start-ThreadJob -Name 'Advisory' -ScriptBlock { + + Import-Module AzureResourceInventory + + $AdvResult = Invoke-ARIAdvisoryProcessing -Advisories $args + + $AdvResult + + } -ArgumentList $Advisories | Out-Null + } + else + { + Start-Job -Name 'Advisory' -ScriptBlock { + + Import-Module AzureResourceInventory + + $AdvResult = Invoke-ARIAdvisoryProcessing -Advisories $args + + $AdvResult + + } -ArgumentList $Advisories | Out-Null + } + } + } + + <######################################################### SUBSCRIPTIONS JOB ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Subscriptions job.') + if ($Automation.IsPresent) + { + Write-Output ('Starting Subscription Job') + Start-ThreadJob -Name 'Subscriptions' -ScriptBlock { + + Import-Module AzureResourceInventory + + $SubResult = Invoke-ARISubsProcessing -Subscriptions $($args[0]) -Resources $($args[1]) + + $SubResult + + } -ArgumentList $Subscriptions, $Resources | Out-Null + } + else + { + Start-Job -Name 'Subscriptions' -ScriptBlock { + + Import-Module AzureResourceInventory + + $SubResult = Invoke-ARISubsProcessing -Subscriptions $($args[0]) -Resources $($args[1]) + + $SubResult + + } -ArgumentList $Subscriptions, $Resources | Out-Null + } +} + +function Start-ARIExtraReports { + Param($File, $QuotaUsage, $SecurityCenter, $SkipPolicy, $SkipAdvisory, $TableStyle, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + if($QuotaUsage.IsPresent) + { + get-job -Name 'Quota Usage' | Wait-Job + + $AzQuota = Receive-Job -Name 'Quota Usage' + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Quota Usage sheet for: ' + $AzQuota.count + ' Subscriptions/Regions.') + + Write-Progress -activity 'Azure Resource Inventory Quota Usage' -Status "50% Complete." -PercentComplete 50 -CurrentOperation "Building Quota Sheet" + + Build-ARIQuotaReport -File $File -AzQuota $AzQuota -TableStyle $TableStyle + + Write-Progress -activity 'Azure Resource Inventory Quota Usage' -Status "100% Complete." -Completed + } + + <################################################ SECURITY CENTER #######################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Security Center Sheet.') + if ($SecurityCenter.IsPresent) { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Security Center Sheet.') + + while (get-job -Name 'Security' | Where-Object { $_.State -eq 'Running' }) { + Write-Progress -Id 1 -activity 'Processing Security Center Advisories' -Status "50% Complete." -PercentComplete 50 + Start-Sleep -Seconds 2 + } + Write-Progress -Id 1 -activity 'Processing Security Center Advisories' -Status "100% Complete." -Completed + + $Sec = Receive-Job -Name 'Security' + + Build-ARISecCenterReport -File $File -Sec $Sec -TableStyle $TableStyle + + } + + <################################################ POLICY #######################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Policy Sheet.') + if (!$SkipPolicy.IsPresent) { + if(get-job -Name 'Policy') + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Policy Sheet.') + + while (get-job -Name 'Policy' | Where-Object { $_.State -eq 'Running' }) { + Write-Progress -Id 1 -activity 'Processing Policies' -Status "50% Complete." -PercentComplete 50 + Start-Sleep -Seconds 2 + } + Write-Progress -Id 1 -activity 'Processing Policies' -Status "100% Complete." -Completed + + $Pol = Receive-Job -Name 'Policy' + + Build-ARIPolicyReport -File $File -Pol $Pol -TableStyle $TableStyle + + Start-Sleep -Milliseconds 200 + } + } + + <################################################ ADVISOR #######################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Checking if Should Generate Advisory Sheet.') + if (!$SkipAdvisory.IsPresent) { + if (get-job -Name 'Advisory') + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Advisor Sheet.') + + while (get-job -Name 'Advisory' | Where-Object { $_.State -eq 'Running' }) { + Write-Progress -Id 1 -activity 'Processing Advisories' -Status "50% Complete." -PercentComplete 50 + Start-Sleep -Seconds 2 + } + Write-Progress -Id 1 -activity 'Processing Advisories' -Status "100% Complete." -Completed + + $Adv = Receive-Job -Name 'Advisory' + + Build-ARIAdvisoryReport -File $File -Adv $Adv -TableStyle $TableStyle + + Start-Sleep -Milliseconds 200 + } + } + + <################################################################### SUBSCRIPTIONS ###################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Subscription sheet.') + + Write-Progress -activity 'Azure Resource Inventory Subscriptions' -Status "50% Complete." -PercentComplete 50 -CurrentOperation "Building Subscriptions Sheet" + + $AzSubs = Receive-Job -Name 'Subscriptions' + + Build-ARISubsReport -File $File -Sub $AzSubs -TableStyle $TableStyle + + [System.GC]::GetTotalMemory($true) | out-null + + Write-Progress -activity 'Azure Resource Inventory Subscriptions' -Status "100% Complete." -Completed +} \ No newline at end of file diff --git a/Modules/Core/ARIGetSubs.psm1 b/Modules/Core/ARIGetSubs.psm1 new file mode 100644 index 0000000..1f14299 --- /dev/null +++ b/Modules/Core/ARIGetSubs.psm1 @@ -0,0 +1,17 @@ +function Get-ARISubscriptions { + Param ($TenantID,$SubscriptionID) + Write-Host "Extracting Subscriptions from Tenant $TenantID" + $Subscriptions = Get-AzSubscription -TenantId $TenantID -WarningAction SilentlyContinue -InformationAction SilentlyContinue + if ($SubscriptionID) + { + if($SubscriptionID.count -gt 1) + { + $Subscriptions = $Subscriptions | Where-Object { $_.ID -in $SubscriptionID } + } + else + { + $Subscriptions = $Subscriptions | Where-Object { $_.ID -eq $SubscriptionID } + } + } + return $Subscriptions +} \ No newline at end of file diff --git a/Modules/Core/ARIInventoryLoop.psm1 b/Modules/Core/ARIInventoryLoop.psm1 new file mode 100644 index 0000000..dffc586 --- /dev/null +++ b/Modules/Core/ARIInventoryLoop.psm1 @@ -0,0 +1,97 @@ +<# +.Synopsis +Azure Resource Graph loop module + +.DESCRIPTION +This module is use to loop trough the Azure Resource Graph. + +.Link +https://github.com/microsoft/ARI/Modules/Core/ARIInventoryLoop.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ResourceInventoryLoop { + param($GraphQuery,$FSubscri,$LoopName) + + Write-Progress -activity 'Azure Inventory' -Status "10% Complete." -PercentComplete 10 -CurrentOperation ('Extracting: ' + $LoopName) + $ReportCounter = 1 + $LocalResults = @() + if($FSubscri.count -gt 200) + { + $SubLoop = $FSubscri.count / 200 + $SubLooper = 0 + $NStart = 0 + $NEnd = 200 + while ($SubLooper -lt $SubLoop) + { + $Sub = $FSubscri[$NStart..$NEnd] + try + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting First 1000 Resources') + $QueryResult = Search-AzGraph -Query $GraphQuery -first 1000 -Subscription $Sub + } + catch + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting First 200 Resources') + $QueryResult = Search-AzGraph -Query $GraphQuery -first 200 -Subscription $Sub + } + $LocalResults += $QueryResult + while ($QueryResult.SkipToken) { + $ReportCounterVar = [string]$ReportCounter + try + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting Next 1000 Resources. Loop Number: ' + $ReportCounterVar) + $QueryResult = Search-AzGraph -Query $GraphQuery -SkipToken $QueryResult.SkipToken -Subscription $Sub -first 1000 + } + catch + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting Next 200 Resources. Loop Number: ' + $ReportCounterVar) + $QueryResult = Search-AzGraph -Query $GraphQuery -SkipToken $QueryResult.SkipToken -Subscription $Sub -first 200 + } + $LocalResults += $QueryResult + } + $NStart = $NStart + 200 + $NEnd = $NEnd + 200 + $SubLooper ++ + $ReportCounter ++ + } + } + else + { + try + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting First 1000 Resources') + $QueryResult = Search-AzGraph -Query $GraphQuery -first 1000 -Subscription $FSubscri + } + catch + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting First 200 Resources') + $QueryResult = Search-AzGraph -Query $GraphQuery -first 200 -Subscription $FSubscri + } + + $LocalResults += $QueryResult + while ($QueryResult.SkipToken) { + $ReportCounterVar = [string]$ReportCounter + try + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting Next 1000 Resources. Loop Number: ' + $ReportCounterVar) + $QueryResult = Search-AzGraph -Query $GraphQuery -SkipToken $QueryResult.SkipToken -Subscription $FSubscri -first 1000 + } + catch + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Extracting Next 200 Resources. Loop Number: ' + $ReportCounterVar) + $QueryResult = Search-AzGraph -Query $GraphQuery -SkipToken $QueryResult.SkipToken -Subscription $FSubscri -first 200 + } + $LocalResults += $QueryResult + $ReportCounter ++ + } + } + $LocalResults +} \ No newline at end of file diff --git a/Modules/Core/ARILoginSession.psm1 b/Modules/Core/ARILoginSession.psm1 new file mode 100644 index 0000000..38714ec --- /dev/null +++ b/Modules/Core/ARILoginSession.psm1 @@ -0,0 +1,123 @@ +<# +.Synopsis +Azure Login Session Module for Azure Resource Inventory + +.DESCRIPTION +This module is used to invoke the authentication process that is handle by the Azure CLI. + +.Link +https://github.com/microsoft/ARI/Core/Connect-LoginSession.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Connect-ARILoginSession { + Param($AzureEnvironment,$TenantID,$SubscriptionID,$DeviceLogin,$Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Connect-LoginSession function') + Write-Host $AzureEnvironment -BackgroundColor Green + if (!$TenantID) { + write-host "Tenant ID not specified. Use -TenantID parameter if you want to specify directly. " + write-host "Authenticating Azure" + write-host "" + Clear-AzContext -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -InformationAction SilentlyContinue + if($DeviceLogin.IsPresent) + { + Connect-AzAccount -UseDeviceAuthentication -Environment $AzureEnvironment | Out-Null + } + else + { + try + { + $AZConfigNewLogin = Get-AzConfig -LoginExperienceV2 -WarningAction SilentlyContinue -InformationAction SilentlyContinue + if ($AZConfigNewLogin.value -eq 'On' ) + { + Update-AzConfig -LoginExperienceV2 Off | Out-Null + Connect-AzAccount -Environment $AzureEnvironment | Out-Null + Update-AzConfig -LoginExperienceV2 On | Out-Null + } + else + { + Connect-AzAccount -Environment $AzureEnvironment | Out-Null + } + } + catch + { + Connect-AzAccount -Environment $AzureEnvironment | Out-Null + } + } + write-host "" + write-host "" + $Tenants = Get-AzTenant -WarningAction SilentlyContinue -InformationAction SilentlyContinue | Sort-Object -Unique + if ($Tenants.Count -eq 1) { + write-host "You have privileges only in One Tenant " + write-host "" + $TenantID = $Tenants.Id + } + else { + write-host "Select the the Azure Tenant ID that you want to connect : " + write-host "" + $SequenceID = 1 + foreach ($Tenant in $Tenants) { + $TenantName = $Tenant.name + write-host "$SequenceID) $TenantName" + $SequenceID ++ + } + write-host "" + [int]$SelectTenant = read-host "Select Tenant ( default 1 )" + $defaultTenant = --$SelectTenant + $TenantID = ($Tenants[$defaultTenant]).Id + if($DeviceLogin.IsPresent) + { + Connect-AzAccount -Tenant $TenantID -UseDeviceAuthentication -Environment $AzureEnvironment | Out-Null + } + else + { + Connect-AzAccount -Tenant $TenantID -Environment $AzureEnvironment | Out-Null + } + } + } + else { + Clear-AzContext -Force | Out-Null + if($DeviceLogin.IsPresent) + { + Connect-AzAccount -Tenant $TenantID -UseDeviceAuthentication -Environment $AzureEnvironment | Out-Null + } + else + { + try + { + $AZConfig = Get-AzConfig -LoginExperienceV2 -WarningAction SilentlyContinue -InformationAction SilentlyContinue + if ($AZConfig.value -eq 'On') + { + Update-AzConfig -LoginExperienceV2 Off | Out-Null + Connect-AzAccount -Tenant $TenantID -Environment $AzureEnvironment | Out-Null + Update-AzConfig -LoginExperienceV2 On | Out-Null + } + else + { + Connect-AzAccount -Tenant $TenantID -Environment $AzureEnvironment | Out-Null + } + } + catch + { + Connect-AzAccount -Tenant $TenantID -Environment $AzureEnvironment | Out-Null + } + } + } + return $TenantID +} \ No newline at end of file diff --git a/Modules/Core/ARITestPS.psm1 b/Modules/Core/ARITestPS.psm1 new file mode 100644 index 0000000..45e4ab7 --- /dev/null +++ b/Modules/Core/ARITestPS.psm1 @@ -0,0 +1,51 @@ +<# +.Synopsis +Test Powershell environment + +.DESCRIPTION +This module is use to test and validate the Powershell environment. + +.Link +https://github.com/microsoft/ARI/Modules/Core/Test-ARIPS.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Test-ARIPS { + Param($Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Test-ARIPS function') + $CShell = try{Get-CloudShellTip}catch{$null} + if ($CShell) { + Write-Host 'Azure CloudShell Identified.' -ForegroundColor Cyan + $PlatOS = 'Azure CloudShell' + } + else + { + if ($PSVersionTable.Platform -eq 'Unix') { + Write-Host "PowerShell Unix Identified." -ForegroundColor Cyan + $PlatOS = 'PowerShell Unix' + + } + else { + Write-Host "PowerShell Desktop Identified." -ForegroundColor Cyan + $PlatOS = 'PowerShell Desktop' + + } + } + return $PlatOS +} \ No newline at end of file diff --git a/Modules/Diagram/ARIDiagramNetwork.psm1 b/Modules/Diagram/ARIDiagramNetwork.psm1 new file mode 100644 index 0000000..ca5b45c --- /dev/null +++ b/Modules/Diagram/ARIDiagramNetwork.psm1 @@ -0,0 +1,3070 @@ +<# +.Synopsis +Network Module for Draw.io Diagram + +.DESCRIPTION +This module is use for the Network topology in the Draw.io Diagram. + +.Link +https://github.com/microsoft/ARI/Modules/Extras/ARIDiagramNetwork.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +Function Invoke-ARIDiagramNetwork { + Param($Subscriptions,$Resources,$Advisories,$DiagramCache,$FullEnvironment,$DDFile,$XMLFiles,$LogFile) + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Network Diagram Job...') | Out-File -FilePath $LogFile -Append + + Start-Job -Name 'Diagram_NetworkTopology' -ScriptBlock { + + Import-Module AzureResourceInventory + + $Script:jobs = @() + $Script:jobs2 = @() + $Script:Subscriptions = $($args[0]) + $Script:Resources = $($args[1]) + $Script:Advisories = $($args[2]) + $Script:DiagramCache = $($args[3]) + $Script:FullEnvironment = $($args[4]) + $Script:DDFile = $($args[5]) + $Script:XMLFiles = $($args[6]) + $Script:Logfile = $($args[7]) + + Function Icon { + Param($Style,$x,$y,$w,$h,$p) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', $Style) + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function VNETContainer { + Param($x,$y,$w,$h,$title) + $Script:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;swimlaneFillColor=#D5E8D4;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function HubContainer { + Param($x,$y,$w,$h,$title) + $Script:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;rounded=1;swimlaneFillColor=#DAE8FC;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function BrokenContainer { + Param($x,$y,$w,$h,$title) + $Script:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#fad9d5;strokeColor=#ae4132;swimlaneFillColor=#FAD9D5;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Connect { + Param($Source,$Target,$Parent) + + if($Parent){$Parent = $Parent}else{$Parent = 1} + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + $Script:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") + $Script:XmlWriter.WriteAttributeString('edge', "1") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $Parent) + $Script:XmlWriter.WriteAttributeString('source', $Source) + $Script:XmlWriter.WriteAttributeString('target', $Target) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('relative', "1") + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + } + + <# Function to create the Visio document and import each stencil #> + Function Stensils { + $Script:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" + + $Script:IconConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" + $Script:IconExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" + $Script:IconVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" + $Script:IconVGW2 = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" + $Script:IconVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" + $Script:IconTraffic = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Local_Network_Gateways.svg;" #width="68" height="68" + $Script:IconNIC = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;" #width="68" height="60" + $Script:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" + $Script:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" + $Script:IconNSG = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Network_Security_Groups.svg;" # width="26.35" height="32" + $Script:IconUDR = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Route_Tables.svg;" #width="30.97" height="30" + $Script:IconDDOS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;" # width="23" height="28" + $Script:IconPIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" + $Script:IconNAT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/NAT.svg;" # width="65" height="52" + + <########################## Azure Generic Stencils #############################> + + $Script:SymError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="50" height="50" + $Script:SymInfo = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Information.svg;" #width="64" height="64" + $Script:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" + $Script:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" + $Script:IconBastions = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/general/Launch_Portal.svg;" #width="68" height="67" + $Script:IconContain = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Container_Instances.svg;" #width="64" height="68" + $Script:IconVWAN = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_WANs.svg;" #width="65" height="64" + $Script:IconCostMGMT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Cost_Analysis.svg;" #width="60" height="70" + + <########################## Azure Computing Stencils #############################> + + $Script:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" + $Script:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" + $Script:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" + $Script:IconARO = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/mscae/OpenShift.svg;" #width="50" height="46" + $Script:IconFunApps = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Function_Apps.svg;" # width="68" height="60" + + <########################## Azure Service Stencils #############################> + + $Script:IconAPIMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/app_services/API_Management_Services.svg;" #width="65" height="60" + $Script:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" + + <########################## Azure Storage Stencils #############################> + + $Script:IconNetApp = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;" #width="65" height="52" + + <########################## Azure Storage Stencils #############################> + + $Script:IconDataExplorer = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;" #width="68" height="68" + + <########################## Other Stencils #############################> + + $Script:IconFWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;" #width="71" height="60" + $Script:IconDet = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/other/Detonation.svg;" #width="42.63" height="44" + $Script:IconAppGWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;" #width="64" height="64" + $Script:IconBricks = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;" #width="60" height="68" + $Script:IconError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="30" height="30" + $Script:OnPrem = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/mscae/Exchange_On_premises_Access.svg;" #width="168.2" height="290" + $Script:Signature = "aspect=fixed;html=1;points=[];align=left;image;fontSize=22;image=img/lib/azure2/general/Dev_Console.svg;" #width="27.5" height="22" + $Script:CloudOnly = "aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;" #width="380.77" height="275" + + } + + <# Function to begin OnPrem environment drawing. Will begin by Local network Gateway, then Express Route.#> + Function OnPremNet { + $Script:VNETHistory = @() + $Script:RoutsW = $AZVNETs | Select-Object -Property Name, @{N="Subnets";E={$_.properties.subnets.properties.addressPrefix.count}} | Sort-Object -Property Subnets -Descending + + $Script:Alt = 0 + + ##################################### Local Network Gateway ############################################# + + foreach($GTW in $AZLGWs) + { + if($GTW.properties.provisioningState -ne 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'This Local Network Gateway has Errors') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconError 40 ($Script:Alt+25) "25" "25" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Con1 = $AZCONs | Where-Object {$_.properties.localNetworkGateway2.id -eq $GTW.id} + + if(!$Con1 -and $GTW.properties.provisioningState -eq 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'No Connections were found in this Local Network Gateway') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SymInfo 40 ($Script:Alt+30) "20" "20" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Name = $GTW.name + $IP = $GTW.properties.gatewayIpAddress + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name + "`n" + [string]$IP)) + $Script:XmlWriter.WriteAttributeString('Local_Address_Space', [string]$GTW.properties.localNetworkAddressSpace.addressPrefixes) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconTraffic 50 $Script:Alt "67" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:GTWAddress = ($Script:CellID+'-'+($Script:IDNum-1)) + $Script:ConnSourceResource = 'GTW' + + OnPrem $Con1 + + $Script:Alt = $Script:Alt + 150 + } + + ##################################### ERS ############################################# + + Foreach($ERs in $AZEXPROUTEs) + { + if($ERs.properties.provisioningState -ne 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'This Express Route has Errors') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconError 51 ($Script:Alt+25) "25" "25" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Con1 = $AZCONs | Where-Object {$_.properties.peer.id -eq $ERs.id} + + if(!$Con1 -and $ERs.properties.circuitProvisioningState -eq 'Enabled') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'No Connections were found in this Express Route') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SymInfo 51 ($Script:Alt+30) "20" "20" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Name = $ERs.name + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" +[string]$Name)) + $Script:XmlWriter.WriteAttributeString('Provider', [string]$ERs.properties.serviceProviderProperties.serviceProviderName) + $Script:XmlWriter.WriteAttributeString('Peering_location', [string]$ERs.properties.serviceProviderProperties.peeringLocation) + $Script:XmlWriter.WriteAttributeString('Bandwidth', [string]$ERs.properties.serviceProviderProperties.bandwidthInMbps) + $Script:XmlWriter.WriteAttributeString('SKU', [string]$ERs.sku.tier) + $Script:XmlWriter.WriteAttributeString('Billing_model', $ERs.sku.family) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconExpressRoute "61.5" $Script:Alt "44" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:ERAddress = ($Script:CellID+'-'+($Script:IDNum-1)) + $Script:ConnSourceResource = 'ER' + + OnPrem $Con1 + + $Script:Alt = $Script:Alt + 150 + + } + + ##################################### VWAN VPNSITES ############################################# + + foreach($GTW in $AZVPNSITES) + { + if($GTW.properties.provisioningState -ne 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'This VPN Site has Errors') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconError 40 ($Script:Alt+25) "25" "25" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $wan1 = $AZVWAN | Where-Object {$_.properties.vpnSites.id -eq $GTW.id} + + if(!$wan1 -and $GTW.properties.provisioningState -eq 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'No vWANs were found in this VPN Site') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SymInfo 40 ($Script:Alt+30) "20" "20" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Name = $GTW.name + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name)) + $Script:XmlWriter.WriteAttributeString('Address_Space', [string]$GTW.properties.addressSpace.addressPrefixes) + $Script:XmlWriter.WriteAttributeString('Link_Speed_In_Mbps', [string]$GTW.properties.deviceProperties.linkSpeedInMbps) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconNAT 50 $Script:Alt "67" "40" 1 + + $Script:XmlWriter.WriteEndElement() + #$tt = $tt + 200 + + vWan $wan1 + + $Script:Alt = $Script:Alt + 150 + } + + ##################################### VWAN ERs ############################################# + + foreach($GTW in $AZVERs) + { + if($GTW.properties.provisioningState -ne 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'This Express Route Circuit has Errors') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconError 40 ($Script:Alt+25) "25" "25" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $wan1 = $AZVWAN | Where-Object {$_.properties.vpnSites.id -eq $GTW.id} + + if(!$wan1 -and $GTW.properties.provisioningState -eq 'Succeeded') + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Status', 'No vWANs were found in this Express Route Circuit') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SymInfo 40 ($Script:Alt+30) "20" "20" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Name = $GTW.name + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" + [string]$Name)) + $Script:XmlWriter.WriteAttributeString('Address_Space', [string]$GTW.properties.addressSpace.addressPrefixes) + $Script:XmlWriter.WriteAttributeString('LinkSpeed_In_Mbps', [string]$GTW.properties.deviceProperties.linkSpeedInMbps) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconNAT 50 $Script:Alt "67" "40" 1 + + $Script:XmlWriter.WriteEndElement() + #$tt = $tt + 200 + + vWan $wan1 + + $Script:Alt = $Script:Alt + 150 + } + + ##################################### LABELs ############################################# + + if(!$Script:FullEnvironment) + { + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Ret -520 -100 "500" ($Script:Alt + 100) 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ('On Premises'+ "`n" +'Environment')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $OnPrem -351 (($Script:Alt + 100)/2) "168.2" "290" 1 + + $Script:XmlWriter.WriteEndElement() + + label + + Icon $Signature -520 ($Script:Alt + 100) "27.5" "22" 1 + + $Script:XmlWriter.WriteEndElement() + } + + } + + Function OnPrem { + Param($Con1) + foreach ($Con2 in $Con1) + { + if([string]::IsNullOrEmpty($Script:vnetLoc)) + { + $Script:vnetLoc = 700 + } + $VGT = $AZVGWs | Where-Object {$_.id -eq $Con2.properties.virtualNetworkGateway1.id} + $VGTPIP = $PIPs | Where-Object {$_.properties.ipConfiguration.id -eq $VGT.properties.ipConfigurations.id} + + $Name2 = $Con2.Name + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', [string]$Name2) + $Script:XmlWriter.WriteAttributeString('Connection_Type', [string]$Con2.properties.connectionType) + $Script:XmlWriter.WriteAttributeString('Use_Azure_Private_IP_Address', [string]$Con2.properties.useLocalAzureIpAddress) + $Script:XmlWriter.WriteAttributeString('Routing_Weight', [string]$Con2.properties.routingWeight) + $Script:XmlWriter.WriteAttributeString('Connection_Protocol', [string]$Con2.properties.connectionProtocol) + $Script:Source = ($Script:CellID+'-'+($Script:IDNum-1)) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconConnections 250 $Script:Alt "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + if($Script:ConnSourceResource -eq 'ER') + { + Connect $Script:ERAddress $Script:Target + } + elseif($Script:ConnSourceResource -eq 'GTW') + { + Connect $Script:GTWAddress $Script:Target + } + + $Script:Source = $Script:Target + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" +[string]$VGT.Name + "`n" + [string]$VGTPIP.properties.ipAddress)) + $Script:XmlWriter.WriteAttributeString('VPN_Type', [string]$VGT.properties.vpnType) + $Script:XmlWriter.WriteAttributeString('Generation', [string]$VGT.properties.vpnGatewayGeneration ) + $Script:XmlWriter.WriteAttributeString('SKU', [string]$VGT.properties.sku.name) + $Script:XmlWriter.WriteAttributeString('Gateway_Type', [string]$VGT.properties.gatewayType) + $Script:XmlWriter.WriteAttributeString('Active_active_mode', [string]$VGT.properties.activeActive) + $Script:XmlWriter.WriteAttributeString('Gateway_Private_IPs', [string]$VGT.properties.enablePrivateIpAddress) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVGW2 425 ($Script:Alt-4) "31.34" "48" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + Connect $Script:Source $Script:Target + + $Script:Source = $Script:Target + + foreach($AZVNETs2 in $AZVNETs) + { + foreach($VNETTEMP in $AZVNETs2.properties.subnets.properties.ipconfigurations.id) + { + $VV4 = $VNETTEMP.Split("/") + $VNETTEMP1 = ($VV4[0] + '/' + $VV4[1] + '/' + $VV4[2] + '/' + $VV4[3] + '/' + $VV4[4] + '/' + $VV4[5] + '/' + $VV4[6] + '/' + $VV4[7]+ '/' + $VV4[8]) + if($VNETTEMP1 -eq $VGT.id) + { + $Script:VNET2 = $AZVNETs2 + + $Script:Alt0 = $Script:Alt + if($VNET2.id -notin $VNETHistory.vnet) + { + if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) + { + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' + }Else{ + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) + if($VNET2.properties.dhcpoptions.dnsServers) + { + $Script:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + else + { + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVNET 600 $Script:Alt "65" "39" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:VNETDrawID = ($Script:CellID+'-'+($Script:IDNum-1)) + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + Connect $Script:Source $Script:Target + + if($VNET2.properties.enableDdosProtection -eq $true) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDDOS 580 ($Script:Alt + 15) "23" "28" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Script:Source = $Script:Target + + VNETCreator $Script:VNET2 + + if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) + { + PeerCreator $Script:VNET2 + } + + $tmp =@{ + 'VNETid' = $Script:VNETDrawID; + 'VNET' = $AZVNETs2.id + } + $Script:VNETHistory += $tmp + + } + else + { + + $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $AZVNETs2.id} + + Connect $Script:Source $VNETDID.VNETid + + } + + } + } + + } + + if($Con1.count -gt 1) + { + $Script:Alt = $Script:Alt + 250 + } + } + + } + + Function vWan { + Param($wan1) + + if([string]::IsNullOrEmpty($Script:vnetLoc)) + { + $Script:vnetLoc = 700 + } + + $Name2 = $wan1.Name + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', [string]$Name2) + $Script:XmlWriter.WriteAttributeString('allow_VnetToVnet_Traffic', [string]$wan1.properties.allowVnetToVnetTraffic) + $Script:XmlWriter.WriteAttributeString('allow_BranchToBranch_Traffic', [string]$wan1.properties.allowBranchToBranchTraffic) + $Script:Source = ($Script:CellID+'-'+($Script:IDNum-1)) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVWAN 250 $Script:Alt "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + Connect $Script:Source $Script:Target + + $Script:Source1 = $Script:Target + + foreach ($Con2 in $wan1.properties.virtualHubs.id) + { + $VHUB = $AZVHUB | Where-Object {$_.id -eq $Con2} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ("`n" +[string]$VHUB.Name)) + $Script:XmlWriter.WriteAttributeString('Address_Prefix', [string]$VHUB.properties.addressPrefix) + $Script:XmlWriter.WriteAttributeString('Preferred_Routing_Gateway', [string]$VHUB.properties.preferredRoutingGateway) + $Script:XmlWriter.WriteAttributeString('Virtual_Router_Asn', [string]$VHUB.properties.virtualRouterAsn) + $Script:XmlWriter.WriteAttributeString('Allow_BranchToBranch_Traffic', [string]$VHUB.properties.allowBranchToBranchTraffic) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVWAN 425 $Script:Alt "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + Connect $Script:Source1 $Script:Target + + $Script:Source = $Script:Target + + foreach($AZVNETs2 in $AZVNETs) + { + foreach($VNETTEMP in $AZVNETs2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) + { + $VV4 = $VNETTEMP.Split("/") + $VNETTEMP1 = $VV4[8] + if($VNETTEMP1 -like ('HV_'+$VHUB.name+'_*')) + { + $Script:VNET2 = $AZVNETs2 + + $Script:Alt0 = $Script:Alt + if($VNET2.id -notin $VNETHistory.vnet) + { + if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) + { + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' + }Else{ + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) + if($VNET2.properties.dhcpoptions.dnsServers) + { + $Script:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + else + { + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVNET 600 $Script:Alt "65" "39" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:VNETDrawID = ($Script:CellID+'-'+($Script:IDNum-1)) + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + Connect $Script:Source $Script:Target + + if($VNET2.properties.enableDdosProtection -eq $true) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDDOS 580 ($Script:Alt + 15) "23" "28" 1 + + $Script:XmlWriter.WriteEndElement() + } + + VNETCreator $Script:VNET2 + + if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id -and $VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id -notlike ('*/HV_'+$VHUB.name+'_*')) + { + PeerCreator $Script:VNET2 + } + + $tmp =@{ + 'VNETid' = $Script:VNETDrawID; + 'VNET' = $AZVNETs2.id + } + $Script:VNETHistory += $tmp + + } + else + { + $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $AZVNETs2.id} + + Connect $Script:Source $VNETDID.VNETid + } + } + } + } + + if($Con1.count -gt 1) + { + $Script:Alt = $Script:Alt + 250 + } + } + + } + + <# Function for Cloud Only Environments #> + Function CloudOnly { + $Script:RoutsW = $AZVNETs | Select-Object -Property Name, @{N="Subnets";E={$_.properties.subnets.properties.addressPrefix.count}} | Sort-Object -Property Subnets -Descending + + $Script:VNETHistory = @() + if([string]::IsNullOrEmpty($Script:vnetLoc)) + { + $Script:vnetLoc = 700 + } + $Script:Alt = 2 + + foreach($AZVNETs2 in $AZVNETs) + { + $Script:VNET2 = $AZVNETs2 + + $Script:Alt0 = $Script:Alt + if($VNET2.id -notin $VNETHistory.vnet) + { + + if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) + { + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' + }Else{ + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) + if($VNET2.properties.dhcpoptions.dnsServers) + { + $Script:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + else + { + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVNET 600 $Script:Alt "65" "39" 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:VNETDrawID = ($Script:CellID+'-'+($Script:IDNum-1)) + + $Script:Target = ($Script:CellID+'-'+($Script:IDNum-1)) + + if($VNET2.properties.enableDdosProtection -eq $true) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDDOS 580 ($Script:Alt + 15) "23" "28" 1 + + $Script:XmlWriter.WriteEndElement() + } + + $Script:Source = $Script:Target + + VNETCreator $Script:VNET2 + + if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) + { + PeerCreator $Script:VNET2 + } + + $tmp =@{ + 'VNETid' = $Script:VNETDrawID; + 'VNET' = $AZVNETs2.id + } + $Script:VNETHistory += $tmp + + } + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Ret -520 -100 "500" ($Script:Alt + 100) 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ('Cloud Only'+ "`n" +'Environment')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Script:CloudOnly -460 (($Script:Alt + 100)/2) "380" "275" 1 + + $Script:XmlWriter.WriteEndElement() + + label + + Icon $Signature -520 ($Script:Alt + 100) "27.5" "22" 1 + + $Script:XmlWriter.WriteEndElement() + + } + + Function FullEnvironment { + foreach($AZVNETs2 in $AZVNETs) + { + $Script:VNET2 = $AZVNETs2 + + if($VNET2.id -notin $VNETHistory.vnet) + { + if($VNET2.properties.addressSpace.addressPrefixes.count -ge 10) + { + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' + }Else{ + $AddSpace = ($VNET2.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$VNET2.Name + "`n" + $AddSpace)) + if($VNET2.properties.dhcpoptions.dnsServers) + { + $Script:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNET2.properties.dhcpoptions.dnsServers) + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + else + { + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNET2.properties.enableDdosProtection) + } + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVNET 600 $Script:Alt "65" "39" 1 + + $Script:XmlWriter.WriteEndElement() + + VNETCreator $Script:VNET2 + + if($VNET2.properties.virtualNetworkPeerings.properties.remoteVirtualNetwork.id) + { + PeerCreator $Script:VNET2 + } + } + + $Script:Alt = $Script:Alt + 250 + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Ret -520 -100 "500" ($Script:Alt + 100) 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ('On Premises'+ "`n" +'Environment')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $OnPrem -351 (($Script:Alt + 100)/2) "168.2" "290" 1 + + $Script:XmlWriter.WriteEndElement() + + label + + Icon $Signature -520 ($Script:Alt + 100) "27.5" "22" 1 + + $Script:XmlWriter.WriteEndElement() + + } + + <# Function for VNET creation #> + Function VNETCreator { + Param($VNET2) + $Script:sizeL = $VNET2.properties.subnets.properties.addressPrefix.count + + [System.GC]::GetTotalMemory($true) | out-null + + if($VNET2.id -notin $VNETHistory.vnet) + { + if ($Script:sizeL -gt 5) + { + $Script:sizeL = $Script:sizeL / 2 + $Script:sizeL = [math]::ceiling($Script:sizeL) + $Script:sizeC = $Script:sizeL + $Script:sizeL = (($Script:sizeL * 210) + 30) + + if('gatewaysubnet' -in $VNET2.properties.subnets.name) + { + HubContainer ($Script:vnetLoc) ($Script:Alt0 - 20) $Script:sizeL "490" $VNET2.Name + } + else + { + VNETContainer ($Script:vnetLoc) ($Script:Alt0 - 20) $Script:sizeL "490" $VNET2.Name + } + + + + $Script:VNETSquare = ($Script:CellID+'-'+($Script:IDNum-1)) + + $SubName = $Subscriptions | Where-Object {$_.id -eq $VNET2.subscriptionId} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $SubName.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconSubscription $Script:sizeL 460 "67" "40" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $ADVS = '' + $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} + If($ADVS) + { + $Count = 1 + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + foreach ($ADV in $ADVS) + { + $Attr1 = ('Recommendation'+[string]$Count) + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconCostMGMT ($Script:sizeL + 150) 460 "30" "35" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + } + + Subnet ($Script:vnetLoc + 15) $VNET2 $Script:IDNum $Script:DiagramCache $Script:ContID + + if($Script:VNETPIP) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $Count = 1 + Foreach ($PIPDetail in $Script:VNETPIP) + { + $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) + $Script:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDet ($Script:sizeL + 500) 225 "42.63" "44" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + Connect ($Script:CellID+'-'+($Script:IDNum-1)) $Script:ContID $Script:ContID + } + + $Script:Alt = $Script:Alt + 650 + } + else + { + $Script:sizeL = (($Script:sizeL * 210) + 30) + + if('gatewaysubnet' -in $VNET2.properties.subnets.name) + { + HubContainer ($Script:vnetLoc) ($Script:Alt0 - 15) $Script:sizeL "260" $VNET2.Name + } + else + { + VNETContainer ($Script:vnetLoc) ($Script:Alt0 - 15) $Script:sizeL "260" $VNET2.Name + } + + + $Script:VNETSquare = ($Script:CellID+'-'+($Script:IDNum-1)) + + $SubName = $Subscriptions | Where-Object {$_.id -eq $VNET2.subscriptionId} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $SubName.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconSubscription $Script:sizeL 225 "67" "40" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $ADVS = '' + $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} + If($ADVS) + { + $Count = 1 + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + foreach ($ADV in $ADVS) + { + $Attr1 = ('Recommendation'+[string]$Count) + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconCostMGMT ($Script:sizeL + 150) 225 "30" "35" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + } + + Subnet ($Script:vnetLoc + 15) $VNET2 $Script:IDNum $Script:DiagramCache $Script:ContID + + if($Script:VNETPIP) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $Count = 1 + Foreach ($PIPDetail in $Script:VNETPIP) + { + $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) + $Script:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDet ($Script:sizeL + 500) 107 "42.63" "44" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + Connect ($Script:CellID+'-'+($Script:IDNum-1)) $Script:ContID $Script:ContID + } + $Script:Alt = $Script:Alt + 350 + } + } + + [System.GC]::GetTotalMemory($true) | out-null + } + + <# Function for create peered VNETs #> + Function PeerCreator { + Param($VNET2) + + $Script:vnetLoc1 = $Script:Alt + + Foreach ($Peer in $VNET2.properties.virtualNetworkPeerings) + { + $VNETSUB = $AZVNETs | Where-Object {$_.id -eq $Peer.properties.remoteVirtualNetwork.id} + + if($VNETSUB.id -in $VNETHistory.VNET) + { + $VNETDID = $VNETHistory | Where-Object {$_.VNET -eq $VNETSUB.id} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Peering_Name', $Peer.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") + $Script:XmlWriter.WriteAttributeString('edge', "1") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + $Script:XmlWriter.WriteAttributeString('source', $Script:VNETDrawID) + $Script:XmlWriter.WriteAttributeString('target', $VNETDID.VNETid) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('relative', "1") + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + else + { + $Script:sizeL = $VNETSUB.properties.subnets.properties.addressPrefix.count + $BrokenVNET = if($VNETSUB.properties.subnets.properties.addressPrefix.count){'Not Broken'}else{'Broken'} + + if($VNETSUB.properties.addressSpace.addressPrefixes.count -ge 10) + { + $AddSpace = ($VNETSUB.properties.addressSpace.addressPrefixes | Select-Object -First 20 | ForEach-Object {$_ + "`n"} ) + "`n" +'...' + }Else{ + $AddSpace = ($VNETSUB.properties.addressSpace.addressPrefixes | ForEach-Object {$_ + "`n"}) + } + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ($VNETSUB.name + "`n" + $AddSpace)) + if($VNETSUB.properties.dhcpoptions.dnsServers) + { + $Script:XmlWriter.WriteAttributeString('Custom_DNS_Servers', [string]$VNETSUB.properties.dhcpoptions.dnsServers) + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNETSUB.properties.enableDdosProtection) + } + else + { + $Script:XmlWriter.WriteAttributeString('DDOS_Protection', [string]$VNETSUB.properties.enableDdosProtection) + } + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVNET $Script:vnetLoc $Script:vnetLoc1 "67" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + + $TwoTarget = ($Script:CellID+'-'+($Script:IDNum-1)) + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('Peering_Name', $Peer.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") + $Script:XmlWriter.WriteAttributeString('edge', "1") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + $Script:XmlWriter.WriteAttributeString('source', $Script:Source) + $Script:XmlWriter.WriteAttributeString('target', $TwoTarget) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('relative', "1") + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + + if($VNETSUB.properties.enableDdosProtection -eq $true) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDDOS ($Script:vnetLoc - 20) ($Script:vnetLoc1 + 15) "23" "28" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + if ($Script:sizeL -gt 5) + { + $Script:sizeL = $Script:sizeL / 2 + $Script:sizeL = [math]::ceiling($Script:sizeL) + $Script:sizeC = $Script:sizeL + $Script:sizeL = (($Script:sizeL * 210) + 30) + + if('gatewaysubnet' -in $VNETSUB.properties.subnets.name) + { + HubContainer ($Script:vnetLoc + 100) ($Script:vnetLoc1 - 20) $Script:sizeL "490" $VNETSUB.name + } + else + { + VNETContainer ($Script:vnetLoc + 100) ($Script:vnetLoc1 - 20) $Script:sizeL "490" $VNETSUB.name + } + + $Script:VNETSquare = ($Script:CellID+'-'+($Script:IDNum-1)) + + $SubName = $Subscriptions | Where-Object {$_.id -eq $VNETSUB.subscriptionId} + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $SubName.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconSubscription $Script:sizeL 460 "67" "40" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $ADVS = '' + $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} + If($ADVS) + { + $Count = 1 + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + foreach ($ADV in $ADVS) + { + $Attr1 = ('Recommendation'+[string]$Count) + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconCostMGMT ($Script:sizeL + 150) 460 "30" "35" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + } + + Subnet ($Script:vnetLoc + 120) $VNETSUB $Script:IDNum $Script:DiagramCache $Script:ContID + + $Script:vnetLoc1 = $Script:vnetLoc1 + 230 + + if($Script:VNETPIP) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $Count = 1 + Foreach ($PIPDetail in $Script:VNETPIP) + { + $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) + $Script:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDet ($Script:sizeL + 500) 225 "42.63" "44" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + Connect ($Script:CellID+'-'+($Script:IDNum-1)) $Script:ContID $Script:ContID + } + + $Script:Alt = $Script:Alt + 650 + } + else + { + $Script:sizeL = (($Script:sizeL * 210) + 30) + + if($BrokenVNET -eq 'Not Broken') + { + if('gatewaysubnet' -in $VNETSUB.properties.subnets.name) + { + HubContainer ($Script:vnetLoc + 100) ($Script:vnetLoc1 - 20) $Script:sizeL "260" $VNETSUB.name + } + else + { + VNETContainer ($Script:vnetLoc + 100) ($Script:vnetLoc1 - 20) $Script:sizeL "260" $VNETSUB.name + } + } + else + { + BrokenContainer ($Script:vnetLoc + 100) ($Script:vnetLoc1 - 20) "250" "260" 'Broken Peering' + $Script:sizeL = '250' + } + + $Script:VNETSquare = ($Script:CellID+'-'+($Script:IDNum-1)) + + $SubName = $Subscriptions | Where-Object {$_.id -eq $VNETSUB.subscriptionId} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $SubName.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconSubscription $Script:sizeL 225 "67" "40" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $ADVS = '' + $ADVS = $Advisories | Where-Object {$_.Properties.Category -eq 'Cost' -and $_.Properties.resourceMetadata.resourceId -eq ('/subscriptions/'+$SubName.id)} + If($ADVS) + { + $Count = 1 + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + foreach ($ADV in $ADVS) + { + $Attr1 = ('Recommendation'+[string]$Count) + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$ADV.Properties.shortDescription.solution) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconCostMGMT ($Script:sizeL + 150) 225 "30" "35" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + } + + Subnet ($Script:vnetLoc + 120) $VNETSUB $Script:IDNum $Script:DiagramCache $Script:ContID + + if($Script:VNETPIP) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $Count = 1 + Foreach ($PIPDetail in $Script:VNETPIP) + { + $Attr1 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('PublicIP-'+[string]("{0:d3}" -f $Count)+'-IP') + $Script:XmlWriter.WriteAttributeString($Attr1, [string]$PIPDetail.name) + $Script:XmlWriter.WriteAttributeString($Attr2, [string]$PIPDetail.properties.ipaddress) + + $Count ++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconDet ($Script:sizeL+ 500) 107 "42.63" "44" $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + Connect ($Script:CellID+'-'+($Script:IDNum-1)) $Script:ContID $Script:ContID + + } + + } + + $tmp =@{ + 'VNETid' = $TwoTarget; + 'VNET' = $VNETSUB.id + } + $Script:VNETHistory += $tmp + + $Script:vnetLoc1 = $Script:vnetLoc1 + 350 + } + } + $Script:Alt = $Script:vnetLoc1 + } + + Function Subnet { + Param($subloc,$VNET,$IDNum,$DiagramCache,$ContID) + + $NameString = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + New-Variable -Name ('Run_'+$NameString) -Scope Global + + Set-Variable -name ('Run_'+$NameString) -Value ([PowerShell]::Create()).AddScript({param($subloc,$VNET,$IDNum,$DiagramCache,$ContID,$Resources) + + $etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $IDNum++ + + $SubFile = ($DiagramCache+$CellID+'.xml') + + ###################################################### STENCILS #################################################### + + Function Stensils { + $Script:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" + + $Script:IconConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" + $Script:IconExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" + $Script:IconVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" + $Script:IconVGW2 = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" + $Script:IconVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" + $Script:IconTraffic = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Local_Network_Gateways.svg;" #width="68" height="68" + $Script:IconNIC = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;" #width="68" height="60" + $Script:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" + $Script:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" + $Script:IconNSG = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Network_Security_Groups.svg;" # width="26.35" height="32" + $Script:IconUDR = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Route_Tables.svg;" #width="30.97" height="30" + $Script:IconDDOS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;" # width="23" height="28" + $Script:IconPIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" + $Script:IconNAT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/NAT.svg;" # width="65" height="52" + + <########################## Azure Generic Stencils #############################> + + $Script:SymError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="50" height="50" + $Script:SymInfo = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Information.svg;" #width="64" height="64" + $Script:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" + $Script:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" + $Script:IconBastions = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/general/Launch_Portal.svg;" #width="68" height="67" + $Script:IconContain = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Container_Instances.svg;" #width="64" height="68" + $Script:IconVWAN = "aspect=fixed;html=1;points=[];align=center;image;fontSize=18;image=img/lib/azure2/networking/Virtual_WANs.svg;" #width="65" height="64" + $Script:IconCostMGMT = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/general/Cost_Analysis.svg;" #width="60" height="70" + + <########################## Azure Computing Stencils #############################> + + $Script:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" + $Script:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" + $Script:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" + $Script:IconARO = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/mscae/OpenShift.svg;" #width="50" height="46" + $Script:IconFunApps = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Function_Apps.svg;" # width="68" height="60" + + <########################## Azure Service Stencils #############################> + + $Script:IconAPIMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/app_services/API_Management_Services.svg;" #width="65" height="60" + $Script:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" + + <########################## Azure Storage Stencils #############################> + + $Script:IconNetApp = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;" #width="65" height="52" + + <########################## Azure Storage Stencils #############################> + + $Script:IconDataExplorer = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;" #width="68" height="68" + + <########################## Other Stencils #############################> + + $Script:IconFWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;" #width="71" height="60" + $Script:IconDet = "aspect=fixed;html=1;points=[];align=center;image;fontSize=12;image=img/lib/azure2/other/Detonation.svg;" #width="42.63" height="44" + $Script:IconAppGWs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;" #width="64" height="64" + $Script:IconBricks = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;" #width="60" height="68" + $Script:IconError = "sketch=0;aspect=fixed;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;shape=mxgraph.mscae.enterprise.not_allowed;fillColor=#EA1C24;" #width="30" height="30" + $Script:OnPrem = "sketch=0;aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/mscae/Exchange_On_premises_Access.svg;" #width="168.2" height="290" + $Script:Signature = "aspect=fixed;html=1;points=[];align=left;image;fontSize=22;image=img/lib/azure2/general/Dev_Console.svg;" #width="27.5" height="22" + $Script:CloudOnly = "aspect=fixed;html=1;points=[];align=center;image;fontSize=56;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;" #width="380.77" height="275" + + } + + ####################################################### PROCTYPE #################################################### + + + Function ProcType { + Param($sub,$subloc,$Alt0,$ContainerID) + + $temp = '' + remove-variable TrueTemp -ErrorAction SilentlyContinue + remove-variable RESNames -ErrorAction SilentlyContinue + + <####################################################### FIND THE RESOURCES IN THE SUBNET ###################################################################> + + if($sub.properties.resourceNavigationLinks.properties.linkedResourceType -eq 'Microsoft.ApiManagement/service') + { + $TrueTemp = 'APIM' + } + if($sub.properties.serviceAssociationLinks.properties.link -and $null -eq $TrueTemp) + { + if($sub.properties.serviceAssociationLinks.properties.link.split("/")[6] -eq 'Microsoft.Web') + { + $TrueTemp = 'App Service' + } + } + if($sub.properties.applicationGatewayIPConfigurations.id -and $null -eq $TrueTemp) + { + if($sub.properties.applicationGatewayIPConfigurations.id.split("/")[7] -eq 'applicationGateways') + { + $TrueTemp = 'applicationGateways' + } + } + if($sub.properties.ipconfigurations.id.count -eq 1 -and $null -eq $TrueTemp) + { + if($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'virtualNetworkGateways') + { + $TrueTemp = 'virtualNetworkGateways' + } + elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'loadBalancers') + { + $TrueTemp = 'loadBalancers' + } + elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'applicationGateways') + { + $TrueTemp = 'applicationGateways' + } + elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'bastionHosts') + { + $TrueTemp = 'bastionHosts' + } + elseif($sub.properties.ipconfigurations.id.Split("/")[7] -eq 'azureFirewalls') + { + $TrueTemp = 'azureFirewalls' + } + } + if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Databricks/workspaces' -and $null -eq $TrueTemp) + { + $TrueTemp = 'DataBricks' + } + if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Web/serverfarms' -and $null -eq $TrueTemp) + { + $TrueTemp = 'App Service' + } + if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.ContainerInstance/containerGroups' -and $null -eq $TrueTemp) + { + $TrueTemp = 'Container Instance' + } + if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Netapp/volumes' -and $null -eq $TrueTemp) + { + $TrueTemp = 'NetApp' + } + if($sub.properties.delegations.properties.serviceName -eq 'Microsoft.Kusto/clusters' -and $null -eq $TrueTemp) + { + $TrueTemp = 'Data Explorer Clusters' + } + + if([string]::IsNullOrEmpty($TrueTemp)) + { + $AKS = $Script:AKS + if($sub.id -in $AKS.properties.agentPoolProfiles.vnetSubnetID) + { + $TrueTemp = 'AKS' + } + } + if([string]::IsNullOrEmpty($TrueTemp)) + { + $Types = @() + + Foreach($type in $sub.properties.ipconfigurations.id) + { + if($type.Split("/")[8] -like 'aks-*') + { + $Types += 'AKS' + } + if($type.Split("/")[8] -like 'gwhost*') + { + $Types += 'APIM' + } + else + { + $Types += $type.Split("/")[7] + } + } + $temp = $Types | Group-Object | Sort-Object -Property Count -Descending + if($temp) + { + $TrueTemp = $temp[0].name + } + } + + if([string]::IsNullOrEmpty($TrueTemp)) + { + if ($sub.id -in ($Script:VMSS).properties.virtualMachineProfile.networkprofile.networkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id) + { + $TrueTemp = 'virtualMachineScaleSets' + } + } + + <#################################################### FIND RESOURCE NAME AND DETAILS #################################################################> + + if($TrueTemp -eq 'networkInterfaces') + { + $NIcNames = $Script:NIC | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id} + + if($sub.properties.privateEndpoints.id) + { + $PrivEndNames = $Script:PrivEnd | Where-Object {$_.properties.networkInterfaces.id -in $NIcNames.id} + $TrueTemp = 'privateLinkServices' + $RESNames = $PrivEndNames + } + else + { + $VMNamesAro = $Script:VM | Where-Object {$_.properties.networkprofile.networkInterfaces.id -in $NIcNames.id} + if($VMNamesAro.properties.storageprofile.imageReference.offer -like 'aro*') + { + $ARONames = $Script:ARO | Where-Object {$_.properties.masterprofile.subnetId -eq $sub.id -or $_.properties.workerProfiles.subnetId -eq $sub.id} + $TrueTemp = 'Open Shift' + $RESNames = $ARONames + } + if($TrueTemp -ne 'Open Shift') + { + $VMs = @() + $VMNames = ($Script:VM).properties.networkprofile.networkInterfaces.id | Where-Object {$_ -in $NIcNames.id} + $VMs = foreach($NIC in $VMNames) + { + $Script:VM| Where-Object {$NIC -in $_.properties.networkprofile.networkInterfaces.id} + } + if($VMs) + { + $TrueTemp = 'Virtual Machine' + $RESNames = $VMs + } + } + if($TrueTemp -eq 'networkInterfaces') + { + $TrueTemp = 'Network Interface' + $RESNames = $NIcNames + } + } + } + if($TrueTemp -eq 'AKS') + { + $AKSNames = $Script:AKS | Where-Object {$_.properties.agentPoolProfiles.vnetSubnetID -eq $sub.id} + $RESNames = $AKSNames + } + if($TrueTemp -eq 'Data Explorer Clusters') + { + $KustoNames = $Script:Kusto | Where-Object {$_.properties.virtualNetworkConfiguration.subnetid -eq $sub.id} + $RESNames = $KustoNames + } + if($TrueTemp -eq 'applicationGateways') + { + $AppGTWNames = $Script:AppGtw| Where-Object {$_.properties.gatewayIPConfigurations.id -in $sub.properties.applicationGatewayIPConfigurations.id} + $RESNames = $AppGTWNames + } + if($TrueTemp -eq 'DataBricks') + { + $DatabriksNames = @() + $Databricks = $Script:Databricks + $DatabriksNames = Foreach($Data in $Databricks) + { + if($Data.properties.parameters.customVirtualNetworkId.value+'/subnets/'+$Data.properties.parameters.customPrivateSubnetName.value -eq $sub.id -or $Data.properties.parameters.customVirtualNetworkId.value+'/subnets/'+$Data.properties.parameters.custompublicSubnetName.value -eq $sub.id) + { + $Data + } + } + $RESNames = $DatabriksNames + } + if($TrueTemp -eq 'App Service') + { + $Apps = $Script:AppWeb | Where-Object {$_.properties.virtualNetworkSubnetId -eq $Sub.id} + if($Apps.kind -like 'functionapp*') + { + $FuntionAppNames = $Apps + $TrueTemp = 'Function App' + $RESNames = $FuntionAppNames + } + else + { + $ServiceAppNames = $Apps + $RESNames = $Apps + } + } + if($TrueTemp -eq 'APIM') + { + $APIMNames = $Script:APIM | Where-Object {$_.properties.virtualNetworkConfiguration.subnetResourceId -eq $sub.id} + $RESNames = $APIMNames + } + if($TrueTemp -eq 'loadBalancers') + { + $LBNames = $Script:LB | Where-Object {$_.properties.frontendIPConfigurations.id -in $sub.properties.ipconfigurations.id} + $RESNames = $LBNames + } + if($TrueTemp -eq 'virtualMachineScaleSets') + { + $VMSSNames = $Script:VMSS | Where-Object {$_.properties.virtualMachineProfile.networkProfile.networkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id -eq $sub.id } + $RESNames = $VMSSNames + } + if($TrueTemp -eq 'virtualNetworkGateways') + { + $VPNGTWNames = $Script:AZVGWs | Where-Object {$_.properties.ipconfigurations.properties.subnet.id -eq $sub.id } + $RESNames = $VPNGTWNames + } + if($TrueTemp -eq 'bastionHosts') + { + $BastionNames = $Script:Bastion | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id } + $RESNames = $BastionNames + } + if($TrueTemp -eq 'azureFirewalls') + { + $AzFWNames = $Script:FW | Where-Object {$_.properties.ipConfigurations.properties.subnet.id -eq $sub.id } + $RESNames = $AzFWNames + } + if($TrueTemp -eq 'Container Instance') + { + $ContainerNames = '' + $ContNICs = $Script:NetProf | Where-Object {$_.properties.containerNetworkInterfaceConfigurations.properties.ipconfigurations.properties.subnet.id -eq $sub.id} + $ContainerNames = $Script:Container | Where-Object {$_.properties.networkprofile.id -in $ContNICs.id} + $RESNames = $ContainerNames + if([string]::IsNullOrEmpty($ContainerNames)) + { + $ARONames = $Script:ARO | Where-Object {$_.properties.masterprofile.subnetId -eq $sub.id -or $_.properties.workerProfiles.subnetId -eq $sub.id} + $TrueTemp = 'Open Shift' + $RESNames = $ARONames + } + } + if($TrueTemp -eq 'NetApp') + { + $NetAppNames = $Script:ANF | Where-Object {$_.properties.subnetId -eq $sub.id } + $RESNames = $NetAppNames + } + + <###################################################### DROP THE ICONS ######################################################> + + switch ($TrueTemp) + { + 'Virtual Machine' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' VMs')) + + $Count = 1 + foreach ($VMName in $RESNames.Name) + { + $Attr1 = ('VirtualMachine-'+[string]("{0:d3}" -f $Count)) + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$VMName) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVMs ($subloc+64) ($Alt0+40) "69" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + $Script:XmlTempWriter.WriteAttributeString('VM_Size', [string]$RESNames.properties.hardwareProfile.vmSize) + $Script:XmlTempWriter.WriteAttributeString('OS', [string]$RESNames.properties.storageProfile.osDisk.osType) + $Script:XmlTempWriter.WriteAttributeString('OS_Disk_Size_GB', [string]$RESNames.properties.storageProfile.osDisk.diskSizeGB) + $Script:XmlTempWriter.WriteAttributeString('Image_Publisher', [string]$RESNames.properties.storageProfile.imageReference.publisher) + $Script:XmlTempWriter.WriteAttributeString('Image_SKU', [string]$RESNames.properties.storageProfile.imageReference.sku) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVMs ($subloc+64) ($Alt0+40) "69" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + 'AKS' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' AKS Clusters')) + + $Count = 1 + foreach ($AKSName in $RESNames.Name) + { + $Attr1 = ('Kubernetes_Cluster-'+[string]("{0:d3}" -f $Count)) + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$AKSName) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAKS ($subloc+65) ($Alt0+40) "68" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) + + $Count = 1 + foreach($Pool in $RESNames.properties.agentPoolProfiles) + { + $Attr1 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Count') + $Attr3 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Size') + $Attr4 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Version') + $Attr5 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Mode') + $Attr6 = ('Node_Pool-'+[string]("{0:d3}" -f $Count)+'-Max_Pods') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$Pool.name) + $Script:XmlTempWriter.WriteAttributeString($Attr2, [string]($Pool | Select-Object -Property 'count').count) + $Script:XmlTempWriter.WriteAttributeString($Attr3, [string]$Pool.vmSize) + $Script:XmlTempWriter.WriteAttributeString($Attr4, [string]$Pool.orchestratorVersion) + $Script:XmlTempWriter.WriteAttributeString($Attr5, [string]$Pool.mode) + $Script:XmlTempWriter.WriteAttributeString($Attr6, [string]$Pool.maxPods) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAKS ($subloc+65) ($Alt0+40) "68" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + 'virtualMachineScaleSets' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Virtual Machine Scale Sets')) + + $Count = 1 + foreach ($ResName in $RESNames.Name) + { + $Attr1 = ('VMSS-'+[string]("{0:d3}" -f $Count)) + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVMSS ($subloc+65) ($Alt0+40) "68" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) + + $Script:XmlTempWriter.WriteAttributeString('VMSS_Name', [string]$RESNames.name) + $Script:XmlTempWriter.WriteAttributeString('Instances', [string]$temp[0].Count) + $Script:XmlTempWriter.WriteAttributeString('VMSS_SKU_Tier', [string]$RESNames.sku.tier) + $Script:XmlTempWriter.WriteAttributeString('VMSS_Upgrade_Policy', [string]$RESNames.Properties.upgradePolicy.mode) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVMSS ($subloc+65) ($Alt0+40) "68" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'loadBalancers' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Load Balancers')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('LB-'+[string]("{0:d3}" -f $Count)+'-SKU') + $Attr3 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Backends') + $Attr4 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Frontends') + $Attr5 = ('LB-'+[string]("{0:d3}" -f $Count)+'-LB_Rules') + $Attr6 = ('LB-'+[string]("{0:d3}" -f $Count)+'-Probes') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + $Script:XmlTempWriter.WriteAttributeString($Attr2, [string]$ResName.sku.name) + $Script:XmlTempWriter.WriteAttributeString($Attr3, [string]$ResName.properties.backendAddressPools.properties.backendIPConfigurations.id.count) + $Script:XmlTempWriter.WriteAttributeString($Attr4, [string]$ResName.properties.frontendIPConfigurations.properties.count) + $Script:XmlTempWriter.WriteAttributeString($Attr5, [string]$ResName.properties.loadBalancingRules.count) + $Script:XmlTempWriter.WriteAttributeString($Attr6, [string]$ResName.properties.probes.count) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconLBs ($subloc+65) ($Alt0+40) "72" "72" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $Script:XmlTempWriter.WriteAttributeString('Load_Balancer_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Load_Balancer_SKU', [string]$ResNames.sku.name) + $Script:XmlTempWriter.WriteAttributeString('Backends', [string]$ResNames.properties.backendAddressPools.properties.backendIPConfigurations.id.count) + $Script:XmlTempWriter.WriteAttributeString('Frontends', [string]$ResNames.properties.frontendIPConfigurations.properties.count) + $Script:XmlTempWriter.WriteAttributeString('LB_Rules', [string]$ResNames.properties.loadBalancingRules.count) + $Script:XmlTempWriter.WriteAttributeString('Probes', [string]$ResNames.properties.probes.count) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconLBs ($subloc+65) ($Alt0+40) "72" "72" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + 'virtualNetworkGateways' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Virtual Network Gateways')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Network_Gateway-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVGW ($subloc+80) ($Alt0+40) "52" "69" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconVGW ($subloc+80) ($Alt0+40) "52" "69" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'azureFirewalls' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Firewalls')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-SKU') + $Attr3 = ('Firewall-'+[string]("{0:d3}" -f $Count)+'-Threat_Intel_Mode') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + $Script:XmlTempWriter.WriteAttributeString($Attr2, [string]$ResName.properties.sku.tier) + $Script:XmlTempWriter.WriteAttributeString($Attr3, [string]$ResName.properties.threatIntelMode) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconFWs ($subloc+65) ($Alt0+40) "71" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) + + + $Script:XmlTempWriter.WriteAttributeString('Firewall_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('SKU_Tier', [string]$ResNames.properties.sku.tier) + $Script:XmlTempWriter.WriteAttributeString('Threat_Intel_Mode', [string]$ResNames.properties.threatIntelMode) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconFWs ($subloc+65) ($Alt0+40) "71" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'privateLinkServices' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Private Endpoints')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('PVE-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconPVTs ($subloc+65) ($Alt0+40) "72" "66" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconPVTs ($subloc+65) ($Alt0+40) "72" "66" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'applicationGateways' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Application Gateways')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Name') + $Attr2 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-SKU') + $Attr3 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Min_Capacity') + $Attr4 = ('App_Gateway-'+[string]("{0:d3}" -f $Count)+'-Max_Capacity') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + $Script:XmlTempWriter.WriteAttributeString($Attr2, [string]$RESName.Properties.sku.tier) + $Script:XmlTempWriter.WriteAttributeString($Attr3, [string]$RESName.Properties.autoscaleConfiguration.minCapacity) + $Script:XmlTempWriter.WriteAttributeString($Attr4, [string]$RESName.Properties.autoscaleConfiguration.maxCapacity) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAppGWs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $Script:XmlTempWriter.WriteAttributeString('App_Gateway_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('App_Gateway_SKU', [string]$RESNames.Properties.sku.tier) + $Script:XmlTempWriter.WriteAttributeString('Autoscale_Min_Capacity', [string]$RESNames.Properties.autoscaleConfiguration.minCapacity) + $Script:XmlTempWriter.WriteAttributeString('Autoscale_Max_Capacity', [string]$RESNames.Properties.autoscaleConfiguration.maxCapacity) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAppGWs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'bastionHosts' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Bastion Hosts')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Bastion-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconBastions ($subloc+65) ($Alt0+40) "68" "67" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.name) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconBastions ($subloc+65) ($Alt0+40) "68" "67" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + 'APIM' { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $APIMHost = [string]($RESNames.properties.hostnameConfigurations | Where-Object {$_.defaultSslBinding -eq $true}).hostname + + $Script:XmlTempWriter.WriteAttributeString('APIM_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.sku.name) + $Script:XmlTempWriter.WriteAttributeString('VNET_Type', [string]$RESNames.properties.virtualNetworkType) + $Script:XmlTempWriter.WriteAttributeString('Default_Hostname', $APIMHost) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAPIMs ($subloc+65) ($Alt0+40) "65" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + 'App Service' { + if($ServiceAppNames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' App Services')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('AppService-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAPPs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$ResNames.name) + + $Script:XmlTempWriter.WriteAttributeString('App_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Default_Hostname', [string]$RESNames.properties.defaultHostName) + $Script:XmlTempWriter.WriteAttributeString('Enabled', [string]$RESNames.properties.enabled) + $Script:XmlTempWriter.WriteAttributeString('State', [string]$RESNames.properties.state) + $Script:XmlTempWriter.WriteAttributeString('Inbound_IP_Address', [string]$RESNames.properties.inboundIpAddress) + $Script:XmlTempWriter.WriteAttributeString('Kind', [string]$RESNames.properties.kind) + $Script:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.properties.sku) + $Script:XmlTempWriter.WriteAttributeString('Workers', [string]$RESNames.properties.siteConfig.numberOfWorkers) + $Script:XmlTempWriter.WriteAttributeString('Min_Workers', [string]$RESNames.properties.siteConfig.minimumElasticInstanceCount) + $Script:XmlTempWriter.WriteAttributeString('Site_Properties', [string]$RESNames.properties.siteProperties.properties.value) + + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconAPPs ($subloc+65) ($Alt0+40) "64" "64" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + } + 'Function App' { + if($FuntionAppNames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Function Apps')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('FunctionApp-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconFunApps ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$ResNames.name) + + $Script:XmlTempWriter.WriteAttributeString('App_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Default_Hostname', [string]$RESNames.properties.defaultHostName) + $Script:XmlTempWriter.WriteAttributeString('Enabled', [string]$RESNames.properties.enabled) + $Script:XmlTempWriter.WriteAttributeString('State', [string]$RESNames.properties.state) + $Script:XmlTempWriter.WriteAttributeString('Inbound_IP_Address', [string]$RESNames.properties.inboundIpAddress) + $Script:XmlTempWriter.WriteAttributeString('Kind', [string]$RESNames.properties.kind) + $Script:XmlTempWriter.WriteAttributeString('SKU', [string]$RESNames.properties.sku) + $Script:XmlTempWriter.WriteAttributeString('Workers', [string]$RESNames.properties.siteConfig.numberOfWorkers) + $Script:XmlTempWriter.WriteAttributeString('Min_Workers', [string]$RESNames.properties.siteConfig.minimumElasticInstanceCount) + $Script:XmlTempWriter.WriteAttributeString('Site_Properties', [string]$RESNames.properties.siteProperties.properties.value) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconFunApps ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + } + 'DataBricks' { + if($DatabriksNames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Databricks')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Databrick-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconBricks ($subloc+65) ($Alt0+40) "60" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $Script:XmlTempWriter.WriteAttributeString('Databrick_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Workspace_URL', [string]$RESNames.properties.workspaceUrl ) + $Script:XmlTempWriter.WriteAttributeString('Pricing_Tier', [string]$RESNames.sku.name) + $Script:XmlTempWriter.WriteAttributeString('Storage_Account', [string]$RESNames.properties.parameters.storageAccountName.value) + $Script:XmlTempWriter.WriteAttributeString('Storage_Account_SKU', [string]$RESNames.properties.parameters.storageAccountSkuName.value) + $Script:XmlTempWriter.WriteAttributeString('Relay_Namespace', [string]$RESNames.properties.parameters.relayNamespaceName.value) + $Script:XmlTempWriter.WriteAttributeString('Require_Infrastructure_Encryption', [string]$RESNames.properties.parameters.requireInfrastructureEncryption.value) + $Script:XmlTempWriter.WriteAttributeString('Enable_Public_IP', [string]$RESNames.properties.parameters.enableNoPublicIp.value) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconBricks ($subloc+65) ($Alt0+40) "60" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + } + 'Open Shift' { + if($ARONames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' OpenShift Clusters')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('OpenShift_Cluster-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconARO ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + + $Script:XmlTempWriter.WriteAttributeString('ARO_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('OpenShift_Version', [string]$RESNames.properties.clusterProfile.version) + $Script:XmlTempWriter.WriteAttributeString('OpenShift_Console', [string]$RESNames.properties.consoleProfile.url) + $Script:XmlTempWriter.WriteAttributeString('Worker_VM_Count', [string]$RESNames.properties.workerprofiles.Count) + $Script:XmlTempWriter.WriteAttributeString('Worker_VM_Size', [string]$RESNames.properties.workerprofiles.vmSize[0]) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconARO ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + } + 'Container Instance' { + if($ContainerNames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Container Intances')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Container_Intance-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconContain ($subloc+65) ($Alt0+40) "64" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconContain ($subloc+65) ($Alt0+40) "64" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + } + 'NetApp' { + if($NetAppNames) + { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' NetApp Volumes')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('NetApp_Volume-'+[string]("{0:d3}" -f $Count)) + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconNetApp ($subloc+65) ($Alt0+40) "65" "52" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]1+' NetApp Volume')) + $Script:XmlTempWriter.WriteAttributeString('NetApp_Volume_Name', [string]$ResName.name) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconNetApp ($subloc+65) ($Alt0+40) "65" "52" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + } + 'Data Explorer Clusters' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Data Explorer Clusters')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('Data_Cluster-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconDataExplorer ($subloc+65) ($Alt0+40) "68" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', [string]$RESNames.Name) + $Script:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_Name', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_URI', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Data_Explorer_Cluster_State', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('SKU_Tier', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('Computer_Specifications', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('AutoScale_Enabled', [string]$ResNames.name) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconDataExplorer ($subloc+65) ($Alt0+40) "68" "68" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + } + 'Network Interface' { + if($RESNames.count -gt 1) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]$RESNames.Count + ' Network Interfaces')) + + $Count = 1 + foreach ($ResName in $RESNames) + { + $Attr1 = ('NIC-'+[string]("{0:d3}" -f $Count)+'-Name') + + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Count ++ + } + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconNIC ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + else + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ([string]1+' Network Interface')) + + $Attr1 = ('NIC-Name') + $Script:XmlTempWriter.WriteAttributeString($Attr1, [string]$ResName.name) + + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconNIC ($subloc+65) ($Alt0+40) "68" "60" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + } + '' {} + default {} + } + if($sub.properties.networkSecurityGroup.id) + { + $NSG = $sub.properties.networkSecurityGroup.id.split('/')[8] + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', '') + $Script:XmlTempWriter.WriteAttributeString('Network_Security_Group', [string]$NSG) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconNSG ($subloc+160) ($Alt0+15) "26.35" "32" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + } + if($sub.properties.routeTable.id) + { + $UDR = $sub.properties.routeTable.id.split('/')[8] + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', '') + $Script:XmlTempWriter.WriteAttributeString('Route_Table', [string]$UDR) + $Script:XmlTempWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon2 $IconUDR ($subloc+15) ($Alt0+15) "30.97" "30" $ContainerID + + $Script:XmlTempWriter.WriteEndElement() + + } + if($sub.properties.ipconfigurations.id) + { + Foreach($SubIPs in $sub.properties.ipconfigurations) + { + $Script:VNETPIP += $Script:CleanPIPs | Where-Object {$_.properties.ipConfiguration.id -eq $SubIPs.id} + } + } + } + + ######################################################### ICON ####################################################### + + Function Icon2 { + Param($Style,$x,$y,$w,$h,$p) + + $Script:XmlTempWriter.WriteStartElement('mxCell') + $Script:XmlTempWriter.WriteAttributeString('style', $Style) + $Script:XmlTempWriter.WriteAttributeString('vertex', "1") + $Script:XmlTempWriter.WriteAttributeString('parent', $p) + + $Script:XmlTempWriter.WriteStartElement('mxGeometry') + $Script:XmlTempWriter.WriteAttributeString('x', $x) + $Script:XmlTempWriter.WriteAttributeString('y', $y) + $Script:XmlTempWriter.WriteAttributeString('width', $w) + $Script:XmlTempWriter.WriteAttributeString('height', $h) + $Script:XmlTempWriter.WriteAttributeString('as', "geometry") + $Script:XmlTempWriter.WriteEndElement() + + $Script:XmlTempWriter.WriteEndElement() + } + + ######################################################## SUBNET ####################################################### + + Stensils + + $Script:XmlTempWriter = New-Object System.XMl.XmlTextWriter($SubFile,$Null) + + $Script:XmlTempWriter.Formatting = 'Indented' + $Script:XmlTempWriter.Indentation = 2 + + $Script:XmlTempWriter.WriteStartDocument() + + $Script:XmlTempWriter.WriteStartElement('mxfile') + $Script:XmlTempWriter.WriteAttributeString('host', 'Electron') + $Script:XmlTempWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') + $Script:XmlTempWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') + $Script:XmlTempWriter.WriteAttributeString('etag', $etag) + $Script:XmlTempWriter.WriteAttributeString('version', '15.4.0') + $Script:XmlTempWriter.WriteAttributeString('type', 'device') + + $Script:XmlTempWriter.WriteStartElement('diagram') + $Script:XmlTempWriter.WriteAttributeString('id', $DiagID) + $Script:XmlTempWriter.WriteAttributeString('name', 'Network Topology') + + $Script:XmlTempWriter.WriteStartElement('mxGraphModel') + $Script:XmlTempWriter.WriteAttributeString('dx', "1326") + $Script:XmlTempWriter.WriteAttributeString('dy', "798") + $Script:XmlTempWriter.WriteAttributeString('grid', "1") + $Script:XmlTempWriter.WriteAttributeString('gridSize', "10") + $Script:XmlTempWriter.WriteAttributeString('guides', "1") + $Script:XmlTempWriter.WriteAttributeString('tooltips', "1") + $Script:XmlTempWriter.WriteAttributeString('connect', "1") + $Script:XmlTempWriter.WriteAttributeString('arrows', "1") + $Script:XmlTempWriter.WriteAttributeString('fold', "1") + $Script:XmlTempWriter.WriteAttributeString('page', "1") + $Script:XmlTempWriter.WriteAttributeString('pageScale', "1") + $Script:XmlTempWriter.WriteAttributeString('pageWidth', "850") + $Script:XmlTempWriter.WriteAttributeString('pageHeight', "1100") + $Script:XmlTempWriter.WriteAttributeString('math', "0") + $Script:XmlTempWriter.WriteAttributeString('shadow', "0") + + $Script:XmlTempWriter.WriteStartElement('root') + + $Script:XmlTempWriter.WriteStartElement('mxCell') + $Script:XmlTempWriter.WriteAttributeString('id', "0") + $Script:XmlTempWriter.WriteEndElement() + + $Script:XmlTempWriter.WriteStartElement('mxCell') + $Script:XmlTempWriter.WriteAttributeString('id', "1") + $Script:XmlTempWriter.WriteAttributeString('parent', "0") + $Script:XmlTempWriter.WriteEndElement() + + $sizeL = $VNET.properties.subnets.properties.addressPrefix.count + if ($sizeL -gt 5) + { + $sizeL = $sizeL / 2 + $sizeL = [math]::ceiling($sizeL) + $sizeC = $sizeL + $sizeL = (($sizeL * 210) + 30) + + $subloc0 = 20 + $SubC = 0 + $alt1 = 40 + $Script:VNETPIP = @() + foreach($Sub in $VNET.properties.subnets) + { + if ($SubC -eq $sizeC) + { + $Alt1 = $Alt1 + 230 + $subloc0 = 20 + $SubC = 0 + } + + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ("`n" + "`n" + "`n" + "`n" + "`n" + "`n" +[string]$sub.Name + "`n" + [string]$sub.properties.addressPrefix)) + $Script:XmlTempWriter.WriteAttributeString('id', ($CellID+'-'+($IDNum++))) + + Icon2 "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" $subloc0 $Alt1 "200" "200" $ContID + + $Script:XmlTempWriter.WriteEndElement() + + ProcType $sub $subloc0 $Alt1 $ContID + + $subloc = $subloc + 210 + $subloc0 = $subloc0 + 210 + $SubC ++ + } + + } + Else + { + $sizeL = (($sizeL * 210) + 30) + $subloc0 = 20 + $Script:VNETPIP = @() + foreach($Sub in $VNET.properties.subnets) + { + $Script:XmlTempWriter.WriteStartElement('object') + $Script:XmlTempWriter.WriteAttributeString('label', ("`n" + "`n" + "`n" + "`n" + "`n" + "`n" +[string]$sub.Name + "`n" + [string]$sub.properties.addressPrefix)) + $Script:XmlTempWriter.WriteAttributeString('id', ($CellID+'-'+($IDNum++))) + + Icon2 "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" $subloc0 40 "200" "200" $ContID + + $Script:XmlTempWriter.WriteEndElement() + + ProcType $sub $subloc0 40 $ContID + + $subloc = $subloc + 210 + $subloc0 = $subloc0 + 210 + } + } + + $Script:XmlTempWriter.WriteEndElement() + + $Script:XmlTempWriter.WriteEndElement() + + $Script:XmlTempWriter.WriteEndElement() + $Script:XmlTempWriter.WriteEndElement() + + $Script:XmlTempWriter.WriteEndDocument() + $Script:XmlTempWriter.Flush() + $Script:XmlTempWriter.Close() + + }).AddArgument($subloc).AddArgument($VNET).AddArgument($IDNum).AddArgument($DiagramCache).AddArgument($ContID).AddArgument($Resources) + + New-Variable -Name ('Job_'+$NameString) -Scope Global + + Set-Variable -Name ('Job_'+$NameString) -Value ((get-variable -name ('Run_'+$NameString)).Value).BeginInvoke() + + $Script:jobs2 += (get-variable -name ('Job_'+$NameString)).Value + + $Script:jobs += $NameString + + #New-Variable -Name ('End_'+$NameString) + #Set-Variable -Name ('End_'+$NameString) -Value (((get-variable -name ('Run_'+$NameString)).Value).EndInvoke((get-variable -name ('Job_'+$NameString)).Value)) + + #((get-variable -name ('Run_'+$NameString)).Value).Dispose() + + #while ($Job.Runspace.IsCompleted -contains $false) {} + + KillJobs + + } + + Function KillJobs { + + foreach($job in $Script:jobs) + { + if((get-variable -name ('Job_'+$job) -Scope Global).Value.IsCompleted -eq $true) + { + #((get-variable -name ('Run_'+$job)).Value).EndInvoke((get-variable -name ('Job_'+$job)).Value) + ((get-variable -name ('Run_'+$job)).Value).Dispose() + Remove-Variable -Name ('Run_'+$job) -Scope Global -Force + Remove-Variable -Name ('Job_'+$job) -Scope Global -Force + } + } + } + + <# Function to create the Label of Version #> + Function label { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ('Powered by:'+ "`n" +'Azure Resource Inventory v3.0'+ "`n" +'https://github.com/microsoft/ARI')) + $Script:XmlWriter.WriteAttributeString('author', 'Claudio Merola') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + } + + Function Icon { + Param($Style,$x,$y,$w,$h,$p) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', $Style) + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Container { + Param($x,$y,$w,$h,$title) + $Script:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Connect { + Param($Source,$Target,$Parent) + + if($Parent){$Parent = $Parent}else{$Parent = 1} + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + $Script:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") + $Script:XmlWriter.WriteAttributeString('edge', "1") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $Parent) + $Script:XmlWriter.WriteAttributeString('source', $Source) + $Script:XmlWriter.WriteAttributeString('target', $Target) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('relative', "1") + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + } + + Function Variables0 { + Start-Job -Name 'DiagramVariables' -ScriptBlock { + $job = @() + + $AZVGWs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualnetworkgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZLGWs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/localnetworkgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVNETs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualnetworks'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZCONs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/connections'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZEXPROUTEs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/expressroutecircuits'} | Select-Object -Property * -Unique }).AddArgument($($args[0])) + $PIPs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/publicipaddresses'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVWAN = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualwans'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVHUB = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/virtualhubs'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVPNSITES = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/vpnsites'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVERs = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/expressroutegateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + + $AZAKS = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.containerservice/managedclusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVMSS = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Compute/virtualMachineScaleSets'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZNIC = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/networkinterfaces'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZPrivEnd = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/privateendpoints'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZVM = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.compute/virtualmachines'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZARO = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.redhatopenshift/openshiftclusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZKusto = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Kusto/clusters'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZAppGW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/applicationgateways'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZDW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.Databricks/workspaces'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZAppWeb = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.web/sites'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZAPIM = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.ApiManagement/service'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZLB = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/loadbalancers'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZBastion = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/bastionhosts'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZFW = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/azurefirewalls'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZNetProf = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.network/networkprofiles'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZCont = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'Microsoft.ContainerInstance/containerGroups'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + $AZANF = ([PowerShell]::Create()).AddScript({param($resources)$resources | Where-Object {$_.Type -eq 'microsoft.netapp/netappaccounts/capacitypools/volumes'} | Select-Object -Property * -Unique}).AddArgument($($args[0])) + + $jobAZVGWs = $AZVGWs.BeginInvoke() + $jobAZLGWs = $AZLGWs.BeginInvoke() + $jobAZVNETs = $AZVNETs.BeginInvoke() + $jobAZCONs = $AZCONs.BeginInvoke() + $jobAZEXPROUTEs = $AZEXPROUTEs.BeginInvoke() + $jobPIPs = $PIPs.BeginInvoke() + $jobAZVWAN = $AZVWAN.BeginInvoke() + $jobAZVHUB = $AZVHUB.BeginInvoke() + $jobAZVERs = $AZVERs.BeginInvoke() + $jobAZVPNSITES = $AZVPNSITES.BeginInvoke() + $jobAZAKS = $AZAKS.BeginInvoke() + $jobAZVMSS = $AZVMSS.BeginInvoke() + $jobAZNIC = $AZNIC.BeginInvoke() + $jobAZPrivEnd = $AZPrivEnd.BeginInvoke() + $jobAZVM = $AZVM.BeginInvoke() + $jobAZARO = $AZARO.BeginInvoke() + $jobAZKusto = $AZKusto.BeginInvoke() + $jobAZAppGW = $AZAppGW.BeginInvoke() + $jobAZDW = $AZDW.BeginInvoke() + $jobAZAppWeb = $AZAppWeb.BeginInvoke() + $jobAZAPIM = $AZAPIM.BeginInvoke() + $jobAZLB = $AZLB.BeginInvoke() + $jobAZBastion = $AZBastion.BeginInvoke() + $jobAZFW = $AZFW.BeginInvoke() + $jobAZNetProf = $AZNetProf.BeginInvoke() + $jobAZCont = $AZCont.BeginInvoke() + $jobAZANF = $AZANF.BeginInvoke() + + $job += $jobAZVGWs + $job += $jobAZLGWs + $job += $jobAZVNETs + $job += $jobAZCONs + $job += $jobAZEXPROUTEs + $job += $jobPIPs + $job += $jobAZVWAN + $job += $jobAZVHUB + $job += $jobAZVPNSITES + $job += $jobAZVERs + $job += $jobAZAKS + $job += $jobAZVMSS + $job += $jobAZNIC + $job += $jobAZPrivEnd + $job += $jobAZVM + $job += $jobAZARO + $job += $jobAZKusto + $job += $jobAZAppGW + $job += $jobAZDW + $job += $jobAZAppWeb + $job += $jobAZAPIM + $job += $jobAZLB + $job += $jobAZBastion + $job += $jobAZFW + $job += $jobAZNetProf + $job += $jobAZCont + $job += $jobAZANF + + while ($Job.Runspace.IsCompleted -contains $false) {} + + $AZVGWsS = $AZVGWs.EndInvoke($jobAZVGWs) + $AZLGWsS = $AZLGWs.EndInvoke($jobAZLGWs) + $AZVNETsS = $AZVNETs.EndInvoke($jobAZVNETs) + $AZCONsS = $AZCONs.EndInvoke($jobAZCONs) + $AZEXPROUTEsS = $AZEXPROUTEs.EndInvoke($jobAZEXPROUTEs) + $PIPsS = $PIPs.EndInvoke($jobPIPs) + $AZVWANS = $AZVWAN.EndInvoke($jobAZVWAN) + $AZVHUBS = $AZVHUB.EndInvoke($jobAZVHUB) + $AZVPNSITESS = $AZVPNSITES.EndInvoke($jobAZVPNSITES) + $AZVERsS = $AZVERs.EndInvoke($jobAZVERs) + $AZAKSs = $AZAKS.EndInvoke($jobAZAKS) + $AZVMSSs = $AZVMSS.EndInvoke($jobAZVMSS) + $AZNICs = $AZNIC.EndInvoke($jobAZNIC) + $AZPrivEnds = $AZPrivEnd.EndInvoke($jobAZPrivEnd) + $AZVMs = $AZVM.EndInvoke($jobAZVM) + $AZAROs = $AZARO.EndInvoke($jobAZARO) + $AZKustos = $AZKusto.EndInvoke($jobAZKusto) + $AZAppGWs = $AZAppGW.EndInvoke($jobAZAppGW) + $AZDWs = $AZDW.EndInvoke($jobAZDW) + $AZAppWebs = $AZAppWeb.EndInvoke($jobAZAppWeb) + $AZAPIMs = $AZAPIM.EndInvoke($jobAZAPIM) + $AZLBs = $AZLB.EndInvoke($jobAZLB) + $AZBastions = $AZBastion.EndInvoke($jobAZBastion) + $AZFWs = $AZFW.EndInvoke($jobAZFW) + $AZNetProfs = $AZNetProf.EndInvoke($jobAZNetProf) + $AZConts = $AZCont.EndInvoke($jobAZCont) + $AZANFs = $AZANF.EndInvoke($jobAZANF) + + + $AZVGWs.Dispose() + $AZLGWs.Dispose() + $AZVNETs.Dispose() + $AZCONs.Dispose() + $AZEXPROUTEs.Dispose() + $PIPs.Dispose() + $AZVWAN.Dispose() + $AZVHUB.Dispose() + $AZVPNSITES.Dispose() + $AZVERs.Dispose() + $AZAKS.Dispose() + $AZVMSS.Dispose() + $AZNIC.Dispose() + $AZPrivEnd.Dispose() + $AZVM.Dispose() + $AZARO.Dispose() + $AZKusto.Dispose() + $AZAppGW.Dispose() + $AZDW.Dispose() + $AZAppWeb.Dispose() + $AZAPIM.Dispose() + $AZLB.Dispose() + $AZBastion.Dispose() + $AZFW.Dispose() + $AZNetProf.Dispose() + $AZCont.Dispose() + $AZANF.Dispose() + + $CleanPIPs = $PIPsS | Where-Object {$_.id -notin $AZVGWsS.properties.ipConfigurations.properties.publicIPAddress.id} + + $Variables = @{ + 'AZVGWs' = $AZVGWsS; + 'AZLGWs' = $AZLGWsS; + 'AZVNETs' = $AZVNETsS; + 'AZCONs' = $AZCONsS; + 'AZEXPROUTEs' = $AZEXPROUTEsS; + 'PIPs' = $PIPsS; + 'AZVWAN' = $AZVWANS; + 'AZVHUB' = $AZVHUBS; + 'AZVPNSITES' = $AZVPNSITESS; + 'AZVERs' = $AZVERsS; + 'CleanPIPs' = $CleanPIPs; + 'AKS' = $AZAKSs; + 'VMSS' = $AZVMSSs; + 'NIC' = $AZNICs; + 'PrivEnd' = $AZPrivEnds; + 'VM' = $AZVMs; + 'ARO' = $AZAROs; + 'Kusto' = $AZKustos; + 'AppGtw' = $AZAppGWs; + 'DW' = $AZDWs; + 'AppWeb' = $AZAppWebs; + 'APIM' = $AZAPIMs; + 'LB' = $AZLBs; + 'Bastion' = $AZBastions; + 'FW' = $AZFWs; + 'NetProf' = $AZNetProfs; + 'Container' = $AZConts; + 'ANF' = $AZANFs + } + + $Variables + + } -ArgumentList $resources, $null + + } + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting Subnet files') | Out-File -FilePath $LogFile -Append + + $Subnetfiles = Get-ChildItem -Path $DiagramCache + + foreach($SubFile in $Subnetfiles) + { + if($SubFile.FullName -notin $XMLFiles) + { + Remove-Item -Path $SubFile.FullName + } + } + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Variables0 Function') | Out-File -FilePath $LogFile -Append + + Variables0 + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting Variables Job to complete') | Out-File -FilePath $LogFile -Append + + Get-Job -Name 'DiagramVariables' | Wait-Job + + $Job = Receive-Job -Name 'DiagramVariables' + + Get-Job -Name 'DiagramVariables' | Remove-Job + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting Variables') | Out-File -FilePath $LogFile -Append + + $Script:AZVGWs = $Job.AZVGWs + $Script:AZLGWs = $Job.AZLGWs + $Script:AZVNETs = $Job.AZVNETs + $Script:AZCONs = $Job.AZCONs + $Script:AZEXPROUTEs = $Job.AZEXPROUTEs + $Script:PIPs = $Job.PIPs + $Script:AZVWAN = $Job.AZVWAN + $Script:AZVHUB = $Job.AZVHUB + $Script:AZVPNSITES = $Job.AZVPNSITES + $Script:AZVERs = $Job.AZVERs + $Script:CleanPIPs = $Job.CleanPIPs + $Script:AKS = $Job.AKS + $Script:VMSS = $Job.VMSS + $Script:NIC = $Job.NIC + $Script:PrivEnd = $Job.PrivEnd + $Script:VM = $Job.VM + $Script:ARO = $Job.ARO + $Script:Kusto = $Job.Kusto + $Script:AppGtw = $Job.AppGtw + $Script:Databricks = $Job.DW + $Script:AppWeb = $Job.AppWeb + $Script:APIM = $Job.APIM + $Script:LB = $Job.LB + $Script:Bastion = $Job.Bastion + $Script:FW = $Job.FW + $Script:NetProf = $Job.NetProf + $Script:Container = $Job.Container + $Script:ANF = $Job.ANF + + $Script:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $Script:DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $Script:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $Script:IDNum = 0 + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Defining XML file') | Out-File -FilePath $LogFile -Append + + $Script:XmlWriter = New-Object System.XMl.XmlTextWriter($DDFile,$Null) + + $Script:XmlWriter.Formatting = 'Indented' + $Script:XmlWriter.Indentation = 2 + + $Script:XmlWriter.WriteStartDocument() + + $Script:XmlWriter.WriteStartElement('mxfile') + $Script:XmlWriter.WriteAttributeString('host', 'Electron') + $Script:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') + $Script:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') + $Script:XmlWriter.WriteAttributeString('etag', $etag) + $Script:XmlWriter.WriteAttributeString('version', '15.4.0') + $Script:XmlWriter.WriteAttributeString('type', 'device') + + $Script:XmlWriter.WriteStartElement('diagram') + $Script:XmlWriter.WriteAttributeString('id', $DiagID) + $Script:XmlWriter.WriteAttributeString('name', 'Network Topology') + + $Script:XmlWriter.WriteStartElement('mxGraphModel') + $Script:XmlWriter.WriteAttributeString('dx', "1326") + $Script:XmlWriter.WriteAttributeString('dy', "798") + $Script:XmlWriter.WriteAttributeString('grid', "1") + $Script:XmlWriter.WriteAttributeString('gridSize', "10") + $Script:XmlWriter.WriteAttributeString('guides', "1") + $Script:XmlWriter.WriteAttributeString('tooltips', "1") + $Script:XmlWriter.WriteAttributeString('connect', "1") + $Script:XmlWriter.WriteAttributeString('arrows', "1") + $Script:XmlWriter.WriteAttributeString('fold', "1") + $Script:XmlWriter.WriteAttributeString('page', "1") + $Script:XmlWriter.WriteAttributeString('pageScale', "1") + $Script:XmlWriter.WriteAttributeString('pageWidth', "850") + $Script:XmlWriter.WriteAttributeString('pageHeight', "1100") + $Script:XmlWriter.WriteAttributeString('math', "0") + $Script:XmlWriter.WriteAttributeString('shadow', "0") + + $Script:XmlWriter.WriteStartElement('root') + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "0") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "1") + $Script:XmlWriter.WriteAttributeString('parent', "0") + $Script:XmlWriter.WriteEndElement() + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling Stensils') | Out-File -FilePath $LogFile -Append + + Stensils + + if($AZLGWs -or $AZEXPROUTEs -or $AZVERs -or $AZVPNSITES) + { + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling OnPremNet') | Out-File -FilePath $LogFile -Append + + OnPremNet + if($Script:FullEnvironment) + { + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling as FullEnvironment') | Out-File -FilePath $LogFile -Append + + FullEnvironment + } + } + else + { + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Calling CloudOnly Function') | Out-File -FilePath $LogFile -Append + CloudOnly + } + + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndDocument() + $Script:XmlWriter.Flush() + $Script:XmlWriter.Close() + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting Job2 to complete') | Out-File -FilePath $LogFile -Append + + while ($Script:jobs2.IsCompleted -contains $false) {} + + #$VNetFile = ($DiagramCache+'Network.xml') + + $Subnetfiles = Get-ChildItem -Path $DiagramCache + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Processing Subnet files') | Out-File -FilePath $LogFile -Append + + foreach($SubFile in $Subnetfiles) + { + if($SubFile.FullName -notin $XMLFiles) + { + $newxml = New-Object XML + $newxml.Load($SubFile.FullName) + + $Innerxml = $newxml.mxfile.diagram.mxGraphModel.root.InnerXml + + $Innerxml2 = $Innerxml.Replace('','') + + #force the config into an XML + $xml = [xml](get-content $DDFile) + + $xmlFrag=$xml.CreateDocumentFragment() + $xmlFrag.InnerXml=$Innerxml2 + + $xml.mxfile.diagram.mxGraphModel.root.AppendChild($xmlFrag) + + #save file + $xml.Save($DDFile) + + Remove-Item -Path $SubFile.FullName + } + } + + ('DrawIONetwork - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - End of Network Diagram') | Out-File -FilePath $LogFile -Append + + } -ArgumentList $Subscriptions,$Resources,$Advisories,$DiagramCache,$FullEnvironment,$DDFile,$XMLFiles,$Logfile +} \ No newline at end of file diff --git a/Modules/Diagram/ARIDiagramOrganization.psm1 b/Modules/Diagram/ARIDiagramOrganization.psm1 new file mode 100644 index 0000000..fdb463e --- /dev/null +++ b/Modules/Diagram/ARIDiagramOrganization.psm1 @@ -0,0 +1,994 @@ +<# +.Synopsis +Organization Module for Draw.io Diagram + +.DESCRIPTION +This module is use for the Organization topology in the Draw.io Diagram. + +.Link +https://github.com/microsoft/ARI/Modules/Extras/ARIDiagramOrganization.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +Function Invoke-ARIDiagramOrganization { + Param($ResourceContainers,$DiagramCache,$LogFile) + + Start-Job -Name 'Diagram_Organization' -ScriptBlock { + + Import-Module AzureResourceInventory + + $Script:ResourceContainers = $($args[0]) + $Script:DiagramCache = $($args[1]) + + Function Icon { + Param($Style,$x,$y,$w,$h,$p) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', $Style) + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Connect { + Param($Source,$Target,$Parent) + + if($Parent){$Parent = $Parent}else{$Parent = 1} + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + $Script:XmlWriter.WriteAttributeString('style', "edgeStyle=none;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;") + $Script:XmlWriter.WriteAttributeString('edge', "1") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $Parent) + $Script:XmlWriter.WriteAttributeString('source', $Source) + $Script:XmlWriter.WriteAttributeString('target', $Target) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('relative', "1") + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + } + + Function Container0 { + Param($x,$y,$w,$h,$title) + $Script:ContID0 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID0) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;swimlaneFillColor=#F5F5F5;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Container1 { + Param($x,$y,$w,$h,$title) + $Script:ContID = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;swimlaneFillColor=#D5E8D4;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', "1") + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Container2 { + Param($x,$y,$w,$h,$title,$p) + $Script:ContID2 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID2) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;swimlaneFillColor=#DAE8FC;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Container3 { + Param($x,$y,$w,$h,$title,$p) + $Script:ContID3 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID3) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;swimlaneFillColor=#FFE6CC;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Container4 { + Param($x,$y,$w,$h,$title,$p) + $Script:ContID4 = (-join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_})+'-'+1) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', $Script:ContID4) + $Script:XmlWriter.WriteAttributeString('value', "$title") + $Script:XmlWriter.WriteAttributeString('style', "swimlane;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;swimlaneFillColor=#FFE6CC;rounded=1;") + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + Function Stencils { + $Script:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" + $Script:IconMgmtGroup = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Management_Groups.svg;" #width="44" height="71" + $Script:Ret = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" + $Script:Ret1 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#b0e3e6;strokeColor=#0e8088;" + $Script:Ret2 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#b1ddf0;strokeColor=#10739e;" + $Script:Ret3 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#fad7ac;strokeColor=#b46504;" + $Script:Ret4 = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;fillColor=#e1d5e7;strokeColor=#9673a6;" + + } + + Function Org { + + $OrgObjs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions'} + + $Script:1stLevel = @() + $Lvl2 = @() + $Lvl3 = @() + $Lvl4 = @() + foreach($org in $OrgObjs) + { + if($org.properties.managementgroupancestorschain.count -eq 2) + { + $Script:1stLevel += $org.properties.managementgroupancestorschain.displayname[0] + } + if($org.properties.managementgroupancestorschain.count -eq 3) + { + $Lvl2 += $org.properties.managementgroupancestorschain.name[0] + $Script:1stLevel += $org.properties.managementgroupancestorschain.displayname[1] + } + if($org.properties.managementgroupancestorschain.count -eq 4) + { + $Lvl3 += $org.properties.managementgroupancestorschain.name[0] + $Lvl2 += $org.properties.managementgroupancestorschain.name[1] + $Script:1stLevel += $org.properties.managementgroupancestorschain.displayname[2] + } + if($org.properties.managementgroupancestorschain.count -eq 5) + { + $Lvl4 += $org.properties.managementgroupancestorschain.name[0] + $Lvl3 += $org.properties.managementgroupancestorschain.name[1] + $Lvl2 += $org.properties.managementgroupancestorschain.name[2] + $Script:1stLevel += $org.properties.managementgroupancestorschain.displayname[3] + } + } + + $Script:1stLevel = $Script:1stLevel | Select-Object -Unique + $Lvl2 = $Lvl2 | Select-Object -Unique + $Lvl3 = $Lvl3 | Select-Object -Unique + $Lvl4 = $Lvl4 | Select-Object -Unique + + $Script:XLeft = 0 + $Script:XTop = 100 + $XXLeft = 100 + + $Script:XTop = $Script:XTop + 200 + + $RoundSubs00 = @() + foreach($Sub in $OrgObjs) + { + if($Sub.properties.managementgroupancestorschain[0].displayname -eq 'tenant root group') + { + $RoundSubs00 += $Sub + } + } + + $MgmtHeight0 = (($RoundSubs00.id.count * 70) + 80) + + Container0 '0' '0' '200' $MgmtHeight0 'tenant root group' + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('ManagementGroup', 'tenant root group') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + if($RoundSubs00) + { + icon $Script:IconMgmtGroup '-30' ($MgmtHeight0-15) '50' '50' $Script:ContID0 + } + else + { + icon $Script:IconMgmtGroup '75' '27' '50' '50' $Script:ContID0 + } + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = 50 + $LocalLeft = 25 + + foreach($Sub in $RoundSubs00) + { + $RGs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $sub.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($Script:CelNum++))) + + Icon $Ret1 $LocalLeft $LocalTop '150' '70' $Script:ContID0 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $RGNum = 1 + foreach($RG in $RGs) + { + $Attr = ('ResourceGroup_'+[string]$RGNum) + $Script:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) + $RGNum++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + icon $Script:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Script:ContID0 + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = $LocalTop + 90 + + } + + + + + foreach($1stlvl in $Script:1stLevel) + { + $RoundSubs0 = @() + + foreach($Sub in $OrgObjs) + { + if($Sub.properties.managementgroupancestorschain.displayname[0] -eq $1stlvl) + { + $RoundSubs0 += $Sub + } + } + + $MgmtHeight = (($RoundSubs0.id.count * 70) + 80) + + Container1 $XLeft $XTop '200' $MgmtHeight $1stlvl $Script:ContID0 + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('ManagementGroup', [string]$1stlvl) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + if($RoundSubs0) + { + icon $Script:IconMgmtGroup '-30' ($MgmtHeight-15) '50' '50' $Script:ContID + } + else + { + icon $Script:IconMgmtGroup '75' '27' '50' '50' $Script:ContID + } + + $Script:XmlWriter.WriteEndElement() + + Connect $Script:ContID0 $Script:ContID + + $LocalTop = 50 + $LocalLeft = 25 + + foreach($Sub in $RoundSubs0) + { + $RGs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $sub.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($Script:CelNum++))) + + Icon $Ret1 $LocalLeft $LocalTop '150' '70' $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $RGNum = 1 + foreach($RG in $RGs) + { + $Attr = ('ResourceGroup_'+[string]$RGNum) + $Script:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) + $RGNum++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + icon $Script:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Script:ContID + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = $LocalTop + 90 + + } + + ######################################## 2ND LEVEL ############################################## + + $2ndLevel = @() + foreach($sub2nd in $OrgObjs) + { + if($sub2nd.properties.managementgroupancestorschain.displayname[1] -eq $1stlvl) + { + $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[0] + } + if($sub2nd.properties.managementgroupancestorschain.displayname[2] -eq $1stlvl) + { + $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[1] + } + if($sub2nd.properties.managementgroupancestorschain.displayname[3] -eq $1stlvl) + { + $2ndLevel += $sub2nd.properties.managementgroupancestorschain.name[2] + } + } + $2ndLevel = $2ndLevel | Select-Object -Unique + + $XXLeft = 0 + if($2ndLevel.count % 2 -eq 1 ) + { + $Align = $true + $loops = -[Math]::ceiling($2ndLevel.count /2 - 1) + } + else + { + $Align = $false + $loops = [Math]::ceiling($2ndLevel.count / 2) + + } + if($2ndLevel.count -eq 1) + { + $loops = 1 + } + $TempSon = 0 + + + foreach($2nd in $2ndLevel) + { + $RoundSubs = @() + $Temp3rd = @() + $Temp4rd = @() + $Temp5th = @() + + foreach($Sub in $OrgObjs) + { + if($Sub.properties.managementgroupancestorschain.name[0] -eq $2nd) + { + $RoundSubs += $Sub + } + if($Sub.properties.managementgroupancestorschain.name[1] -eq $2nd) + { + $Temp3rd += $Sub.properties.managementgroupancestorschain.name[0] + } + if($Sub.properties.managementgroupancestorschain.name[2] -eq $2nd) + { + $Temp4rd += $Sub.properties.managementgroupancestorschain.name[0] + $Temp3rd += $Sub.properties.managementgroupancestorschain.name[1] + } + if($Sub.properties.managementgroupancestorschain.name[3] -eq $2nd) + { + $Temp5th += $Sub.properties.managementgroupancestorschain.name[0] + $Temp4rd += $Sub.properties.managementgroupancestorschain.name[1] + $Temp3rd += $Sub.properties.managementgroupancestorschain.name[2] + } + } + + $Temp3rd = $Temp3rd | Select-Object -Unique + $Temp4rd = $Temp4rd | Select-Object -Unique + $Temp5th = $Temp5th | Select-Object -Unique + + if($XXLeft -eq 0 -and $Align -eq $true) + { + } + elseif($XXLeft -eq 0 -and $Align -eq $false) + { + $XXLeft = -150 + -((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) + $loops++ + } + elseif($Align -eq $false -and $loops -eq 0) + { + $XXLeft = 150 + ((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) + $loops++ + } + elseif($loops -gt 0 -and $XXLeft -eq 0) + { + $XXLeft = $XXLeft + ($2ndLevel.count*300)/2 + ((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)))*300)/2) + $loops++ + } + elseif($XXLeft -le 0 -and $loops -lt 0) + { + $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150))} + $XXLeft = $XXLeft + -$XXTemp + $loops++ + } + elseif($XXLeft -gt 0 -and $loops -ge 0) + { + $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*150))} + $XXLeft = $XXLeft + $XXTemp + $loops++ + } + else + { + $XXTemp = if(((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*300)) -eq 0){300}else{((((($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)+$TempSon))*300))} + $XXLeft = $XXLeft + $XXTemp + $loops++ + } + + $MgmtHeight1 = if((($RoundSubs.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs.id.count * 90) + 50)} + + $XXTop = $MgmtHeight + 200 + + Container2 $XXLeft $XXTop '200' $MgmtHeight1 $2nd $Script:ContID + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('ManagementGroup', [string]$2nd) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + if($RoundSubs) + { + icon $Script:IconMgmtGroup '-30' ($MgmtHeight1-15) '50' '50' $Script:ContID2 + } + else + { + icon $Script:IconMgmtGroup '75' '27' '50' '50' $Script:ContID2 + } + + $Script:XmlWriter.WriteEndElement() + + Connect $Script:ContID $Script:ContID2 + + $TempSon = (($Temp3rd.count)+($Temp4rd.count)+($Temp5th.count)) + + if($XXLeft -eq 0 -and $loops -lt 0) + { + $XXLeft = -1 + } + elseif($XXLeft -lt 0 -and $loops -ge 0) + { + $XXLeft = 1 + } + + $LocalTop = 50 + $LocalLeft = 25 + + foreach($Sub in $RoundSubs) + { + $RGs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $sub.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($Script:CelNum++))) + + Icon $Ret2 $LocalLeft $LocalTop '150' '70' $Script:ContID2 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $RGNum = 1 + foreach($RG in $RGs) + { + $Attr = ('ResourceGroup_'+[string]$RGNum) + $Script:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) + $RGNum++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + icon $Script:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Script:ContID2 + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = $LocalTop + 90 + } + + + ######################################## 3RD LEVEL ############################################## + + $3rdLevel = @() + foreach($sub3rd in $OrgObjs) + { + if($sub3rd.properties.managementgroupancestorschain.name[1] -eq $2nd) + { + $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[0] + } + if($sub3rd.properties.managementgroupancestorschain.name[2] -eq $2nd) + { + $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[1] + } + if($sub3rd.properties.managementgroupancestorschain.name[3] -eq $2nd) + { + $3rdLevel += $sub3rd.properties.managementgroupancestorschain.name[2] + } + } + $3rdLevel = $3rdLevel | Select-Object -Unique + + $XXXLeft = 0 + if($3rdLevel.count % 2 -eq 1 ) + { + $Align3 = $true + $loops3 = -[Math]::ceiling($3rdLevel.count / 2 - 1) + } + else + { + $Align3 = $false + $loops3 = [Math]::ceiling($3rdLevel.count / 2) - 1 + + } + if($3rdLevel.count -eq 1) + { + $loops3 = 1 + } + + + foreach($3rd in $3rdLevel) + { + $RoundSubs3 = @() + $Temp4rd3 = @() + $Temp5th3 = @() + + foreach($Sub in $OrgObjs) + { + if($Sub.properties.managementgroupancestorschain.name[0] -eq $3rd) + { + $RoundSubs3 += $Sub + } + if($Sub.properties.managementgroupancestorschain.name[1] -eq $3rd) + { + $Temp4rd3 += $Sub.properties.managementgroupancestorschain.name[0] + } + if($Sub.properties.managementgroupancestorschain.name[2] -eq $3rd) + { + $Temp5th3 += $Sub.properties.managementgroupancestorschain.name[0] + $Temp4rd3 += $Sub.properties.managementgroupancestorschain.name[1] + } + } + + $Temp4rd3 = $Temp4rd3 | Select-Object -Unique + $Temp5th3 = $Temp5th3 | Select-Object -Unique + + + if($XXXLeft -eq 0 -and $Align3 -eq $true) + { + } + elseif($XXXLeft -eq 0 -and $Align3 -eq $false) + { + $XXXLeft = -150 + -((((($Temp4rd3.count)+($Temp5th3.count)))*150)/2) + $loops3++ + } + elseif($Align3 -eq $false -and $loops3 -eq 0) + { + $XXXLeft = 150 + ((((($Temp4rd3.count)+($Temp5th3.count)))*150)/2) + $loops3++ + } + elseif($loops3 -gt 0 -and $XXXLeft -eq 0) + { + $XXXLeft = $XXXLeft + ($3rdLevel.count*300)/2 + ((((($Temp4rd3.count)+($Temp5th3.count)))*300)/2) + $loops3++ + } + elseif($XXXLeft -eq 0 -and $loops3 -lt 0) + { + $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} + $XXXLeft = $XXXLeft + -$XXXTemp + $loops3++ + } + elseif($XXXLeft -lt 0 -and $loops3 -lt 0) + { + $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} + $XXXLeft = $XXXLeft + -$XXXTemp + $loops3++ + } + elseif($XXXLeft -eq 1 -and $loops3 -gt 0) + { + $XXXLeft = 150 + ((((($Temp4rd3.count)+($Temp5th3.count)))*150)) + $loops3++ + } + else + { + $XXXTemp = if(((((($Temp4rd3.count)+($Temp5th3.count)))*300)) -eq 0){300}else{((((($Temp4rd3.count)+($Temp5th3.count)))*300))} + $XXXLeft = $XXXLeft + $XXXTemp + $loops3++ + } + + + $MgmtHeight2 = if((($RoundSubs3.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs3.id.count * 90) + 50)} + + $XXXTop = $MgmtHeight1 + 200 + + Container3 $XXXLeft $XXXTop '200' $MgmtHeight2 $3rd $Script:ContID2 + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('ManagementGroup', [string]$3rd) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + if($RoundSubs3) + { + icon $Script:IconMgmtGroup '-30' ($MgmtHeight2-15) '50' '50' $Script:ContID3 + } + else + { + icon $Script:IconMgmtGroup '75' '27' '50' '50' $Script:ContID3 + } + + $Script:XmlWriter.WriteEndElement() + + Connect $Script:ContID2 $Script:ContID3 + + if($XXXLeft -eq 0 -and $loops3 -lt 0) + { + $XXXLeft = -1 + } + elseif($XXXLeft -lt 0 -and $loops3 -ge 0) + { + $XXXLeft = 1 + } + + $LocalTop = 50 + $LocalLeft = 25 + + foreach($Sub in $RoundSubs3) + { + + $RGs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $sub.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($Script:CelNum++))) + + Icon $Ret3 $LocalLeft $LocalTop '150' '70' $Script:ContID3 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $RGNum = 1 + foreach($RG in $RGs) + { + $Attr = ('ResourceGroup_'+[string]$RGNum) + $Script:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) + $RGNum++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + icon $Script:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Script:ContID3 + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = $LocalTop + 90 + } + + + ######################################## 4TH LEVEL ############################################## + + $4thLevel = @() + foreach($sub4th in $OrgObjs) + { + if($sub4th.properties.managementgroupancestorschain.name[1] -eq $3rd) + { + $4thLevel += $sub4th.properties.managementgroupancestorschain.name[0] + } + if($sub4th.properties.managementgroupancestorschain.name[2] -eq $3rd) + { + $4thLevel += $sub4th.properties.managementgroupancestorschain.name[1] + } + if($sub4th.properties.managementgroupancestorschain.name[3] -eq $3rd) + { + $4thLevel += $sub4th.properties.managementgroupancestorschain.name[2] + } + } + $4thLevel = $4thLevel | Select-Object -Unique + + $XXXXLeft = 0 + if($4thLevel.count % 2 -eq 1 ) + { + $Align4 = $true + $loops4 = -[Math]::ceiling($sub4th.count / 2 - 1) + } + else + { + $Align4 = $false + $loops4 = [Math]::ceiling($sub4th.count / 2) - 1 + + } + if($4thLevel.count -eq 1) + { + $loops4 = 1 + } + + + foreach($4th in $4thLevel) + { + $RoundSubs4 = @() + $Temp5th4 = @() + + foreach($Sub in $OrgObjs) + { + if($Sub.properties.managementgroupancestorschain.name[0] -eq $4th) + { + $RoundSubs4 += $Sub + } + if($Sub.properties.managementgroupancestorschain.name[1] -eq $4th) + { + $Temp5th4 += $Sub.properties.managementgroupancestorschain.name[0] + } + if($Sub.properties.managementgroupancestorschain.name[2] -eq $4th) + { + $Temp5th4 += $Sub.properties.managementgroupancestorschain.name[0] + } + } + + $Temp5th4 = $Temp5th4 | Select-Object -Unique + + if($XXXXLeft -eq 0 -and $Align4 -eq $true) + { + } + elseif($XXXXLeft -eq 0 -and $Align4 -eq $false) + { + $XXXXLeft = -150 + -((((($Temp4rd4.count)+($Temp5th4.count)))*150)/2) + $loops4++ + } + elseif($Align4 -eq $false -and $loops4 -eq 0) + { + $XXXXLeft = 150 + ((((($Temp4rd4.count)+($Temp5th4.count)))*150)/2) + $loops4++ + } + elseif($loops4 -gt 0 -and $XXXXLeft -eq 0) + { + $XXXXLeft = $XXXXLeft + ($4thLevel.count*300)/2 + ((((($Temp5th4.count)))*300)/2) + $loops4++ + } + elseif($XXXXLeft -eq 0 -and $loops4 -lt 0) + { + $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} + $XXXXLeft = $XXXXLeft + -$XXXXTemp + $loops4++ + } + elseif($XXXXLeft -lt 0 -and $loops4 -lt 0) + { + $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} + $XXXXLeft = $XXXXLeft + -$XXXXTemp + $loops4++ + } + elseif($XXXXLeft -eq 1 -and $loops4 -gt 0) + { + $XXXXLeft = 150 + ((((($Temp5th4.count)))*150)) + $loops4++ + } + else + { + $XXXXTemp = if(((((($Temp5th4.count)))*300)) -eq 0){300}else{((((($Temp5th4.count)))*300))} + $XXXXLeft = $XXXXLeft + $XXXXTemp + $loops4++ + } + + + $MgmtHeight3 = if((($RoundSubs4.id.count * 90) + 50) -eq 50){80}else{(($RoundSubs4.id.count * 90) + 50)} + + $XXXXTop = $MgmtHeight2 + 200 + + Container4 $XXXXLeft $XXXXTop '200' $MgmtHeight3 $4th $Script:ContID3 + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('ManagementGroup', [string]$4th) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + if($RoundSubs4) + { + icon $Script:IconMgmtGroup '-30' ($MgmtHeight3-15) '50' '50' $Script:ContID4 + } + else + { + icon $Script:IconMgmtGroup '75' '27' '50' '50' $Script:ContID4 + } + + $Script:XmlWriter.WriteEndElement() + + Connect $Script:ContID3 $Script:ContID4 + + if($XXXXLeft -eq 0 -and $loops4 -lt 0) + { + $XXXXLeft = -1 + } + elseif($XXXXLeft -lt 0 -and $loops4 -ge 0) + { + $XXXXLeft = 1 + } + + $LocalTop = 50 + $LocalLeft = 25 + + foreach($Sub in $RoundSubs4) + { + + $RGs = $Script:ResourceContainers | Where-Object {$_.Type -eq 'microsoft.resources/subscriptions/resourcegroups' -and $_.subscriptionid -eq $sub.subscriptionid} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $sub.name) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($Script:CelNum++))) + + Icon $Ret4 $LocalLeft $LocalTop '150' '70' $Script:ContID4 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + + $RGNum = 1 + foreach($RG in $RGs) + { + $Attr = ('ResourceGroup_'+[string]$RGNum) + $Script:XmlWriter.WriteAttributeString($Attr, [string]$RG.Name) + $RGNum++ + } + + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + icon $Script:IconSubscription ($LocalLeft+140) ($LocalTop+40) '31' '51' $Script:ContID4 + + $Script:XmlWriter.WriteEndElement() + + $LocalTop = $LocalTop + 90 + } + + } + + } + + } + + } + + } + + Stencils + + $OrgFile = ($DiagramCache+'Organization.xml') + + $Script:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $Script:DiagID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $Script:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $Script:IDNum = 0 + $Script:CelNum = 0 + + $Script:XmlWriter = New-Object System.XMl.XmlTextWriter($OrgFile,$Null) + + $Script:XmlWriter.Formatting = 'Indented' + $Script:XmlWriter.Indentation = 2 + + $Script:XmlWriter.WriteStartDocument() + + $Script:XmlWriter.WriteStartElement('mxfile') + $Script:XmlWriter.WriteAttributeString('host', 'Electron') + $Script:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') + $Script:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') + $Script:XmlWriter.WriteAttributeString('etag', $etag) + $Script:XmlWriter.WriteAttributeString('version', '15.4.0') + $Script:XmlWriter.WriteAttributeString('type', 'device') + + $Script:XmlWriter.WriteStartElement('diagram') + $Script:XmlWriter.WriteAttributeString('id', $DiagID) + $Script:XmlWriter.WriteAttributeString('name', 'Organization') + + $Script:XmlWriter.WriteStartElement('mxGraphModel') + $Script:XmlWriter.WriteAttributeString('dx', "1326") + $Script:XmlWriter.WriteAttributeString('dy', "798") + $Script:XmlWriter.WriteAttributeString('grid', "1") + $Script:XmlWriter.WriteAttributeString('gridSize', "10") + $Script:XmlWriter.WriteAttributeString('guides', "1") + $Script:XmlWriter.WriteAttributeString('tooltips', "1") + $Script:XmlWriter.WriteAttributeString('connect', "1") + $Script:XmlWriter.WriteAttributeString('arrows', "1") + $Script:XmlWriter.WriteAttributeString('fold', "1") + $Script:XmlWriter.WriteAttributeString('page', "1") + $Script:XmlWriter.WriteAttributeString('pageScale', "1") + $Script:XmlWriter.WriteAttributeString('pageWidth', "850") + $Script:XmlWriter.WriteAttributeString('pageHeight', "1100") + $Script:XmlWriter.WriteAttributeString('math', "0") + $Script:XmlWriter.WriteAttributeString('shadow', "0") + + $Script:XmlWriter.WriteStartElement('root') + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "0") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "1") + $Script:XmlWriter.WriteAttributeString('parent', "0") + $Script:XmlWriter.WriteEndElement() + + + Org + + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndDocument() + $Script:XmlWriter.Flush() + $Script:XmlWriter.Close() + + } -ArgumentList $ResourceContainers,$DiagramCache + +} \ No newline at end of file diff --git a/Modules/Diagram/ARIDiagramSubscription.psm1 b/Modules/Diagram/ARIDiagramSubscription.psm1 new file mode 100644 index 0000000..1e6176e --- /dev/null +++ b/Modules/Diagram/ARIDiagramSubscription.psm1 @@ -0,0 +1,1856 @@ +<# +.Synopsis +Subscription Module for Draw.io Diagram + +.DESCRIPTION +This module is use for the Subscription topology in the Draw.io Diagram. + +.Link +https://github.com/microsoft/ARI/Modules/Extras/ARIDiagramSubscription.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +Function Invoke-ARIDiagramSubscription { + Param($Subscriptions,$Resources,$DiagramCache,$LogFile) + + Start-Job -Name 'Diagram_Subscriptions' -ScriptBlock { + + Import-Module AzureResourceInventory + + $Script:Subscriptions = $($args[0]) + $Script:Resources = $($args[1]) + $Script:DiagramCache = $($args[2]) + + Function Icon { + Param($Style,$x,$y,$w,$h,$p) + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('style', $Style) + $Script:XmlWriter.WriteAttributeString('vertex', "1") + $Script:XmlWriter.WriteAttributeString('parent', $p) + + $Script:XmlWriter.WriteStartElement('mxGeometry') + $Script:XmlWriter.WriteAttributeString('x', $x) + $Script:XmlWriter.WriteAttributeString('y', $y) + $Script:XmlWriter.WriteAttributeString('width', $w) + $Script:XmlWriter.WriteAttributeString('height', $h) + $Script:XmlWriter.WriteAttributeString('as', "geometry") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + function variables { + + $Script:Ret = "rounded=0;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" + $Script:RetRound = "rounded=1;whiteSpace=wrap;fontSize=16;html=1;sketch=0;fontFamily=Helvetica;" + + ############# Azure AI + $Script:AzureBotServices = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Bot_Services.svg;' + $Script:AzureMachineLearning = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Machine_Learning.svg;' + $Script:AzureCognitive = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/ai_machine_learning/Cognitive_Services.svg;' + + ############# Azure Analytics + $Script:AzureDatabricks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Azure_Databricks.svg;' + $Script:AzureAnalysis = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Analysis_Services.svg;' + $Script:AzureSynapses = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/analytics/Azure_Synapse_Analytics.svg;' + + ############# Azure App Service + $Script:IconAPPs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/App_Services.svg;" #width="64" height="64" + $Script:AppSvcPlan = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/app_services/App_Service_Plans.svg;' #width="43.5" height="43.5" + $Script:AzureAppDomain = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/app_services/App_Service_Domains.svg;' + + + ############# Azure VMware + $Script:AzureAVSPrivateCloud = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/azure_vmware_solution/AVS.svg;' + + + ############# Azure Compute + $Script:SvcFabric = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Service_Fabric_Clusters.svg;' #width="49.47" height="47.25" + $Script:IconVMSS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/VM_Scale_Sets.svg;" # width="68" height="68" + $Script:Disks = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Disks.svg;' #width="40.72" height="40" + $Script:RestorePoint = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Restore_Points_Collections.svg;' + $Script:AzureCloudSvc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Cloud_Services_Classic.svg;' + $Script:AvSet = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Availability_Sets.svg;' #width="43.5" height="43.5" + $Script:AzureVMImage = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Images.svg;' + $Script:AzureAVDWorkspace = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/compute/Workspaces.svg;' + $Script:IconVMs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/compute/Virtual_Machine.svg;" #width="69" height="64" + + ############ Azure Container + $Script:IconAKS = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/containers/Kubernetes_Services.svg;" #width="68" height="60" + $Script:ContRegis = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/containers/Container_Registries.svg;' + $Script:AzureContainerInstances = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/containers/Container_Instances.svg;' + + ############ Azure Database + $Script:AzureSQLDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Database.svg;' + $Script:AzureSQLDBServer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Server.svg;' + $Script:AzureDataExplorer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Data_Explorer_Clusters.svg;' + $Script:AzureDBforPostgre = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_PostgreSQL_Server.svg;' + $Script:AzureDBforPostgreFlex = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_PostgreSQL_Server_Group.svg;' + $Script:AzureRedisCa = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Cache_Redis.svg;' + $Script:AzureDataFactory = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Azure_DevOps.svg;' + $Script:AzureCosmos = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Cosmos_DB.svg;' + $Script:AzureElastic = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Elastic_Pools.svg;' + $Script:AzureElasticJobAgent = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Elastic_Job_Agents.svg;' + $Script:AzureDB4MySQL = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_MySQL_Server.svg;' + $Script:AzureSQLManagedInstances = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/SQL_Managed_Instance.svg;' + $Script:AzureSQLManagedInstancesDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Managed_Database.svg;' + $Script:AzureSQLVM = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_SQL_VM.svg;' + $Script:AzureSQLVirtualCluster = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Virtual_Clusters.svg;' + $Script:AzureDBMigration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_Migration_Services.svg;' + $Script:AzurePurviewAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Purview_Accounts.svg;' + $Script:AzureMariaDB = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/databases/Azure_Database_MariaDB_Server.svg;' + + ############ Azure DevOps + $Script:Insight = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Application_Insights.svg;' #width="44" height="63" + $Script:AzureDevOpsOrg = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/devops/Azure_DevOps.svg;' + + ############ Azure General + $Script:AzureError = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Error.svg;' #width="50.12" height="48" + $Script:AzureWebSlot = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Web_Slots.svg;' + $Script:AzureWorkbooks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Workbooks.svg;' + $Script:AzureWebTest = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/general/Web_Test.svg;' + $Script:IconSubscription = "aspect=fixed;html=1;points=[];align=center;image;fontSize=20;image=img/lib/azure2/general/Subscriptions.svg;" #width="44" height="71" + $Script:IconRG = "image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=12;image=img/lib/mscae/ResourceGroup.svg;" # width="37.5" height="30" + + ############ Azure Identity + $Script:AzureB2C = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/identity/Azure_AD_B2C.svg;' + + ########### Azure Integration + $Script:SvcBus = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Service_Bus.svg;' #width="45.05" height="39.75" + $Script:AzureAPIConnections = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Logic_Apps_Custom_Connector.svg;' + $Script:AzureLogicApp = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Logic_Apps.svg;' + $Script:AzureDataCatalog = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Azure_Data_Catalog.svg;' + $Script:AzureEventGridSymtopics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/System_Topic.svg;' + $Script:AzureAppConfiguration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/App_Configuration.svg;' + $Script:AzureIntegrationAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Integration_Accounts.svg;' + $Script:AzureEvtGridTopics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Event_Grid_Topics.svg;' + $Script:AzureAPIMangement = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/API_Management_Services.svg;' + $Script:AzureEvtGridDomain = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/integration/Event_Grid_Subscriptions.svg;' + + ########### Azure IoT + $Script:AzureEvtHubs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/iot/Event_Hubs.svg;' + $Script:AzureIoTHubs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/iot/Event_Hubs.svg;' + + ########### Azure Management Governance + $Script:RecoveryVault = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/Recovery_Services_Vaults.svg;' #width="43.7" height="38" + $Script:AutAcc = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/Automation_Accounts.svg;' + $Script:AzureArcServer = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/management_governance/MachinesAzureArc.svg;' + + + ########### Azure Migrate + $Script:AzureMigration = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/migrate/Azure_Migrate.svg;' + + + ########### Azure Networking + $Script:AzureConnections = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Connections.svg;" #width="68" height="68" + $Script:AzureExpressRoute = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/ExpressRoute_Circuits.svg;" #width="70" height="64" + $Script:AzureVGW = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Network_Gateways.svg;" #width="52" height="69" + $Script:AzureVNET = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Virtual_Networks.svg;" #width="67" height="40" + $Script:AzurePIP = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Public_IP_Addresses.svg;" # width="65" height="52" + $Script:Azureproximityplacementgroups = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Proximity_Placement_Groups.svg;' + $Script:AzureUDRs = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Route_Tables.svg;' + $Script:AzureRouteFilters = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Route_Filters.svg;' + $Script:AzureBastionHost = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Bastions.svg;' + $Script:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" + $Script:NetWatcher = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Watcher.svg;' + $Script:AzurePvtLinks = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Private_Link_Service.svg;' + $Script:AzureIPGroups = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/IP_Groups.svg;' + $Script:AzureFW = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Firewalls.svg;' + $Script:AzureLNG = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Local_Network_Gateways.svg;' + $Script:AzureFrontDoor = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Front_Doors.svg;' + $Script:AzurePIPPrefixes = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Public_IP_Prefixes.svg;' + $Script:AzureNATGateways = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/NAT.svg;' + $Script:AzureCDN = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/CDN_Profiles.svg;' + $Script:AzureNSG = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Security_Groups.svg;' + $Script:AzureSvcEndpointPol = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Service_Endpoint_Policies.svg;' + $Script:AzureVMNIC = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Network_Interfaces.svg;' + $Script:AzureWAFPolicies = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Web_Application_Firewall_Policies_WAF.svg;' + $Script:AzureDNSZone = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/DNS_Zones.svg;' + $Script:AzureAppGateway = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Application_Gateways.svg;' + $Script:AzureDDOS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/DDoS_Protection_Plans.svg;' + $Script:AzureTrafficManager = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Traffic_Manager_Profiles.svg;' + $Script:AzurePvtLink = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/networking/Private_Link.svg;' + $Script:IconPVTs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Private_Endpoint.svg;" #width="72" height="66" + $Script:IconLBs = "aspect=fixed;html=1;points=[];align=center;image;fontSize=14;image=img/lib/azure2/networking/Load_Balancers.svg;" #width="72" height="72" + + ########### Azure Other + $Script:Dashboard = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Dashboard_Hub.svg;' #width="50.02" height="38.25" + $Script:TemplSpec = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Template_Specs.svg;' + $Script:AzureBackupVault = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Azure_Backup_Center.svg;' + $Script:AzureERDirect = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/ExpressRoute_Direct.svg;' + $Script:AzureAVDSessionHost = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/AVS_VM.svg;' + $Script:AzureAVDHostPool = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Windows_Virtual_Desktop.svg;' + $Script:AzureGrafana = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Grafana.svg;' + $Script:AzureNetworkManager = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/other/Azure_Network_Manager.svg;' + + + ########### Azure Security + $Script:KeyVault = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Key_Vaults.svg;' #width="49.5" height="49.5" + $Script:AzureAppSecGroup = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Application_Security_Groups.svg;' + $Script:AzureDefender = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/security/Azure_Defender.svg;' + + + ########### Azure Storage + $Script:StorageAcc = 'image;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Storage_Accounts.svg;' #width="43.75" height="35" + $Script:AzureNetApp = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Azure_NetApp_Files.svg;' + $Script:AzureDatalakeGen1 = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/storage/Data_Lake_Storage_Gen1.svg;' + + + ########### Azure Web + $Script:AzureMediaServices = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/azure2/web/Azure_Media_Service.svg;' + + ########### MSCAE + $Script:Certificate = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Certificate.svg;' #width="50" height="42" + $Script:LogAnalytics = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Log_Analytics_Workspaces.svg;' #width="40" height="40" + $Script:PvtDNS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/DNS_Private_Zones.svg;' #width="50" height="50" + $Script:AzureSaaS = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Software_as_a_Service.svg;' + $Script:AzureRelay = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Service_Bus_Relay.svg;' + $Script:AzureLogAlertRule = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/Notification.svg;' + $Script:AzureSignalR = 'image;sketch=0;aspect=fixed;html=1;points=[];align=center;fontSize=14;image=img/lib/mscae/SignalR.svg;' + + + } + + function ResourceTypes { + Param($TempResourceType,$TempResLeft,$TempResTop) + + switch ($TempResourceType.Name) + { + <########## AZURE AI ############> + + 'microsoft.botservice/botservices' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Bot' + "`n" + 'Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureBotServices $TempResLeft $TempResTop "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.machinelearningservices/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Machine' + "`n" + 'Learning')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureMachineLearning $TempResLeft $TempResTop "40" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.cognitiveservices/accounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cognitive' + "`n" + 'Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureCognitive $TempResLeft $TempResTop "58" "38" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE ANALYTICS ############> + + 'microsoft.databricks/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Databricks')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDatabricks $TempResLeft $TempResTop "48" "52" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.analysisservices/servers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Analysis' + "`n" + 'Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAnalysis $TempResLeft $TempResTop "53" "41" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.synapse/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Synapse' + "`n" + 'Analytics')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSynapses $TempResLeft $TempResTop "45" "54" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE APP ############> + + 'microsoft.web/sites' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web App')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconAPPs $TempResLeft $TempResTop "45" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.web/serverfarms' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Service Plan')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AppSvcPlan $TempResLeft $TempResTop "43.5" "43.5" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.domainregistration/domains' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App Service' + "`n" + 'Domain')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAppDomain $TempResLeft $TempResTop "50" "38" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE VMWARE ############> + + 'microsoft.avs/privateclouds' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VMware' + "`n" + 'Private Cloud')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAVSPrivateCloud $TempResLeft $TempResTop "60" "46" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE COMPUTE ############> + + 'microsoft.desktopvirtualization/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Workspaces')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAVDWorkspace $TempResLeft $TempResTop "48" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/virtualmachinescalesets' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VMSS')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVMSS $TempResLeft $TempResTop "45" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.servicefabric/clusters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Fabric')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SvcFabric $TempResLeft $TempResTop "49.4" "47.2" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/disks' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Disk')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Disks $TempResLeft $TempResTop "40.72" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/virtualmachines' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Virtual' + "`n" + 'Machine')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconVMs $TempResLeft $TempResTop "43" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/availabilitysets' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Availability' + "`n" + 'Set')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AvSet $TempResLeft $TempResTop "43.5" "43.5" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/restorepointcollections' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Restore' + "`n" + 'Point Collection')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $RestorePoint $TempResLeft $TempResTop "50" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.classiccompute/domainnames' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cloud' + "`n" + 'Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureCloudSvc $TempResLeft $TempResTop "51" "37" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/images' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Images')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureVMImage $TempResLeft $TempResTop "47" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + <########## AZURE CONTAINERS ############> + + 'microsoft.containerservice/managedclusters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AKS')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconAKS $TempResLeft $TempResTop "51" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.containerregistry/registries' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Container' + "`n" + 'Registry')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $ContRegis $TempResLeft $TempResTop "45" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.kubernetes/connectedclusters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Kubernetes' + "`n" + 'Azure Arc')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconAKS $TempResLeft $TempResTop "51" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.containerinstance/containergroups' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Container' + "`n" + 'Instances')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureContainerInstances $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + <########## AZURE DATABASES ############> + + 'microsoft.sql/servers/databases' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Database')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLDB $TempResLeft $TempResTop "36" "49" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/servers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLDBServer $TempResLeft $TempResTop "49" "49" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.kusto/clusters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Explorer Cluster')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDataExplorer $TempResLeft $TempResTop "41" "41" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dbforpostgresql/servers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'PostgreSQL')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDBforPostgre $TempResLeft $TempResTop "38" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dbforpostgresql/flexibleservers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' PostgreSQL' + "`n" + 'Flexible Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDBforPostgreFlex $TempResLeft $TempResTop "37.94" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.cache/redis' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Redis' + "`n" + 'Cache')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureRedisCa $TempResLeft $TempResTop "55" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.datafactory/factories' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Factory')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDataFactory $TempResLeft $TempResTop "44" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.documentdb/databaseaccounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Cosmos' + "`n" + 'Database')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureCosmos $TempResLeft $TempResTop "51" "51" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/servers/elasticpools' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Elastic Pool')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureElastic $TempResLeft $TempResTop "51" "51" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/servers/jobagents' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Elastic' + "`n" + 'Job Agent')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureElasticJobAgent $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dbformysql/servers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MySQL' + "`n" + 'Database Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDB4MySQL $TempResLeft $TempResTop "35" "46" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dbformysql/flexibleservers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MySQL' + "`n" + 'Flexible Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDB4MySQL $TempResLeft $TempResTop "35" "46" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/managedinstances/databases' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Managed Instances' + "`n" + 'Database')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLManagedInstancesDB $TempResLeft $TempResTop "51" "47" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/managedinstances' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Managed Instances')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLManagedInstances $TempResLeft $TempResTop "50" "49" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sqlvirtualmachine/sqlvirtualmachines' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Virtual Machine')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLVM $TempResLeft $TempResTop "50" "46" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.sql/virtualclusters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SQL' + "`n" + 'Virtual Cluster')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSQLVirtualCluster $TempResLeft $TempResTop "50" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.datamigration/sqlmigrationservices' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Service')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.datamigration/services' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Service')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.datamigration/services/projects' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Database' + "`n" + 'Migration Project')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDBMigration $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.purview/accounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Purview' + "`n" + 'Account')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzurePurviewAcc $TempResLeft $TempResTop "58" "32" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dbformariadb/servers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' MariaDB' + "`n" + 'Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureMariaDB $TempResLeft $TempResTop "34" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE DEVOPS ############> + + 'microsoft.insights/metricalerts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Insight' + "`n" + 'Metrics')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Insight $TempResLeft $TempResTop "33" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.insights/components' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Insights')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Insight $TempResLeft $TempResTop "50" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.visualstudio/account' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DevOps' + "`n" + 'Organization')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDevOpsOrg $TempResLeft $TempResTop "41" "41" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE GENERAL ############> + + 'microsoft.web/sites/slots' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web' + "`n" + 'Slots')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWebSlot $TempResLeft $TempResTop "44" "49" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.insights/workbooks' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Workbooks')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWorkbooks $TempResLeft $TempResTop "39" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.insights/webtests' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Web' + "`n" + 'Test')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWebTest $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE IDENTITY ############> + + 'microsoft.azureactivedirectory/b2cdirectories' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' B2C' + "`n" + 'Directories')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureB2C $TempResLeft $TempResTop "49" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE INTEGRATION ############> + + 'microsoft.servicebus/namespaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Bus')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $SvcBus $TempResLeft $TempResTop "45.05" "39.75" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.web/connections' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' API' + "`n" + 'Connections')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAPIConnections $TempResLeft $TempResTop "43" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.logic/workflows' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Logic' + "`n" + 'Apps')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureLogicApp $TempResLeft $TempResTop "57" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.datacatalog/catalogs' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data' + "`n" + 'Catalog')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDataCatalog $TempResLeft $TempResTop "46" "52" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.web/customapis' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Logic App' + "`n" + 'Custom Connector')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAPIConnections $TempResLeft $TempResTop "43" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.eventgrid/systemtopics' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'System Topics')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureEventGridSymtopics $TempResLeft $TempResTop "44" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.appconfiguration/configurationstores' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' App' + "`n" + 'Configuration')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAppConfiguration $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.logic/integrationaccounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Integration' + "`n" + 'Accounts')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureIntegrationAcc $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.eventgrid/topics' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'Topics')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureEvtGridTopics $TempResLeft $TempResTop "44" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.apimanagement/service' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' API' + "`n" + 'Management')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAPIMangement $TempResLeft $TempResTop "50" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.eventgrid/domains' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event Grid' + "`n" + 'Domain')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureEvtGridDomain $TempResLeft $TempResTop "50" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE IOT ############> + + 'microsoft.eventhub/namespaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Event' + "`n" + 'Hubs')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureEvtHubs $TempResLeft $TempResTop "50" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.devices/iothubs' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' IoT' + "`n" + 'Hubs')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureIoTHubs $TempResLeft $TempResTop "50" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + <########## AZURE MANAGEMENT GOVERNANCE ############> + + 'microsoft.recoveryservices/vaults' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Recovery' + "`n" + 'Services Vault')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $RecoveryVault $TempResLeft $TempResTop "43.5" "38" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.automation/automationaccounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Automation' + "`n" + 'Account')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AutAcc $TempResLeft $TempResTop "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'Microsoft.HybridCompute/machines' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Arc' + "`n" + 'Server')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureArcServer $TempResLeft $TempResTop "30" "54" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE MIGRATE ############> + + 'microsoft.migrate/projects' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Migration' + "`n" + 'Project')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureMigration $TempResLeft $TempResTop "62" "34" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE NETWORKING ############> + + 'microsoft.network/privateendpoints' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'Endpoint')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconPVTs $TempResLeft $TempResTop "44" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/loadbalancers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Load' + "`n" + 'Balancer')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconLBs $TempResLeft $TempResTop "41" "41" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/publicipaddresses' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Public IPs')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzurePIP $TempResLeft $TempResTop "51" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/virtualnetworks' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Virtual' + "`n" + 'Network')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureVNET $TempResLeft $TempResTop "62" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/networkwatchers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Watcher')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $NetWatcher $TempResLeft $TempResTop "44" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/virtualnetworkgateways' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' VPN' + "`n" + 'Gateway')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureVGW $TempResLeft $TempResTop "36" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/connections' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Connection')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureConnections $TempResLeft $TempResTop "44" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/expressroutecircuits' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Express' + "`n" + 'Route')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureExpressRoute $TempResLeft $TempResTop "45" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/networksecuritygroups' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Security Group')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureNSG $TempResLeft $TempResTop "37" "46" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/routetables' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' User Defined' + "`n" + 'Route Tables')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureUDRs $TempResLeft $TempResTop "43" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/routefilters' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Route' + "`n" + 'Filters')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureRouteFilters $TempResLeft $TempResTop "54" "34" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/bastionhosts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Bastion' + "`n" + 'Host')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureBastionHost $TempResLeft $TempResTop "31" "37" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.compute/proximityplacementgroups' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Proximity' + "`n" + 'Placement Groups')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Azureproximityplacementgroups $TempResLeft $TempResTop "47" "45" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/privatelinkservices' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'Link Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzurePvtLinks $TempResLeft $TempResTop "56" "33" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/ipgroups' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' IP' + "`n" + 'Groups')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureIPGroups $TempResLeft $TempResTop "56" "33" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/azurefirewalls' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Firewall')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureFW $TempResLeft $TempResTop "64" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/localnetworkgateways' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Local' + "`n" + 'Network Gateway')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureLNG $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/frontdoors' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Front Door')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureFrontDoor $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/natgateways' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' NAT' + "`n" + 'Gateways')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureNATGateways $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/publicipprefixes' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Public IP' + "`n" + 'Prefixes')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzurePIPPrefixes $TempResLeft $TempResTop "51" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.cdn/profiles' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' CDN' + "`n" + 'Profile')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureCDN $TempResLeft $TempResTop "64" "36" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/serviceendpointpolicies' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Service' + "`n" + 'Endpoint Polices')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSvcEndpointPol $TempResLeft $TempResTop "48" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.Network/networkInterfaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Interface')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureVMNIC $TempResLeft $TempResTop "50" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/frontdoorwebapplicationfirewallpolicies' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(FrontDoor)')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.cdn/cdnwebapplicationfirewallpolicies' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(CDN)')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' WAF Policies' + "`n" + '(App Gateway)')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureWAFPolicies $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/dnszones' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DNS' + "`n" + 'Zone')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDNSZone $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/applicationgateways' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Application' + "`n" + 'Gateway')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAppGateway $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/ddosprotectionplans' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' DDOS' + "`n" + 'Protection')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDDOS $TempResLeft $TempResTop "38" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/trafficmanagerprofiles' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Traffic Manager' + "`n" + 'Profiles')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureTrafficManager $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.hybridcompute/privatelinkscopes' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Arc Private' + "`n" + 'Link Scope')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzurePvtLink $TempResLeft $TempResTop "50" "44" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + <########## AZURE OTHER ############> + + 'microsoft.portal/dashboards' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Shared' + "`n" + 'Dashboard')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Dashboard $TempResLeft $TempResTop "50.02" "38.25" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.resources/templatespecs' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Template' + "`n" + 'Specs')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $TemplSpec $TempResLeft $TempResTop "33" "39" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dataprotection/backupvaults' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Backup' + "`n" + 'Services Vault')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureBackupVault $TempResLeft $TempResTop "40" "36" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/expressrouteports' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' ExpressRoute' + "`n" + 'Direct')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureBackupVault $TempResLeft $TempResTop "45" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.desktopvirtualization/hostpools/sessionhosts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Session Host')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAVDSessionHost $TempResLeft $TempResTop "51" "51" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.desktopvirtualization/hostpools' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' AVD' + "`n" + 'Host Pool')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAVDHostPool $TempResLeft $TempResTop "51" "51" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.dashboard/grafana' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Grafana')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureGrafana $TempResLeft $TempResTop "50" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/networkmanagers' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Network' + "`n" + 'Manager')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureNetworkManager $TempResLeft $TempResTop "46" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE SECURITY ############> + + 'microsoft.keyvault/vaults' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Key' + "`n" + 'Vault')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $KeyVault $TempResLeft $TempResTop "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/applicationsecuritygroups' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Application' + "`n" + 'Security Group')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureAppSecGroup $TempResLeft $TempResTop "35" "43" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.easm/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Defender' + "`n" + 'EASM')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDefender $TempResLeft $TempResTop "50" "38" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE STORAGE ############> + + 'microsoft.storage/storageaccounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Storage' + "`n" + 'Account')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $StorageAcc $TempResLeft $TempResTop "49.94" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.netapp/netappaccounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' NetApp' + "`n" + 'Account')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureNetApp $TempResLeft $TempResTop "40" "32" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'Microsoft.DataLakeStore/accounts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Data Lake' + "`n" + 'Storage Gen1')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureDatalakeGen1 $TempResLeft $TempResTop "54" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## AZURE WEB ############> + + 'microsoft.media/mediaservices' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Media' + "`n" + 'Services')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureMediaServices $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + + <########## MSCAE ############> + + 'microsoft.web/certificates' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Certificate')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $Certificate $TempResLeft $TempResTop "50" "42" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.operationalinsights/workspaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Log' + "`n" + 'Analytics')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $LogAnalytics $TempResLeft $TempResTop "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.network/privatednszones' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Private' + "`n" + 'DNS Zone')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $PvtDNS $TempResLeft $TempResTop "40" "40" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.saas/resources' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SaaS' + "`n" + 'Resource')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSaaS $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.relay/namespaces' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Relay')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureRelay $TempResLeft $TempResTop "50" "50" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.Insights/ActivityLogAlerts' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Activity Log' + "`n" + 'Alert Rule')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'Microsoft.AlertsManagement/smartDetectorAlertRules' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Smart Detector' + "`n" + 'Alert Rule')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'microsoft.insights/scheduledqueryrules' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' Log Search' + "`n" + 'Alert Rule')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureLogAlertRule $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + 'Microsoft.SignalRService/SignalR' + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' SignalR')) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureSignalR $TempResLeft $TempResTop "48" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + + + default + { + $TempName = [string]$TempResourceType.Name + $TempName = $TempName.Replace('microsoft.','') + $TempName = $TempName.split('/') + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Count + ' ' + $TempName[0]+ "`n" + $TempName[1])) + #$Script:XmlWriter.WriteAttributeString('label', ([string]$TempResourceType.Name)) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $AzureError $TempResLeft $TempResTop "50" "48" 1 + + $Script:XmlWriter.WriteEndElement() + } + } + + } + + + $Script:NonTypes = ('microsoft.compute/virtualmachines/extensions', + 'microsoft.operationsmanagement/solutions', + 'microsoft.network/privatednszones/virtualnetworklinks', + 'microsoft.devtestlab/schedules', + 'microsoft.managedidentity/userassignedidentities', + 'microsoft.compute/virtualmachines/runcommands', + 'microsoft.compute/sshpublickeys', + 'microsoft.resources/templatespecs/versions', + 'microsoft.containerregistry/registries/replications', + 'microsoft.automation/automationaccounts/runbooks', + 'microsoft.compute/snapshots', + 'microsoft.insights/autoscalesettings', + 'microsoft.insights/actiongroups', + 'microsoft.network/networkwatchers/flowlogs', + 'microsoft.compute/diskencryptionsets', + 'microsoft.insights/datacollectionrules', + 'microsoft.netapp/netappaccounts/capacitypools', + 'microsoft.netapp/netappaccounts/capacitypools/volumes', + 'microsoft.network/firewallpolicies', + 'microsoft.web/connectiongateways', + 'microsoft.security/automations', + 'microsoft.datacatalog/catalogs', + 'microsoft.hybridcompute/machines/extensions', + 'microsoft.compute/galleries/images', + 'microsoft.compute/galleries/images/versions', + 'microsoft.desktopvirtualization/applicationgroups', + 'microsoft.network/networkintentpolicies', + 'microsoft.resourcegraph/queries', + 'microsoft.cdn/profiles/endpoints', + 'microsoft.network/networkwatchers/connectionmonitors', + 'microsoft.compute/galleries', + 'microsoft.synapse/workspaces/sqlpools', + 'microsoft.containerregistry/registries/webhooks', + 'microsoft.migrate/movecollections', + 'microsoft.databricks/accessconnectors', + 'microsoft.insights/datacollectionendpoints', + 'microsoft.synapse/workspaces/bigdatapools', + 'microsoft.media/mediaservices/streamingendpoints', + 'microsoft.security/customentitystoreassignments', + 'microsoft.security/securityconnectors', + 'microsoft.security/customassessmentautomations', + 'microsoft.datashare/accounts', + 'microsoft.cdn/profiles/afdendpoints', + 'microsoft.securitydevops/azuredevopsconnectors', + 'microsoft.securitydevops/githubconnectors', + 'microsoft.security/datascanners', + 'microsoft.offazure/importsites', + 'microsoft.offazure/vmwaresites', + 'microsoft.migrate/migrateprojects', + 'microsoft.migrate/assessmentprojects', + 'microsoft.offazure/mastersites', + 'microsoft.automation/automationaccounts/configurations', + 'microsoft.alertsmanagement/actionrules', + 'microsoft.resourceconnector/appliances', + 'microsoft.automanage/configurationprofiles', + 'microsoft.offazure/hypervsites', + 'microsoft.machinelearningservices/registries', + 'microsoft.machinelearningservices/workspaces/onlineendpoints/deployments', + 'microsoft.machinelearningservices/workspaces/onlineendpoints', + 'microsoft.serviceshub/connectors', + 'microsoft.containerregistry/registries/tasks', + 'microsoft.web/staticsites', + 'microsoft.security/standards', + 'microsoft.security/iotsecuritysolutions', + 'microsoft.security/assignments', + 'microsoft.connectedvmwarevsphere/virtualmachines', + 'microsoft.connectedvmwarevsphere/vcenters', + 'microsoft.extendedlocation/customlocations', + 'microsoft.offazure/serversites', + 'microsoft.signalrservice/webpubsub', + 'microsoft.eventgrid/partnerconfigurations') + + + $Subs = $Resources | group-object -Property subscriptionId | Sort-Object -Property Count -Descending + + $DDDFile = ($DiagramCache+'Subscriptions.xml') + + $XLeft = 100 + $XTop = 100 + $CelNum = 0 + + $Script:etag = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + $Script:CellID = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $Script:IDNum = 0 + + $Script:XmlWriter = New-Object System.XMl.XmlTextWriter($DDDFile,$Null) + + $Script:XmlWriter.Formatting = 'Indented' + $Script:XmlWriter.Indentation = 2 + + $Script:XmlWriter.WriteStartDocument() + + $Script:XmlWriter.WriteStartElement('mxfile') + $Script:XmlWriter.WriteAttributeString('host', 'Electron') + $Script:XmlWriter.WriteAttributeString('modified', '2021-10-01T21:45:40.561Z') + $Script:XmlWriter.WriteAttributeString('agent', '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36') + $Script:XmlWriter.WriteAttributeString('etag', $etag) + $Script:XmlWriter.WriteAttributeString('version', '15.4.0') + $Script:XmlWriter.WriteAttributeString('type', 'device') + + foreach($Sub in $Subs.Name) + { + $RGLeft = $XLeft + 40 + $RGTop = $XTop + 40 + $Resource = $Resources | Where-Object {$_.subscriptionId -eq $Sub} + $SubName = $Subscriptions | Where-Object {$_.id -eq $Sub} + $Resource0 = $Resource | Group-Object -Property resourceGroup | Sort-Object -Property Count -Descending + $SubName = $SubName.Name + + $DiagID1 = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $Script:XmlWriter.WriteStartElement('diagram') + $Script:XmlWriter.WriteAttributeString('id', $DiagID1) + $Script:XmlWriter.WriteAttributeString('name', $SubName) + + $Script:XmlWriter.WriteStartElement('mxGraphModel') + $Script:XmlWriter.WriteAttributeString('dx', "1326") + $Script:XmlWriter.WriteAttributeString('dy', "798") + $Script:XmlWriter.WriteAttributeString('grid', "1") + $Script:XmlWriter.WriteAttributeString('gridSize', "10") + $Script:XmlWriter.WriteAttributeString('guides', "1") + $Script:XmlWriter.WriteAttributeString('tooltips', "1") + $Script:XmlWriter.WriteAttributeString('connect', "1") + $Script:XmlWriter.WriteAttributeString('arrows', "1") + $Script:XmlWriter.WriteAttributeString('fold', "1") + $Script:XmlWriter.WriteAttributeString('page', "1") + $Script:XmlWriter.WriteAttributeString('pageScale', "1") + $Script:XmlWriter.WriteAttributeString('pageWidth', "850") + $Script:XmlWriter.WriteAttributeString('pageHeight', "1100") + $Script:XmlWriter.WriteAttributeString('math', "0") + $Script:XmlWriter.WriteAttributeString('shadow', "0") + + $Script:XmlWriter.WriteStartElement('root') + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "0") + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('mxCell') + $Script:XmlWriter.WriteAttributeString('id', "1") + $Script:XmlWriter.WriteAttributeString('parent', "0") + $Script:XmlWriter.WriteEndElement() + + variables + + $Script:CellIDRes = -join ((65..90) + (97..122) | Get-Random -Count 20 | ForEach-Object {[char]$_}) + + $Witd = 2060 + + $Counter = 1 + $ZCounter = 0 + foreach($RG in $Resource0.Name) + { + $Res = $Resource | Where-Object {$_.resourceGroup -eq $RG -and $_.Type -notin $NonTypes} + $Resource1 = $Res | Group-Object -Property type | Sort-Object -Property Count -Descending + + $RGHeigh = if($Resource1.name.count -le 8){1}else{[math]::ceiling($Resource1.name.count / 8)} + + if($Counter -eq 1) + { + $RGLeft = $RGLeft + $RGWitdh + 40 + $TempHeight1 = $RGTop + ($RGHeigh*120) + 40 + if($ZCounter -eq 1) + { + $RGTop = $TempHeight2 + } + } + else + { + $RGLeft = $XLeft + 40 + $TempHeight2 = $RGTop + ($RGHeigh*120) + 40 + $RGTop = $TempHeight1 + $ZCounter = 1 + } + + if($Counter -eq 1){$Counter = 2}else{$Counter = 1} + } + + if($TempHeight1 -gt $TempHeight2){$RGTop = $TempHeight1}else{$RGTop = $TempHeight2} + + $SubHeight = $RGTop - $XTop + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($CelNum++))) + + Icon $Ret $XLeft $XTop $Witd $SubHeight 1 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $SubName) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconSubscription 30 ($XTop+$SubHeight-20) "67" "40" 1 + + $Script:XmlWriter.WriteEndElement() + + $RGLeft = $XLeft + 40 + $RGTop = $XTop + 40 + + $Counter = 1 + $ZCounter = 0 + foreach($RG in $Resource0.Name) + { + $Res = $Resource | Where-Object {$_.resourceGroup -eq $RG -and $_.subscriptionId -eq $Sub -and $_.Type -notin $NonTypes} + $Resource1 = $Res | Group-Object -Property type | Sort-Object -Property Count -Descending + + $RGWitdh = 960 + $RGHeigh = if($Resource1.name.count -le 8){1}else{[math]::ceiling($Resource1.name.count / 8)} + + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', '') + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellIDRes+'-'+($CelNum++))) + + Icon $RetRound $RGLeft $RGTop $RGWitdh ($RGHeigh*120) 1 + + $Script:XmlWriter.WriteEndElement() + + if($Counter -eq 1) + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $RG) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconRG ($XLeft+20) ($RGTop+($RGHeigh*120)-20) "37.5" "30" 1 + + $Script:XmlWriter.WriteEndElement() + + $ResTypeLeft = $RGLeft + 60 + $ResTypeTop = $RGTop + 25 + $YCounter = 1 + + foreach($res0 in $Resource1) + { + ResourceTypes $res0 $ResTypeLeft $ResTypeTop + if($YCounter -ge 8) + { + $ResTypeLeft = $RGLeft + 60 + $ResTypeTop = $ResTypeTop + 110 + $YCounter = 1 + } + else + { + $ResTypeLeft = $ResTypeLeft + 110 + $YCounter++ + } + + } + $RGLeft = $RGLeft + $RGWitdh + 40 + $TempHeight1 = $RGTop + ($RGHeigh*120) + 40 + if($ZCounter -eq 1) + { + $RGTop = $TempHeight2 + } + } + else + { + $Script:XmlWriter.WriteStartElement('object') + $Script:XmlWriter.WriteAttributeString('label', $RG) + $Script:XmlWriter.WriteAttributeString('id', ($Script:CellID+'-'+($Script:IDNum++))) + + Icon $IconRG ($RGLeft + $RGWitdh - 20) ($RGTop+($RGHeigh*120)-20) "37.5" "30" 1 + + $Script:XmlWriter.WriteEndElement() + + $ResTypeLeft = $RGLeft + 60 + $ResTypeTop = $RGTop + 25 + $YCounter = 1 + + foreach($res0 in $Resource1) + { + ResourceTypes $res0 $ResTypeLeft $ResTypeTop + if($YCounter -ge 8) + { + $ResTypeLeft = $RGLeft + 60 + $ResTypeTop = $ResTypeTop + 110 + $YCounter = 1 + } + else + { + $ResTypeLeft = $ResTypeLeft + 110 + $YCounter++ + } + + } + + $RGLeft = $XLeft + 40 + $TempHeight2 = $RGTop + ($RGHeigh*120) + 40 + $RGTop = $TempHeight1 + $ZCounter = 1 + } + + if($Counter -eq 1){$Counter = 2}else{$Counter = 1} + + } + + if($TempHeight1 -gt $TempHeight2){$RGTop = $TempHeight1}else{$RGTop = $TempHeight2} + + $XTop = $RGTop + 200 + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + + $Script:XmlWriter.WriteEndElement() + } + + $Script:XmlWriter.WriteEndDocument() + $Script:XmlWriter.Flush() + $Script:XmlWriter.Close() + + } -ArgumentList $Subscriptions,$Resources,$DiagramCache + +} \ No newline at end of file diff --git a/Modules/Diagram/ARIDrawIODiagram.psm1 b/Modules/Diagram/ARIDrawIODiagram.psm1 new file mode 100644 index 0000000..56bd315 --- /dev/null +++ b/Modules/Diagram/ARIDrawIODiagram.psm1 @@ -0,0 +1,79 @@ +<# +.Synopsis +Diagram Module for Draw.io + +.DESCRIPTION +This script process and creates a Draw.io Diagram based on resources present in the extraction variable $Resources. + +.Link +https://github.com/microsoft/ARI/Modules/Extras/DrawIODiagram.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ARIDrawIODiagram { + param($Subscriptions, $Resources, $Advisories, $DDFile, $DiagramCache, $FullEnvironment, $ResourceContainers) + + $TempPath = $DiagramCache.split("DiagramCache\")[0] + + $Logfile = ($TempPath+'DiagramLogFile.log') + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Draw.IO file') | Out-File -FilePath $LogFile -Append + + $XMLFiles = @() + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Setting XML files to be clean') | Out-File -FilePath $LogFile -Append + + $XMLFiles += ($DiagramCache+'Organization.xml') + $XMLFiles += ($DiagramCache+'Subscriptions.xml') + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Cleaning old files') | Out-File -FilePath $LogFile -Append + + foreach($File in $XMLFiles) + { + Remove-Item -Path $File -ErrorAction SilentlyContinue + } + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Organization Function') | Out-File -FilePath $LogFile -Append + + Invoke-ARIDiagramOrganization -ResourceContainers $ResourceContainers -DiagramCache $DiagramCache -LogFile $Logfile + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Network Topology Function') | Out-File -FilePath $LogFile -Append + + Invoke-ARIDiagramNetwork -Subscriptions $Subscriptions -Resources $Resources -Advisories $Advisories -DiagramCache $DiagramCache -FullEnvironment $FullEnvironment -DDFile $DDFile -XMLFiles $XMLFiles -LogFile $Logfile + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting Subscription Function') | Out-File -FilePath $LogFile -Append + + Invoke-ARIDiagramSubscription -Subscriptions $Subscriptions -Resources $Resources -DiagramCache $DiagramCache -LogFile $Logfile + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Waiting for Jobs to complete') | Out-File -FilePath $LogFile -Append + + (Get-Job | Where-Object {$_.name -like 'Diagram_*'}) | Wait-Job + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Starting to process files') | Out-File -FilePath $LogFile -Append + + foreach($File in $XMLFiles) + { + $oldxml = New-Object XML + $oldxml.Load($File) + + $newxml = New-Object XML + $newxml.Load($DDFile) + + $oldxml.DocumentElement.InsertAfter($oldxml.ImportNode($newxml.SelectSingleNode('mxfile'), $true), $afternode) + + $oldxml.Save($DDFile) + + Remove-Item -Path $File + } + + ('DrawIOCoreFile - '+(get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - Cleaning old jobs') | Out-File -FilePath $LogFile -Append + + (Get-Job | Where-Object {$_.name -like 'Diagram_*'}) | Remove-Job +} diff --git a/Extras/VisioDiagram.ps1 b/Modules/Diagram/VisioDiagram.ps1 similarity index 100% rename from Extras/VisioDiagram.ps1 rename to Modules/Diagram/VisioDiagram.ps1 diff --git a/Modules/Extras/ARIReportCharts.psm1 b/Modules/Extras/ARIReportCharts.psm1 new file mode 100644 index 0000000..8887a84 --- /dev/null +++ b/Modules/Extras/ARIReportCharts.psm1 @@ -0,0 +1,989 @@ +<# +.Synopsis +Module for Main Dashboard + +.DESCRIPTION +This script process and creates the Overview sheet. + +.Link +https://github.com/microsoft/ARI/Modules/Extras/ARIReportCharts.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Build-ARIExcelChart { + param($File, $TableStyle, $PlatOS, $Subscriptions, $ExtractionRunTime, $ReportingRunTime, $RunLite, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + $ARIMod = Get-InstalledModule -Name AzureResourceInventory + + $ScriptVersion = [string]$ARIMod.Version + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Excel Charts Customization.') + + if(!$RunLite) + { + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File + $Worksheets = $Excel.Workbook.Worksheets + + $Order = $Worksheets | Where-Object { $_.Name -notin 'Policy', 'Advisor', 'Security Center', 'Subscriptions', 'Quota Usage', 'AdvisorScore', 'Outages', 'SupportTickets', 'Reservation Advisor' } | Select-Object -Property Index, name, @{N = "Dimension"; E = { $_.dimension.Rows - 1 } } | Sort-Object -Property Dimension -Descending + + $Order0 = $Order | Where-Object { $_.Name -ne $Order[0].name -and $_.Name -ne ($Order | select-object -Last 1).Name } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Validating if Advisor and Policies are included.') + if (($Worksheets | Where-Object { $_.Name -eq 'Advisor'})) + { + $Worksheets.MoveAfter($Order[0].Name, 'Advisor') + } + if (($Worksheets | Where-Object { $_.Name -eq 'Policy'})) + { + $Worksheets.MoveAfter($Order[0].Name, 'Policy') + } + $Worksheets.MoveAfter(($Order | select-object -Last 1).Name, 'Subscriptions') + + $Loop = 0 + + + Foreach ($Ord in $Order0) { + if ($Ord.Index -and $Loop -ne 0) { + $Worksheets.MoveAfter($Ord.Name, $Order0[$Loop - 1].Name) + } + if ($Loop -eq 0) { + $Worksheets.MoveAfter($Ord.Name, $Order[0].Name) + } + $Loop++ + } + + $Excel.Save() + $Excel.Dispose() + } + + "" | Export-Excel -Path $File -WorksheetName 'Overview' -MoveToStart + + if($RunLite) + { + $excel = Open-ExcelPackage -Path $file -KillExcel + } + else + { + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File + } + $Worksheets = $Excel.Workbook.Worksheets + $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } + + $WS.SetValue(75,70,'') + $WS.SetValue(76,70,'') + $WS.View.ShowGridLines = $false + + if($RunLite) + { + Close-ExcelPackage $excel + } + else + { + $Excel.Save() + $Excel.Dispose() + } + + $TableStyleEx = if($PlatOS -eq 'PowerShell Desktop'){'Medium1'}else{$TableStyle} + $TableStyle = if($PlatOS -eq 'PowerShell Desktop'){'Medium15'}else{$TableStyle} + #$TableStyle = 'Medium22' + $Font = 'Segoe UI' + + if($RunLite) + { + $excel = Open-ExcelPackage -Path $file -KillExcel + } + else + { + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File + } + $Worksheets = $Excel.Workbook.Worksheets | Where-Object { $_.name -notin 'Overview', 'Advisor', 'Policy', 'Security Center'} + $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } + + $TabDraw = $WS.Drawings.AddShape('TP00', 'RoundRect') + $TabDraw.SetSize(130 , 78) + $TabDraw.SetPosition(1, 0, 0, 0) + $TabDraw.TextAlignment = 'Center' + + $Table = @() + $TotalRes = 0 + Foreach ($WorkS in $Worksheets) { + $Number = $WorkS.Tables.Name.split('_') + $tmp = @{ + 'Name' = $WorkS.name; + 'Size' = [int]$Number[1]; + 'Size2' = if ($WorkS.name -in ('Subscriptions', 'Quota Usage', 'AdvisorScore', 'Outages', 'SupportTickets', 'Reservation Advisor')) {0}else{[int]$Number[1]} + } + $TotalRes = $TotalRes + ([int]$Number[1]) + $Table += $tmp + } + + if($RunLite) + { + Close-ExcelPackage $excel + } + else + { + $Excel.Save() + $Excel.Dispose() + } + + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 + + $Table | + ForEach-Object { [PSCustomObject]$_ } | Sort-Object -Property 'Size2' -Descending | + Select-Object -Unique 'Name', + 'Size' | Export-Excel -Path $File -WorksheetName 'Overview' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzureTabs' -TableStyle $TableStyleEx -Style $Style -StartRow 6 -StartColumn 1 + + $Date = (get-date -Format "MM/dd/yyyy") + + $ExtractTime = if($ExtractionRunTime.Totalminutes -lt 1){($ExtractionRunTime.Seconds.ToString()+' Seconds')}else{($ExtractionRunTime.Totalminutes.ToString('#######.##')+' Minutes')} + $ReportTime = ($ReportingRunTime.Totalminutes.ToString('#######.##')+' Minutes') + + $User = (get-azcontext -WarningAction SilentlyContinue -InformationAction SilentlyContinue | Select-Object -Property Account -Unique).Account.Id + + + #$TotalRes = $TotalResources + + if($RunLite) + { + $excel = Open-ExcelPackage -Path $file -KillExcel + } + else + { + $Excel = New-Object -TypeName OfficeOpenXml.ExcelPackage $File + } + $Worksheets = $Excel.Workbook.Worksheets + $WS = $Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Overview' } + + $cell = $WS.Cells | Where-Object {$_.Address -like 'A*' -and $_.Address -notin 'A1','A2','A3','A4','A5','A6'} + foreach ($item in $cell) { + $Works = $Item.Text + $Link = New-Object -TypeName OfficeOpenXml.ExcelHyperLink ("'"+$Works+"'"+'!A1'),$Works + $Item.Hyperlink = $Link + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Creating Overall Panel.') + $Egg = $WS.Cells | Where-Object {$_.Address -eq 'BR75'} + $Egg.AddComment('Created with a lot of effort and hard work, we hope you enjoy it.','.') | Out-Null + $Egg = $WS.Cells | Where-Object {$_.Address -eq 'BR76'} + $Egg.AddComment('By: Claudio Merola and Renato Gregio','.') | Out-Null + + $TabDraw = $WS.Drawings.AddShape('TP0', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 52, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP1', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 55, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP2', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 58, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP3', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 61, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP4', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 64, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP5', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 67, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP6', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 70, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP7', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 73, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP8', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 76, 0) + $TabDraw.TextAlignment = 'Center' + + $TabDraw = $WS.Drawings.AddShape('TP9', 'RoundRect') + $TabDraw.SetSize(125, 25) + $TabDraw.SetPosition(0, 10, 79, 0) + $TabDraw.TextAlignment = 'Center' + + $Draw = $WS.Drawings.AddShape('ARI', 'RoundRect') + $Draw.SetSize(445, 240) + $Draw.SetPosition(1, 0, 2, 5) + + $txt = $Draw.RichText.Add('Azure Resource Inventory v' + $ScriptVersion + "`n") + $txt.Size = 14 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('https://github.com/microsoft/ARI' + "`n" + "`n") + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('Report Date: ') + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add($Date + "`n") + $txt.Size = 12 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('Extraction Time: ') + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add($ExtractTime + "`n") + $txt.Size = 12 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('Reporting Time: ') + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add($ReportTime + "`n") + $txt.Size = 12 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('User Session: ') + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add($User + "`n") + $txt.Size = 12 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add('Environment: ') + $txt.Size = 11 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $txt = $Draw.RichText.Add($PlatOS) + $txt.Size = 12 + $txt.ComplexFont = $Font + $txt.LatinFont = $Font + + $Draw.TextAlignment = 'Center' + + $RGD = $WS.Drawings.AddShape('RGs', 'RoundRect') + $RGD.SetSize(124, 115) + $RGD.SetPosition(21, 5, 9, 5) + $RGD.TextAlignment = 'Center' + $RGD.RichText.Add('Total Resources' + "`n").Size = 12 + $RGD.RichText.Add($TotalRes).Size = 22 + + $DrawP00 = $WS.Drawings | Where-Object { $_.Name -eq 'TP00' } + $P00Name = 'Reported Resources' + $DrawP00.RichText.Add($P00Name).Size = 16 + + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Reservation Advisor' }) { + $P00Name = 'Reservation Advisor' + } + else + { + $P00Name = 'Resources' + } + $DrawP0 = $WS.Drawings | Where-Object { $_.Name -eq 'TP0' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Outages' }) { + $P0Name = 'Outages' + } + elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisor' }) { + $P0Name = 'Advisories' + } + else { + $P0Name = 'Public IPs' + } + $DrawP0.RichText.Add($P0Name) | Out-Null + + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'AdvisorScore' }) { + $P1Name = 'AdvisorScore' + } + elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Subscriptions' }) { + $P1Name = 'Subscriptions' + } + $DrawP1 = $WS.Drawings | Where-Object { $_.Name -eq 'TP1' } + $DrawP1.RichText.Add($P1Name) | Out-Null + + $DrawP2 = $WS.Drawings | Where-Object { $_.Name -eq 'TP2' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Policy' }) { + $P2Name = 'Policy' + } + elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisor' }) { + $P2Name = 'Annual Savings' + } + else { + $P2Name = 'Virtual Networks' + } + + $DrawP2.RichText.Add($P2Name) | Out-Null + + $DrawP3 = $WS.Drawings | Where-Object { $_.Name -eq 'TP3' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'SupportTickets' }) { + $P3Name = 'SupportTickets' + } + elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'AKS' }) { + $P3Name = 'Azure Kubernetes' + } + else { + $P3Name = 'Storage Accounts' + } + $DrawP3.RichText.Add($P3Name) | Out-Null + + $DrawP4 = $WS.Drawings | Where-Object { $_.Name -eq 'TP4' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Outages' }) { + $P4Name = 'Outages' + } + elseif ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Quota Usage' }) { + $P4Name = 'Quota Usage' + } + else { + $P4Name = 'VM Disks' + } + $DrawP4.RichText.Add($P4Name) | Out-Null + + $DrawP5 = $WS.Drawings | Where-Object { $_.Name -eq 'TP5' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { + $P5Name = 'Virtual Machines' + } + $DrawP5.RichText.Add($P5Name) | Out-Null + + $DrawP6 = $WS.Drawings | Where-Object { $_.Name -eq 'TP6' } + $P6Name = 'Resources by Location' + $DrawP6.RichText.Add($P6Name) | Out-Null + + $DrawP7 = $WS.Drawings | Where-Object { $_.Name -eq 'TP7' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { + $P7Name = 'Virtual Machines' + } + $DrawP7.RichText.Add($P7Name) | Out-Null + + $DrawP8 = $WS.Drawings | Where-Object { $_.Name -eq 'TP8' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Advisor' }) { + $P8Name = 'Advisories' + } + $DrawP8.RichText.Add($P8Name) | Out-Null + + $DrawP9 = $WS.Drawings | Where-Object { $_.Name -eq 'TP9' } + if ($Excel.Workbook.Worksheets | Where-Object { $_.Name -eq 'Virtual Machines' }) { + $P9Name = 'Virtual Machines' + } + $DrawP9.RichText.Add($P9Name) | Out-Null + + if($RunLite) + { + Close-ExcelPackage $excel + } + else + { + $Excel.Save() + $Excel.Dispose() + } + + $excel = Open-ExcelPackage -Path $file -KillExcel + + if ($P00Name -eq 'Reservation Advisor') + { + $PTParams = @{ + PivotTableName = "P00" + Address = $excel.Overview.cells["CV5"] # top-left corner of the table + SourceWorkSheet = $excel.'Reservation Advisor' + PivotRows = @("Subscription") + PivotData = @{"Net Savings" = "Sum" } + PivotColumns = @("Instance Flexibility Group") + PivotTableStyle = $TableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 1 # place the chart below row 22nd + ChartColumn = 9 + Activate = $true + PivotNumberFormat = '$#' + PivotFilter = 'Recommended Size' + PivotTotals = 'Both' + ShowCategory = $false + NoLegend = $true + ChartTitle = 'Potential Net Savings (VM Reservation)' + ShowPercent = $true + ChartHeight = 400 + ChartWidth = 950 + ChartRowOffSetPixels = 0 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams + } + else + { + Add-ExcelChart -Worksheet $excel.Overview -ChartType Area3D -XRange "AzureTabs[Name]" -YRange "AzureTabs[Size]" -SeriesHeader 'Resources', 'Count' -Column 9 -Row 1 -Height 400 -Width 950 -RowOffSetPixels 0 -ColumnOffSetPixels 5 -NoLegend + } + + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Creating Charts.') + + if ($P0Name -eq 'Outages') { + $PTParams = @{ + PivotTableName = "P0" + Address = $excel.Overview.cells["BA5"] # top-left corner of the table + SourceWorkSheet = $excel.'Outages' + PivotRows = @("Impacted Services") + PivotData = @{"Impacted Services" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarStacked3D" + ChartRow = 13 # place the chart below row 22nd + ChartColumn = 2 + Activate = $true + PivotFilter = 'Subscription' + ChartTitle = 'Outages (Last 6 Months)' + ShowPercent = $true + ChartHeight = 275 + ChartWidth = 445 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams -NoLegend + } + elseif ($P0Name -eq 'Advisories') { + $PTParams = @{ + PivotTableName = "P0" + Address = $excel.Overview.cells["BA5"] # top-left corner of the table + SourceWorkSheet = $excel.Advisor + PivotRows = @("Category") + PivotData = @{"Category" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarStacked3D" + ChartRow = 13 # place the chart below row 22nd + ChartColumn = 2 + Activate = $true + PivotFilter = 'Impact' + ChartTitle = 'Advisor' + ShowPercent = $true + ChartHeight = 275 + ChartWidth = 445 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams -NoLegend + } + else { + $PTParams = @{ + PivotTableName = "P0" + Address = $excel.Overview.cells["BA5"] # top-left corner of the table + SourceWorkSheet = $excel.'Public IPs' + PivotRows = @("Use") + PivotData = @{"Use" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarStacked3D" + ChartRow = 13 # place the chart below row 22nd + ChartColumn = 2 + Activate = $true + PivotFilter = 'location' + ChartTitle = 'Public IPs' + ShowPercent = $true + ChartHeight = 275 + ChartWidth = 445 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams -NoLegend + } + + if ($P1Name -eq 'AdvisorScore') { + $PTParams = @{ + PivotTableName = "P1" + Address = $excel.Overview.cells["BD6"] # top-left corner of the table + SourceWorkSheet = $excel.AdvisorScore + PivotRows = @("Category") + PivotData = @{"Latest Score (%)" = "average" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarClustered" + ChartRow = 27 # place the chart below row 22nd + ChartColumn = 2 + Activate = $true + #PivotNumberFormat = '0' + ShowCategory = $false + PivotFilter = 'Subscription' + ChartTitle = 'Advisor Score (%)' + NoLegend = $true + ShowPercent = $true + ChartHeight = 655 + ChartWidth = 570 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams + + } + else + { + $PTParams = @{ + PivotTableName = "P1" + Address = $excel.Overview.cells["BD6"] # top-left corner of the table + SourceWorkSheet = $excel.Subscriptions + PivotRows = @("Subscription") + PivotData = @{"Resources" = "sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarClustered" + ChartRow = 27 # place the chart below row 22nd + ChartColumn = 2 + Activate = $true + PivotFilter = 'Resource Group', 'Resource Type' + ChartTitle = 'Resources by Subscription' + NoLegend = $true + ShowPercent = $true + ChartHeight = 655 + ChartWidth = 570 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams + } + + if ($P2Name -eq 'Policy') { + $PTParams = @{ + PivotTableName = "P2" + Address = $excel.Overview.cells["BG5"] # top-left corner of the table + SourceWorkSheet = $excel.Policy + PivotRows = @("Policy Category") + PivotData = @{"Policy" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 21 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'Policy Type' + ChartTitle = 'Policies by Category' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams -NoLegend + } + elseif ($P2Name -eq 'Annual Savings') { + $PTParams = @{ + PivotTableName = "P2" + Address = $excel.Overview.cells["BG5"] # top-left corner of the table + SourceWorkSheet = $excel.Advisor + PivotRows = @("Savings Currency") + PivotData = @{"Annual Savings" = "Sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 21 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + ChartTitle = 'Potential Savings' + PivotFilter = 'Savings Region' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + PivotNumberFormat = '#,##0.00' + } + Add-PivotTable @PTParams -NoLegend + } + else { + $PTParams = @{ + PivotTableName = "P2" + Address = $excel.Overview.cells["BG5"] # top-left corner of the table + SourceWorkSheet = $excel.'Virtual Networks' + PivotRows = @("Location") + PivotData = @{"Location" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 21 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + ChartTitle = 'Virtual Networks' + PivotFilter = 'Subscription' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams -NoLegend + } + + if ($P3Name -eq 'SupportTickets') { + $PTParams = @{ + PivotTableName = "P3" + Address = $excel.Overview.cells["BJ5"] # top-left corner of the table + SourceWorkSheet = $excel.SupportTickets + PivotRows = @("Status") + PivotData = @{"Status" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "Pie3D" + ChartRow = 34 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'Current Severity' + ChartTitle = 'Support Tickets' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams + } + elseif ($P3Name -eq 'Azure Kubernetes') { + $PTParams = @{ + PivotTableName = "P3" + Address = $excel.Overview.cells["BJ5"] # top-left corner of the table + SourceWorkSheet = $excel.AKS + PivotRows = @("Kubernetes Version") + PivotData = @{"Clusters" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "Pie3D" + ChartRow = 34 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + ChartTitle = 'AKS Versions' + PivotFilter = 'Node Pool Size' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams + } + else { + $PTParams = @{ + PivotTableName = "P3" + Address = $excel.Overview.cells["BJ5"] # top-left corner of the table + SourceWorkSheet = $excel.'Storage Acc' + PivotRows = @("Tier") + PivotData = @{"Tier" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "Pie3D" + ChartRow = 34 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'SKU' + ChartTitle = 'Storage Accounts' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams + } + + if ($P4Name -eq 'Outages') { + $PTParams = @{ + PivotTableName = "P4" + Address = $excel.Overview.cells["BM5"] # top-left corner of the table + SourceWorkSheet = $excel.'Outages' + PivotRows = @("Subscription") + PivotData = @{"Outage ID" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 47 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'Event Level' + ChartTitle = 'Outages per Subscription' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams -NoLegend + } + elseif ($P4Name -eq 'Quota Usage') { + $PTParams = @{ + PivotTableName = "P4" + Address = $excel.Overview.cells["BM5"] # top-left corner of the table + SourceWorkSheet = $excel.'Quota Usage' + PivotRows = @("Region") + PivotData = @{"vCPUs Available" = "Sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 47 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'Limit' + ChartTitle = 'Available Quota (vCPUs)' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + Add-PivotTable @PTParams -NoLegend + } + else { + $PTParams = @{ + PivotTableName = "P4" + Address = $excel.Overview.cells["BM5"] # top-left corner of the table + SourceWorkSheet = $excel.Disks + PivotRows = @("Disk State") + PivotData = @{"Disk State" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 47 # place the chart below row 22nd + ChartColumn = 11 + Activate = $true + PivotFilter = 'SKU' + ChartTitle = 'VM Disks' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams -NoLegend + } + + if ($P5Name -eq 'Virtual Machines') { + $PTParams = @{ + PivotTableName = "P5" + Address = $excel.Overview.cells["BP7"] # top-left corner of the table + SourceWorkSheet = $excel.'Virtual Machines' + PivotRows = @("VM Size") + PivotData = @{"Resource U" = "Sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarClustered" + ChartRow = 21 # place the chart below row 22nd + ChartColumn = 16 + Activate = $true + NoLegend = $true + ChartTitle = 'Virtual Machines by Serie' + PivotFilter = 'OS Type', 'Location', 'Power State' + ShowPercent = $true + ChartHeight = 775 + ChartWidth = 502 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 5 + } + + Add-PivotTable @PTParams + } + + $PTParams = @{ + PivotTableName = "P6" + Address = $excel.Overview.cells["BS5"] # top-left corner of the table + SourceWorkSheet = $excel.Subscriptions + PivotRows = @("Location") + PivotData = @{"Resources" = "sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "ColumnStacked3D" + ChartRow = 1 # place the chart below row 22nd + ChartColumn = 24 + Activate = $true + PivotFilter = 'Resource Type' + ChartTitle = 'Resources by Location' + NoLegend = $true + ShowPercent = $true + ChartHeight = 400 + ChartWidth = 315 + ChartRowOffSetPixels = 0 + ChartColumnOffSetPixels = 0 + } + + Add-PivotTable @PTParams + + if ($P7Name -eq 'Virtual Machines') { + $PTParams = @{ + PivotTableName = "P7" + Address = $excel.Overview.cells["BV5"] # top-left corner of the table + SourceWorkSheet = $excel.'Virtual Machines' + PivotRows = @("OS Type") + PivotData = @{"Resource U" = "Sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "Pie3D" + ChartRow = 21 # place the chart below row 22nd + ChartColumn = 24 + Activate = $true + NoLegend = $true + ChartTitle = 'VMs by OS' + PivotFilter = 'Location' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 0 + } + + Add-PivotTable @PTParams + } + + if ($P8Name -eq 'Advisories') { + $PTParams = @{ + PivotTableName = "P8" + Address = $excel.Overview.cells["BY5"] # top-left corner of the table + SourceWorkSheet = $excel.Advisor + PivotRows = @("Impact") + PivotData = @{"Impact" = "Count" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "BarStacked3D" + ChartRow = 34 + ChartColumn = 24 + Activate = $true + PivotFilter = 'Category' + ChartTitle = 'Advisor' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 0 + } + Add-PivotTable @PTParams -NoLegend + } + + if ($P9Name -eq 'Virtual Machines') { + $PTParams = @{ + PivotTableName = "P9" + Address = $excel.Overview.cells["CB5"] # top-left corner of the table + SourceWorkSheet = $excel.'Virtual Machines' + PivotRows = @("Boot Diagnostics") + PivotData = @{"Resource U" = "Sum" } + PivotTableStyle = $tableStyle + IncludePivotChart = $true + ChartType = "Pie3D" + ChartRow = 47 + ChartColumn = 24 + Activate = $true + NoLegend = $true + ChartTitle = 'Boot Diagnostics' + PivotFilter = 'Location' + ShowPercent = $true + ChartHeight = 255 + ChartWidth = 315 + ChartRowOffSetPixels = 5 + ChartColumnOffSetPixels = 0 + } + + Add-PivotTable @PTParams + } + + Close-ExcelPackage $excel + + if(!$RunLite) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Validating if Excel is installed (Extra Customizations).') + $application = New-Object -ComObject Excel.Application + if ($application) { + $Ex = $application.Workbooks.Open($File) + Start-Sleep -Seconds 2 + $WS = $ex.Worksheets | Where-Object { $_.Name -eq 'Overview' } + + foreach ($Sheet in ($Ex.Worksheets | Where-Object {$_.Name -in ('Policy', 'Advisor', 'Security Center', 'Subscriptions', 'Quota Usage', 'AdvisorScore', 'Outages', 'SupportTickets', 'Reservation Advisor')})) + { + $Sheet.tab.ColorIndex = 55 + Start-Sleep -Milliseconds 50 + } + + $NoChangeChart = ('ChartP0', 'ChartP1', 'ChartP2', 'ChartP3', 'ChartP4', 'ChartP5', 'ChartP6', 'ChartP7', 'ChartP8', 'ChartP9', 'ARI', 'RGs', 'TP00', 'TP0', 'TP1', 'TP2', 'TP3', 'TP4', 'TP5','TP6','TP7','TP8','TP9') + $ChangeChart = ('ARI', 'RGs', 'TP00', 'TP0', 'TP1', 'TP2', 'TP3', 'TP4', 'TP5', 'TP6', 'TP7','TP8','TP9') + + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartStyle = 294 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartStyle = 222 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP2' }).DrawingObject.Chart.ChartStyle = 294 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP3' }).DrawingObject.Chart.ChartStyle = 268 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP4' }).DrawingObject.Chart.ChartStyle = 294 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP5' }).DrawingObject.Chart.ChartStyle = 222 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP6' }).DrawingObject.Chart.ChartStyle = 294 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP7' }).DrawingObject.Chart.ChartStyle = 268 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP8' }).DrawingObject.Chart.ChartStyle = 294 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -eq 'ChartP9' }).DrawingObject.Chart.ChartStyle = 268 + Start-Sleep -Milliseconds 50 + ($WS.Shapes | Where-Object { $_.name -notin $NoChangeChart -and $_.name -like 'Chart*' }).DrawingObject.Chart.ChartStyle = 315 + Start-Sleep -Milliseconds 50 + + Foreach ($Changer in $ChangeChart) { + ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.interior.color = 2500134 + ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.color = 16777215 + ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.ColorIndex = -4142 + ($WS.Shapes | Where-Object { $_.name -eq $Changer }).DrawingObject.border.LineStyle = -4142 + Start-Sleep -Milliseconds 50 + } + + foreach ($Sheet in ($Ex.Worksheets | Where-Object {$_.Name -notin ('Overview', 'Policy', 'Advisor', 'Security Center', 'Subscriptions', 'Quota Usage', 'AdvisorScore', 'Outages', 'SupportTickets', 'Reservation Advisor')})) + { + $Sheet.tab.ColorIndex = 48 + Start-Sleep -Milliseconds 50 + } + + #$WS.Cells.Interior.Color = 0 + + $Draw = ($WS.Shapes | Where-Object {$_.name -eq 'ARI'}) + $Draw.Adjustments(1) = 0.07 + Start-Sleep -Milliseconds 50 + + $Ex.Save() + $Ex.Close() + $application.Quit() + Get-Process -Name "excel" -ErrorAction Ignore | Stop-Process + } + } +} \ No newline at end of file diff --git a/Extras/Module-template.tpl b/Modules/Extras/Module-template.tpl similarity index 100% rename from Extras/Module-template.tpl rename to Modules/Extras/Module-template.tpl diff --git a/Extras/Support.json b/Modules/Extras/Support.json similarity index 100% rename from Extras/Support.json rename to Modules/Extras/Support.json diff --git a/Modules/Inventory/ARIAPIInv.psm1 b/Modules/Inventory/ARIAPIInv.psm1 new file mode 100644 index 0000000..d27ff57 --- /dev/null +++ b/Modules/Inventory/ARIAPIInv.psm1 @@ -0,0 +1,154 @@ +function Get-ARIAPIResources { + Param($Subscriptions, $AzureEnvironment, $SkipPolicy, $Debug ) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting API Inventory') + + $Token = Get-AzAccessToken -AsSecureString -InformationAction SilentlyContinue -WarningAction SilentlyContinue + + $TokenData = $Token.Token | ConvertFrom-SecureString -AsPlainText + + $header = @{ + 'Authorization' = 'Bearer ' + $TokenData + } + + if ($AzureEnvironment -eq 'AzureCloud') { + $AzURL = 'management.azure.com' + } else { + $AzURL = 'management.usgovcloudapi.net' + } + $ResourceHealthHistoryDate = (Get-Date).AddMonths(-6) + $APIResults = @() + + foreach ($Subscription in $Subscriptions) + { + $ResourceHealth = "" + $SupTickets = "" + $Identities = "" + $ADVScore = "" + $ReservationRecon = "" + $PolicyAssign = "" + $PolicySetDef = "" + $PolicyDef = "" + + $SubName = $Subscription.Name + $Sub = $Subscription.id + + Write-Host 'Running API Inventory at: ' -NoNewline + Write-Host $SubName -ForegroundColor Cyan + + #ResourceHealth Events + $url = ('https://' + $AzURL + '/subscriptions/' + $Sub + '/providers/Microsoft.ResourceHealth/events?api-version=2022-10-01&queryStartTime=' + $ResourceHealthHistoryDate) + try { + $ResourceHealth = Invoke-RestMethod -Uri $url -Headers $header -Method GET + } + catch { + $ResourceHealth = "" + } + + Start-Sleep -Milliseconds 200 + + #Support Tickets + $url = ('https://' + $AzURL + '/subscriptions/' + $Sub + '/providers/Microsoft.Support/supportTickets?api-version=2020-04-01') + try { + $SupTickets = Invoke-RestMethod -Uri $url -Headers $header -Method GET + } + catch { + $SupTickets = "" + } + Start-Sleep -Milliseconds 200 + + #Managed Identities + $url = ('https://' + $AzURL + '/subscriptions/' + $Sub + '/providers/Microsoft.ManagedIdentity/userAssignedIdentities?api-version=2023-01-31') + try { + $Identities = Invoke-RestMethod -Uri $url -Headers $header -Method GET + } + catch { + $Identities = "" + } + Start-Sleep -Milliseconds 200 + + #Advisor Score + $url = ('https://' + $AzURL + '/subscriptions/' + $Sub + '/providers/Microsoft.Advisor/advisorScore?api-version=2023-01-01') + try { + $ADVScore = Invoke-RestMethod -Uri $url -Headers $header -Method GET + } + catch { + $ADVScore = "" + } + Start-Sleep -Milliseconds 200 + + #VM Reservation Recomentation + $url = ('https://' + $AzURL + '/subscriptions/' + $Sub + '/providers/Microsoft.Consumption/reservationRecommendations?api-version=2023-05-01') + try { + $ReservationRecon = Invoke-RestMethod -Uri $url -Headers $header -Method GET + } + catch { + $ReservationRecon = "" + } + Start-Sleep -Milliseconds 200 + + if (!$SkipPolicy.isPresent) + { + #Policies + try { + $url = ('https://'+ $AzURL +'/subscriptions/'+$sub+'/providers/Microsoft.PolicyInsights/policyStates/latest/summarize?api-version=2019-10-01') + $PolicyAssign = (Invoke-RestMethod -Uri $url -Headers $header -Method POST).value + Start-Sleep -Milliseconds 200 + $url = ('https://'+ $AzURL +'/subscriptions/'+$sub+'/providers/Microsoft.Authorization/policySetDefinitions?api-version=2023-04-01') + $PolicySetDef = (Invoke-RestMethod -Uri $url -Headers $header -Method GET).value + Start-Sleep -Milliseconds 200 + $url = ('https://'+ $AzURL +'/subscriptions/'+$sub+'/providers/Microsoft.Authorization/policyDefinitions?api-version=2023-04-01') + $PolicyDef = (Invoke-RestMethod -Uri $url -Headers $header -Method GET).value + } + catch { + $PolicyAssign = "" + $PolicySetDef = "" + $PolicyDef = "" + } + } + + Start-Sleep 1 + + $tmp = @{ + 'Subscription' = $Sub; + 'ResourceHealth' = $ResourceHealth.value; + 'SupportTickets' = $SupTickets.value; + 'ManagedIdentities' = $Identities.value; + 'AdvisorScore' = $ADVScore.value; + 'ReservationRecomen' = $ReservationRecon.value; + 'PolicyAssign' = $PolicyAssign; + 'PolicyDef' = $PolicyDef; + 'PolicySetDef' = $PolicySetDef + } + $APIResults += $tmp + + } + + <# + $Body = @{ + reportType = "OverallSummaryReport" + subscriptionList = @($Subscri) + carbonScopeList = @("Scope1") + dateRange = @{ + start = "2024-06-01" + end = "2024-06-30" + } + } + $url = 'https://management.azure.com/providers/Microsoft.Carbon/carbonEmissionReports?api-version=2023-04-01-preview' + #$url = 'https://management.azure.com/providers/Microsoft.Carbon/queryCarbonEmissionDataAvailableDateRange?api-version=2023-04-01-preview' + + $Carbon = Invoke-RestMethod -Uri $url -Headers $header -Body ($Body | ConvertTo-Json) -Method POST -ContentType 'application/json' + + #> + + return $APIResults +} \ No newline at end of file diff --git a/Modules/Inventory/ARIAdvisoryInv.psm1 b/Modules/Inventory/ARIAdvisoryInv.psm1 new file mode 100644 index 0000000..12d2fc3 --- /dev/null +++ b/Modules/Inventory/ARIAdvisoryInv.psm1 @@ -0,0 +1,71 @@ +<# +.Synopsis +Advisory Module + +.DESCRIPTION +This script process and creates the Advisory sheet based on advisorresources. + +.Link +https://github.com/microsoft/ARI/Extras/ARIAdvisoryInv.psm1 + +.COMPONENT + This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ARIAdvisoryProcessing { + param($Advisories) + + $tmp = foreach ($1 in $Advisories) + { + $data = $1.PROPERTIES + $Savings = if([string]::IsNullOrEmpty($data.extendedProperties.annualSavingsAmount)){0}Else{$data.extendedProperties.annualSavingsAmount} + $SavingsCurrency = if([string]::IsNullOrEmpty($data.extendedProperties.savingsCurrency)){'USD'}Else{$data.extendedProperties.savingsCurrency} + $obj = @{ + 'ResourceGroup' = $1.RESOURCEGROUP; + 'Affected Resource Type' = $data.impactedField; + 'Name' = $data.impactedValue; + 'Category' = $data.category; + 'Impact' = $data.impact; + #'Score' = $data.extendedproperties.score; + 'Problem' = $data.shortDescription.problem; + 'Savings Currency' = $SavingsCurrency; + 'Annual Savings' = "=$Savings"; + 'Savings Region' = $data.extendedProperties.location; + 'Current SKU' = $data.extendedProperties.currentSku; + 'Target SKU' = $data.extendedProperties.targetSku + } + $obj + } + $tmp +} + +function Build-ARIAdvisoryReport { + param($File, $Adv, $TableStyle) + $condtxtadv = @() + $condtxtadv += New-ConditionalText High -Range E:E + $condtxtadv += New-ConditionalText Security -Range D:D -BackgroundColor Wheat + + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '#,##0.00' -Range H:H + + $Adv | + ForEach-Object { [PSCustomObject]$_ } | + Select-Object 'ResourceGroup', + 'Affected Resource Type', + 'Name', + 'Category', + 'Impact', + #'Score', + 'Problem', + 'Savings Currency', + 'Annual Savings', + 'Savings Region', + 'Current SKU', + 'Target SKU' | + Export-Excel -Path $File -WorksheetName 'Advisor' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzureAdvisory' -MoveToStart -TableStyle $tableStyle -Style $Style -ConditionalText $condtxtadv +} + diff --git a/Modules/Inventory/ARIMGMTGroups.psm1 b/Modules/Inventory/ARIMGMTGroups.psm1 new file mode 100644 index 0000000..a4f6502 --- /dev/null +++ b/Modules/Inventory/ARIMGMTGroups.psm1 @@ -0,0 +1,57 @@ +function Get-ARIManagementGroups { + Param ($ManagementGroup, $Debug) + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Management group name supplied: ' + $ManagmentGroupName) + $group = az account management-group entities list --query "[?name =='$ManagementGroup']" | ConvertFrom-Json + if ($group.Count -lt 1) + { + Write-Host "ERROR:" -NoNewline -ForegroundColor Red + Write-Host "Management Group $ManagementGroup not found!" + Write-Host "" + Write-Host "Please check the Management Group name and try again." + Write-Host "" + Exit + } + else + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Management groups found: ' + $group.count) + foreach ($item in $group) + { + $Subscriptions = @() + $GraphQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$($item.name)' | summarize count()" + $EnvSize = az graph query -q $GraphQuery --output json --only-show-errors | ConvertFrom-Json + $EnvSizeNum = $EnvSize.data.'count_' + + if ($EnvSizeNum -ge 1) { + $Loop = $EnvSizeNum / 1000 + $Loop = [math]::ceiling($Loop) + $Looper = 0 + $Limit = 0 + + while ($Looper -lt $Loop) { + $GraphQuery = "resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$($item.name)' | project id = subscriptionId" + $Resource = (az graph query -q $GraphQuery --skip $Limit --first 1000 --output json --only-show-errors).tolower() | ConvertFrom-Json + + foreach ($Sub in $Resource.data) { + $Subscriptions += az account show --subscription $Sub.id --output json --only-show-errors | ConvertFrom-Json + } + + Start-Sleep 2 + $Looper ++ + Write-Progress -Id 1 -activity "Running Subscription Inventory Job" -Status "$Looper / $Loop of Subscription Jobs" -PercentComplete (($Looper / $Loop) * 100) + $Limit = $Limit + 1000 + } + } + Write-Progress -Id 1 -activity "Running Subscription Inventory Job" -Status "$Looper / $Loop of Subscription Jobs" -Completed + } + } + return $Subscriptions +} \ No newline at end of file diff --git a/Modules/Inventory/ARIPolicyInv.psm1 b/Modules/Inventory/ARIPolicyInv.psm1 new file mode 100644 index 0000000..4c4622a --- /dev/null +++ b/Modules/Inventory/ARIPolicyInv.psm1 @@ -0,0 +1,104 @@ +<# +.Synopsis +Policy Module + +.DESCRIPTION +This script process and creates the Policy sheet based on advisorresources. + +.Link +https://github.com/microsoft/ARI/Extras/ARIPolicyInv.psm1 + +.COMPONENT + This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.2 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ARIPolicyProcessing { + param($Subscriptions, $PolicySetDef, $PolicyAssign, $PolicyDef) + + $poltmp = $PolicyDef | Select-Object -Property id,properties -Unique + + $tmp = foreach ($1 in $PolicyAssign.policyAssignments) + { + if(![string]::IsNullOrEmpty($1.policySetDefinitionId)) + { + $Initiative = (($PolicySetDef | Where-Object {$_.id -eq $1.policySetDefinitionId}).properties.displayName | Select-Object -Unique ) + $InitNonCompRes = $1.results.nonCompliantResources + $InitNonCompPol = $1.results.nonCompliantPolicies + } + else + { + $Initiative = '' + $InitNonCompRes = '' + $InitNonCompPol = '' + } + + foreach ($2 in $1.policyDefinitions) + { + $Pol = (($poltmp | Where-Object {$_.id -eq $2.policyDefinitionId}).properties) + if(![string]::IsNullOrEmpty($Pol)) + { + $PolMode + $PolResUnkown = ($2.results.resourceDetails | Where-Object {$_.complianceState -eq 'unknown'} | Select-Object -ExpandProperty Count) + $PolResUnkown = if (![string]::IsNullOrEmpty($PolResUnkown)){$PolResUnkown}else{'0'} + $PolResCompl = ($2.results.resourceDetails | Where-Object {$_.complianceState -eq 'compliant'} | Select-Object -ExpandProperty Count) + $PolResCompl = if (![string]::IsNullOrEmpty($PolResCompl)){$PolResCompl}else{'0'} + $PolResNonCompl = ($2.results.resourceDetails | Where-Object {$_.complianceState -eq 'noncompliant'} | Select-Object -ExpandProperty Count) + $PolResNonCompl = if (![string]::IsNullOrEmpty($PolResNonCompl)){$PolResNonCompl}else{'0'} + $PolResExemp = ($2.results.resourceDetails | Where-Object {$_.complianceState -eq 'exempt'} | Select-Object -ExpandProperty Count) + $PolResExemp = if (![string]::IsNullOrEmpty($PolResExemp)){$PolResExemp}else{'0'} + + $obj = @{ + 'Initiative' = $Initiative; + 'Initiative Non Compliance Resources' = $InitNonCompRes; + 'Initiative Non Compliance Policies' = $InitNonCompPol; + 'Policy' = $Pol.displayName; + 'Policy Type' = $Pol.policyType; + 'Effect' = $2.effect; + 'Compliance Resources' = $PolResCompl; + 'Non Compliance Resources' = $PolResNonCompl; + 'Unknown Resources' = $PolResUnkown; + 'Exempt Resources' = $PolResExemp + 'Policy Mode' = $Pol.mode; + 'Policy Version' = $Pol.version; + 'Policy Deprecated' = $Pol.metadata.deprecated; + 'Policy Category' = $Pol.metadata.category + } + $obj + } + } + } + $tmp +} + +function Build-ARIPolicyReport { + param($File ,$Pol, $TableStyle) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 + + $condtxt = @() + $condtxt += New-ConditionalText -Range B2:B500 -ConditionalType GreaterThan 0 + $condtxt += New-ConditionalText -Range C2:C500 -ConditionalType GreaterThan 0 + $condtxt += New-ConditionalText -Range H2:H500 -ConditionalType GreaterThan 0 + + $Pol | + ForEach-Object { [PSCustomObject]$_ } | + Select-Object 'Initiative', + 'Initiative Non Compliance Resources', + 'Initiative Non Compliance Policies', + 'Policy', + 'Policy Type', + 'Effect', + 'Compliance Resources', + 'Non Compliance Resources', + 'Unknown Resources', + 'Exempt Resources', + 'Policy Mode', + 'Policy Version', + 'Policy Deprecated', + 'Policy Category' | Export-Excel -Path $File -WorksheetName 'Policy' -AutoSize -MaxAutoSizeRows 100 -TableName 'AzurePolicy' -MoveToStart -ConditionalText $condtxt -TableStyle $tableStyle -Style $Style +} + diff --git a/Modules/Inventory/ARIQuotaInv.psm1 b/Modules/Inventory/ARIQuotaInv.psm1 new file mode 100644 index 0000000..84de630 --- /dev/null +++ b/Modules/Inventory/ARIQuotaInv.psm1 @@ -0,0 +1,103 @@ +<# +.Synopsis +vCPU Quotas Module + +.DESCRIPTION +This script process and creates the Quota sheet based on Quotas Used. + +.Link +https://github.com/microsoft/ARI/Modules/Inventory/ARIQuotaInv.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> + +function Start-ARIQuotaJob { + Param($Resources,$Subscriptions) + + Start-Job -Name 'Quota Usage' -ScriptBlock { + + $Quotas = @() + $Quotas = Foreach($Sub in $($args[1])) + { + $Locs = ($($args[0]) | Where-Object {$_.subscriptionId -eq $Sub.id -and $_.Type -in 'microsoft.compute/virtualmachines','microsoft.compute/virtualmachinescalesets'} | Group-Object -Property Location).name + if (![string]::IsNullOrEmpty($Locs)) + { + Foreach($Loc in $Locs) + { + if($Loc.Loc.count -eq 1) + { + Set-AzContext -Subscription $Sub.Id + $Quota = get-azvmusage -location $Loc.Loc + $Quota = $Quota | Where-Object {$_.CurrentValue -ge 1} + $Q = @{ + 'Location' = $Loc.Loc; + 'Subscription' = $Sub.name; + 'Data' = $Quota + } + $Q + } + else { + Set-AzContext -Subscription $Sub.Id + foreach($Loc1 in $Loc.loc) + { + $Quota = get-azvmusage -location $Loc1 + $Quota = $Quota | Where-Object {$_.CurrentValue -ge 1} + $Q = @{ + 'Location' = $Loc1; + 'Subscription' = $Sub.name; + 'Data' = $Quota + } + $Q + } + } + } + } + } + $Quotas + } -ArgumentList $Resources, $Subscriptions +} + +function Build-ARIQuotaReport { + param($File, $AzQuota, $TableStyle) + + $tmp = @() + $Total = ($AzQuota.Data).count + foreach($Quota in $AzQuota) + { + foreach($Data in $Quota.Data) + { + $FreevCPU = '' + if($Data.Name.LocalizedValue -like '*vCPUs'){$FreevCPU = $Data.limit - $Data.CurrentValue} + $obj = @{ + 'Subscription' = $Quota.Subscription; + 'Region' = $Quota.Location; + 'Current Usage' = $Data.currentValue; + 'Limit' = $Data.limit; + 'Quota' = $Data.Name.LocalizedValue; + 'vCPUs Available' = $FreevCPU; + 'Total' = $Total + } + $tmp += $obj + } + } + + $ExcelVar = $tmp + + $TableName = ('QuotaTable_'+$ExcelVar[0].Total) + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | + Select-Object -Unique 'Subscription', + 'Region', + 'Current Usage', + 'Limit', + 'Quota', + 'vCPUs Available' | + Export-Excel -Path $File -WorksheetName 'Quota Usage' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -Numberformat '0' -MoveToEnd +} \ No newline at end of file diff --git a/Modules/Inventory/ARIResourceDataPull.psm1 b/Modules/Inventory/ARIResourceDataPull.psm1 new file mode 100644 index 0000000..67e02df --- /dev/null +++ b/Modules/Inventory/ARIResourceDataPull.psm1 @@ -0,0 +1,161 @@ +<# +.Synopsis +Main module for Resource Extraction + +.DESCRIPTION +This module is the main module for the Azure Resource Graphs that will be run against the environment. + +.Link +https://github.com/microsoft/ARI/Core/Start-AzureResourceExtraction.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +Function Start-AzureResourceDataPull { + Param($ManagementGroup, $Subscriptions, $SubscriptionID, $ResourceGroup, $SecurityCenter, $SkipAdvisory, $IncludeTags, $QuotaUsage, $TagKey, $TagValue, $Debug) + + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Extractor function') + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Powershell Edition: ' + ([string]$psversiontable.psEdition)) + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Powershell Version: ' + ([string]$psversiontable.psVersion)) + + #Field for tags + if ($IncludeTags.IsPresent) { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Tags will be included") + $GraphQueryTags = ",tags " + } else { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+"Tags will be ignored") + $GraphQueryTags = "" + } + + <###################################################### Subscriptions ######################################################################> + + Write-Progress -activity 'Azure Inventory' -Status "1% Complete." -PercentComplete 2 -CurrentOperation 'Discovering Subscriptions..' + + if (![string]::IsNullOrEmpty($ManagementGroup)) + { + $Subscriptions = Get-ARIManagementGroups -ManagementGroup $ManagementGroup -Debug $Debug + } + + $SubCount = [string]$Subscriptions.id.count + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Number of Subscriptions Found: ' + $SubCount) + Write-Progress -activity 'Azure Inventory' -Status "3% Complete." -PercentComplete 3 -CurrentOperation "$SubCount Subscriptions found.." + + <######################################################## INVENTORY LOOPs #######################################################################> + +$ExtractionRuntime = Measure-Command -Expression { + + Write-Progress -Id 1 -activity "Running Inventory Jobs" -Status "1% Complete." -Completed + + Write-Progress -activity 'Azure Inventory' -Status "4% Complete." -PercentComplete 4 -CurrentOperation "Starting Resources extraction jobs.." + + if(![string]::IsNullOrEmpty($ResourceGroup) -and [string]::IsNullOrEmpty($SubscriptionID)) + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Resource Group Name present, but missing Subscription ID.') + Write-Output '' + Write-Output 'If Using the -ResourceGroup Parameter, the Subscription ID must be informed' + Write-Output '' + Exit + } + else + { + $Subscri = $Subscriptions.id + $RGQueryExtension = '' + $TagQueryExtension = '' + $MGQueryExtension = '' + if(![string]::IsNullOrEmpty($ResourceGroup) -and ![string]::IsNullOrEmpty($SubscriptionID)) + { + $RGQueryExtension = "| where resourceGroup in~ ('$([String]::Join("','",$ResourceGroup))')" + } + elseif(![string]::IsNullOrEmpty($TagKey) -and ![string]::IsNullOrEmpty($TagValue)) + { + $TagQueryExtension = "| where isnotempty(tags) | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey =~ '$TagKey' and tagValue =~ '$TagValue'" + } + elseif (![string]::IsNullOrEmpty($ManagementGroup)) + { + $MGQueryExtension = "| join kind=inner (resourcecontainers | where type == 'microsoft.resources/subscriptions' | mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$ManagementGroup' | project subscriptionId, managanagementGroup = managementGroupParent.name) on subscriptionId" + $MGContainerExtension = "| mv-expand managementGroupParent = properties.managementGroupAncestorsChain | where managementGroupParent.name =~ '$ManagementGroup'" + } + } + + $GraphQuery = "resources $RGQueryExtension $TagQueryExtension $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Resources') + $Resources += Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Resources' + + $GraphQuery = "networkresources $RGQueryExtension $TagQueryExtension $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Network Resources') + $Resources += Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Network Resources' + + $GraphQuery = "recoveryservicesresources $RGQueryExtension $TagQueryExtension | where type =~ 'microsoft.recoveryservices/vaults/backupfabrics/protectioncontainers/protecteditems' or type =~ 'microsoft.recoveryservices/vaults/backuppolicies' $MGQueryExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Backup Resources') + $Resources += Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Backup Items' + + $GraphQuery = "desktopvirtualizationresources $RGQueryExtension $MGQueryExtension| project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for AVD Resources') + $Resources += Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Virtual Desktop' + + $GraphQuery = "resourcecontainers $RGQueryExtension $TagQueryExtension $MGContainerExtension | project id,name,type,tenantId,kind,location,resourceGroup,subscriptionId,managedBy,sku,plan,properties,identity,zones,extendedLocation$($GraphQueryTags) | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Resource Containers') + $ResourceContainers = Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Subscriptions and Resource Groups' + + if (!($SkipAdvisory.IsPresent)) + { + $GraphQuery = "advisorresources $RGQueryExtension $MGQueryExtension | where properties.impact in~ ('Medium','High') | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Advisories') + $Advisories = Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Advisories' + } + if ($SecurityCenter.IsPresent) + { + $GraphQuery = "securityresources $RGQueryExtension | where type =~ 'microsoft.security/assessments' and properties['status']['code'] == 'Unhealthy' $MGQueryExtension | order by id asc" + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Invoking Inventory Loop for Security Resources') + $Security = Invoke-ResourceInventoryLoop -GraphQuery $GraphQuery -FSubscri $Subscri -LoopName 'Security Center' + } + + Write-Progress -activity 'Azure Inventory' -Status "4% Complete." -PercentComplete 4 -CurrentOperation "Starting API Extraction.." + + + <######################################################### QUOTA JOB ######################################################################> + + if($QuotaUsage.isPresent) + { + Start-ARIQuotaJob -Resources $Resources -Subscriptions $Subscriptions + } + + Write-Progress -activity 'Azure Inventory' -PercentComplete 20 + + Write-Progress -Id 1 -activity "Running Inventory Jobs" -Status "100% Complete." -Completed + +} + $tmp = [pscustomobject]@{ + ExtractionRunTime = $ExtractionRuntime + Resources = $Resources + ResourceContainers = $ResourceContainers + Advisories = $Advisories + Security = $Security + } + return $tmp +} \ No newline at end of file diff --git a/Modules/Inventory/ARIResourceReport.psm1 b/Modules/Inventory/ARIResourceReport.psm1 new file mode 100644 index 0000000..9a34a7f --- /dev/null +++ b/Modules/Inventory/ARIResourceReport.psm1 @@ -0,0 +1,157 @@ +<# +.Synopsis +Main module for Excel Report Building + +.DESCRIPTION +This module is the main module for building the Excel Report. + +.Link +https://github.com/microsoft/ARI/Modules/Inventory/ARIResourceReport.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +Function Build-AzureResourceReport { + Param($Subscriptions, + $ExtractionRuntime, + $Resources, + $SecurityCenter, + $File, + $DDFile, + $SkipDiagram, + $RunLite, + $PlatOS, + $InTag, + $SkipAPIs, + $SkipPolicy, + $SkipAdvisory, + $Automation, + $Debug) + + if ($Debug.IsPresent) + { + $DebugPreference = 'Continue' + $ErrorActionPreference = 'Continue' + } + else + { + $ErrorActionPreference = "silentlycontinue" + } + + $ReportingRunTime = Measure-Command -Expression { + + #### Generic Conditional Text rules, Excel style specifications for the spreadsheets and tables: + $TableStyle = "Light19" + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Excel Table Style used: ' + $TableStyle) + + Write-Progress -activity 'Azure Inventory' -Status "21% Complete." -PercentComplete 21 -CurrentOperation "Starting to process extraction data.." + + + <######################################################### IMPORT UNSUPPORTED VERSION LIST ######################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Importing List of Unsupported Versions.') + + $Unsupported = Get-ARIUnsupportedData -Debug $Debug + + $DataActive = ('Azure Resource Inventory Reporting (' + ($Resources.count) + ') Resources') + + <######################################################### RESOURCE GROUP JOB ######################################################################> + + if ($Automation.IsPresent) + { + $SmaResources = Start-ARIAutResourceJob -Resources $Resources -Subscriptions $Subscriptions -InTag $InTag -Unsupported $Unsupported + } + else + { + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Resource Jobs.') + + $DebugEnvSize = Start-ARIResourceJobs -Resources $Resources -Subscriptions $Subscriptions -InTag $InTag -Unsupported $Unsupported -Debug $Debug + } + + <############################################################## RESOURCES LOOP CREATION #############################################################> + + if (!$Automation.IsPresent) + { + if($DebugEnvSize -in ('Large','Enormous')) + { + Clear-Variable Resources + [System.GC]::GetTotalMemory($true) | out-null + } + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Jobs Collector.') + Write-Progress -activity $DataActive -Status "Processing Inventory" -PercentComplete 0 + $c = 0 + + $JobNames = (Get-Job | Where-Object {$_.name -like 'ResourceJob_*'}).Name + + while (get-job -Name $JobNames | Where-Object { $_.State -eq 'Running' }) { + $jb = get-job -Name $JobNames + $c = (((($jb.count - ($jb | Where-Object { $_.State -eq 'Running' }).Count)) / $jb.Count) * 100) + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Jobs Still Running: '+[string]($jb | Where-Object { $_.State -eq 'Running' }).count) + $c = [math]::Round($c) + Write-Progress -Id 1 -activity "Processing Resource Jobs" -Status "$c% Complete." -PercentComplete $c + Start-Sleep -Seconds 5 + } + Write-Progress -Id 1 -activity "Processing Resource Jobs" -Status "100% Complete." -Completed + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Jobs Compleated.') + + $SmaResources = @() + + Foreach ($Job in $JobNames) + { + $TempJob = Receive-Job -Name $Job + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Job '+ $Job +' Returned: ' + ($TempJob.values | Where-Object {$_ -ne $null}).Count + ' Resource Types.') + $SmaResources += $TempJob + } + } + + <############################################################## REPORTING ###################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Resource Reporting.') + + Start-ARIResourceReporting -InTag $InTag -file $file -SmaResources $SmaResources -TableStyle $TableStyle -Unsupported $Unsupported -DebugEnvSize $DebugEnvSize -DataActive $DataActive -Debug $Debug + + <################################################################### EXTRA REPORTS ###################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Starting Default Data Reporting.') + + Start-ARIExtraReports -File $File -QuotaUsage $QuotaUsage -SecurityCenter $SecurityCenter -SkipPolicy $SkipPolicy -SkipAdvisory $SkipAdvisory -TableStyle $TableStyle -Debug $Debug + + <################################################################### CHARTS ###################################################################> + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Generating Overview sheet (Charts).') + + } + + Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "15% Complete." -PercentComplete 15 -CurrentOperation "Invoking Excel Chart's Module." + + Build-ARIExcelChart -File $File -TableStyle $TableStyle -PlatOS $PlatOS -Subscriptions $Subscriptions -ExtractionRunTime $ExtractionRuntime -ReportingRunTime $ReportingRunTime -RunLite $RunLite -Debug $Debug + + [System.GC]::GetTotalMemory($true) | out-null + + Write-Debug ((get-date -Format 'yyyy-MM-dd_HH_mm_ss')+' - '+'Finished Charts Phase.') + + Write-Progress -activity 'Azure Resource Inventory Reporting Charts' -Status "100% Complete." -Completed + + if(!$SkipDiagram.IsPresent) + { + Write-Progress -activity 'Diagrams' -Status "Completing Diagram" -PercentComplete 70 -CurrentOperation "Consolidating Diagram" + + while (get-job -Name 'DrawDiagram' | Where-Object { $_.State -eq 'Running' }) { + Write-Progress -Id 1 -activity 'Processing Diagrams' -Status "50% Complete." -PercentComplete 50 + Start-Sleep -Seconds 2 + } + Write-Progress -Id 1 -activity 'Processing Diagrams' -Status "100% Complete." -Completed + + Write-Progress -activity 'Diagrams' -Status "Closing Diagram File" -Completed + } + + Get-Job | Wait-Job | Remove-Job +} \ No newline at end of file diff --git a/Modules/Inventory/ARISecCenterInv.psm1 b/Modules/Inventory/ARISecCenterInv.psm1 new file mode 100644 index 0000000..988ff60 --- /dev/null +++ b/Modules/Inventory/ARISecCenterInv.psm1 @@ -0,0 +1,68 @@ +<# +.Synopsis +Security Center Module + +.DESCRIPTION +This script process and creates the Security Center sheet based on securityresources. + +.Link +https://github.com/microsoft/ARI/Extras/ARISecCenterInv.psm1 + +.COMPONENT + This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ARISecCenterProcessing { + param($Subscriptions,$Security) + $obj = '' + $tmp = @() + + foreach ($1 in $Security) { + $data = $1.PROPERTIES + + $sub1 = $Subscriptions | Where-Object { $_.id -eq $1.properties.resourceDetails.Id.Split("/")[2] } + + $obj = @{ + 'Subscription' = $sub1.Name; + 'Resource Group' = $1.RESOURCEGROUP; + 'Resource Type' = $data.resourceDetails.Id.Split("/")[7]; + 'Resource Name' = $data.resourceDetails.Id.Split("/")[8]; + 'Categories' = [string]$data.metadata.categories; + 'Control' = $data.displayName; + 'Severity' = $data.metadata.severity; + 'Status' = $data.status.code; + 'Remediation' = $data.metadata.remediationDescription; + 'Remediation Effort' = $data.metadata.implementationEffort; + 'User Impact' = $data.metadata.userImpact; + 'Threats' = [string]$data.metadata.threats + } + $tmp += $obj + } + $tmp +} +function Build-ARISecCenterReport { + param($File, $Sec, $TableStyle) + $condtxtsec = $(New-ConditionalText High -Range G:G + New-ConditionalText High -Range L:L) + + $Sec | + ForEach-Object { [PSCustomObject]$_ } | + Select-Object 'Subscription', + 'Resource Group', + 'Resource Type', + 'Resource Name', + 'Categories', + 'Control', + 'Severity', + 'Status', + 'Remediation', + 'Remediation Effort', + 'User Impact', + 'Threats' | + Export-Excel -Path $File -WorksheetName 'SecurityCenter' -AutoSize -MaxAutoSizeRows 100 -MoveToStart -TableName 'SecurityCenter' -TableStyle $tableStyle -ConditionalText $condtxtsec +} \ No newline at end of file diff --git a/Modules/Inventory/ARISubInv.psm1 b/Modules/Inventory/ARISubInv.psm1 new file mode 100644 index 0000000..564947a --- /dev/null +++ b/Modules/Inventory/ARISubInv.psm1 @@ -0,0 +1,55 @@ +<# +.Synopsis +Module for Subscriptions + +.DESCRIPTION +This script process and creates the Subscriptions sheet based on resources and subscriptions the resources belong. + +.Link +https://github.com/azureinventory/ARI/Extras/ARISubInv.psm1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 15th Oct, 2024 +Authors: Claudio Merola + +#> +function Invoke-ARISubsProcessing { + param($Subscriptions,$Resources) + + $ResTable = $Resources | Where-Object { $_.type -ne 'microsoft.advisor/recommendations' } + $resTable2 = $ResTable | Select-Object id, Type, location, resourcegroup, subscriptionid + $ResTable3 = $ResTable2 | Group-Object -Property type, location, resourcegroup, subscriptionid + + $tmp = foreach ($ResourcesSUB in $ResTable3) { + $ResourceDetails = $ResourcesSUB.name -split "," + $SubName = $Subscriptions | Where-Object { $_.Id -eq ($ResourceDetails[3] -replace (" ", "")) } + + $obj = @{ + 'Subscription' = $SubName.Name; + 'Resource Group' = $ResourceDetails[2]; + 'Location' = $ResourceDetails[1]; + 'Resource Type' = $ResourceDetails[0]; + 'Resources' = $ResourcesSUB.Count + } + $obj + } + $tmp +} + +function Build-ARISubsReport { + param($File, $Sub, $TableStyle) + $TableName = ('SubsTable_'+($Sub.Subscription | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' + + $Sub | + ForEach-Object { [PSCustomObject]$_ } | + Select-Object 'Subscription', + 'Resource Group', + 'Location', + 'Resource Type', + 'Resources' | Export-Excel -Path $File -WorksheetName 'Subscriptions' -TableName $TableName -AutoSize -MaxAutoSizeRows 100 -TableStyle $tableStyle -Style $Style -Numberformat '0' -MoveToEnd +} diff --git a/Modules/Scripts/APIs/AdvisorScore.ps1 b/Modules/Scripts/APIs/AdvisorScore.ps1 new file mode 100644 index 0000000..b6c116c --- /dev/null +++ b/Modules/Scripts/APIs/AdvisorScore.ps1 @@ -0,0 +1,106 @@ +<# +.Synopsis +Inventory for Azure Advisor Score + +.DESCRIPTION +Excel Sheet Name: AdvisorScore + +.Link +https://github.com/microsoft/ARI/Modules/APIs/AdvisorScore.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 25th Aug, 2024 +Authors: Claudio Merola + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +If ($Task -eq 'Processing') { + + <######### Insert the resource extraction here ########> + + $AdvisorScore = $Resources | Where-Object { $_.TYPE -eq 'Microsoft.Advisor/advisorScore' } + + <######### Insert the resource Process here ########> + + if($AdvisorScore) + { + $tmp = @() + foreach ($1 in $AdvisorScore) { + if ($1.name -in ('Cost','OperationalExcellence','Performance','Security','HighAvailability','Advisor')) + { + $SubId = $1.id.split('/')[2] + $sub1 = $SUB | Where-Object { $_.id -eq $SubId } + $data = $1.PROPERTIES + $Series = $data.timeSeries | Where-Object {$_.aggregationLevel -eq 'Monthly'} + + $RefreshDate = $data.lastRefreshedScore.date + $RefreshDate = [datetime]$RefreshDate + $RefreshDate = $RefreshDate.ToString("yyyy-MM-dd") + + foreach ($Serie in $Series.scoreHistory) + { + $Date = $Serie.date + $Date = [datetime]$Date + $Date = $Date.ToString("yyyy-MM-dd") + + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.Name; + 'Category' = $1.Name; + 'Latest Score (%)' = $data.lastRefreshedScore.score; + 'Latest Refresh Score' = $RefreshDate; + 'Score Date' = $Date; + 'Score' = $Serie.score; + 'Impacted Resources' = $Serie.impactedResourceCount; + 'Consumption Units' = $Serie.consumptionUnits; + 'Potential Score Increase' = $Serie.potentialScoreIncrease + } + $tmp += $obj + } + } + } + $tmp + } +} + +<######## Resource Excel Reporting Begins Here ########> + +Else { + <######## $SmaResources.(RESOURCE FILE NAME) ##########> + + if ($SmaResources.AdvisorScore) { + + $TableName = ('AdvScoreTable_'+($SmaResources.AdvisorScore.id | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' + + $condtxt = @() + $condtxt += New-ConditionalText -Range C:C -ConditionalType LessThan 80 + $condtxt += New-ConditionalText -Range F:F -ConditionalType LessThan 70 + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('Category') + $Exc.Add('Latest Score (%)') + $Exc.Add('Latest Refresh Score') + $Exc.Add('Score Date') + $Exc.Add('Score') + $Exc.Add('Impacted Resources') + $Exc.Add('Consumption Units') + $Exc.Add('Potential Score Increase') + + $ExcelVar = $SmaResources.AdvisorScore + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'AdvisorScore' -AutoSize -TableName $TableName -MaxAutoSizeRows 100 -TableStyle $tableStyle -ConditionalText $condtxt -Numberformat '0' -Style $Style + + } +} \ No newline at end of file diff --git a/Modules/Scripts/APIs/ManagedIds.ps1 b/Modules/Scripts/APIs/ManagedIds.ps1 new file mode 100644 index 0000000..db0cbde --- /dev/null +++ b/Modules/Scripts/APIs/ManagedIds.ps1 @@ -0,0 +1,91 @@ +<# +.Synopsis +Inventory for Azure Managed Identities + +.DESCRIPTION +Excel Sheet Name: ManagedIdentities + +.Link +https://github.com/microsoft/ARI/Modules/APIs/ManagedIdentities.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 25th Aug, 2024 +Authors: Claudio Merola + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +If ($Task -eq 'Processing') { + + <######### Insert the resource extraction here ########> + + $ManagedIdentities = $Resources | Where-Object { $_.TYPE -eq 'Microsoft.ManagedIdentity/userAssignedIdentities' } + + <######### Insert the resource Process here ########> + + if($ManagedIdentities) + { + $tmp = @() + foreach ($1 in $ManagedIdentities) { + $ResUCount = 1 + $SubId = $1.id.split('/')[2] + $sub1 = $SUB | Where-Object { $_.id -eq $SubId } + $data = $1.PROPERTIES + $Tags = if(![string]::IsNullOrEmpty($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} + foreach ($Tag in $Tags) { + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.Name; + 'Name' = $1.Name; + 'Location' = $1.location; + 'Principal ID' = $data.principalId; + 'Client ID' = $data.clientId; + 'Resource U' = $ResUCount; + 'Tag Name' = [string]$Tag.Name; + 'Tag Value' = [string]$Tag.Value + } + $tmp += $obj + if ($ResUCount -eq 1) { $ResUCount = 0 } + } + } + $tmp + } +} + +<######## Resource Excel Reporting Begins Here ########> + +Else { + <######## $SmaResources.(RESOURCE FILE NAME) ##########> + + if ($SmaResources.ManagedIds) { + + $TableName = ('ManIdTable_'+($SmaResources.ManagedIds.id | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('Name') + $Exc.Add('Location') + $Exc.Add('Principal ID') + $Exc.Add('Client ID') + if($InTag) + { + $Exc.Add('Tag Name') + $Exc.Add('Tag Value') + } + + $ExcelVar = $SmaResources.ManagedIds + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'Managed Identity' -AutoSize -TableName $TableName -MaxAutoSizeRows 100 -TableStyle $tableStyle -Numberformat '0' -Style $Style + + } +} \ No newline at end of file diff --git a/Modules/Scripts/APIs/Outages.ps1 b/Modules/Scripts/APIs/Outages.ps1 new file mode 100644 index 0000000..53dd268 --- /dev/null +++ b/Modules/Scripts/APIs/Outages.ps1 @@ -0,0 +1,125 @@ +<# +.Synopsis +Inventory for Azure Outages + +.DESCRIPTION +Excel Sheet Name: Outages + +.Link +https://github.com/microsoft/ARI/Modules/APIs/Outages.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 25th Aug, 2024 +Authors: Claudio Merola + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +If ($Task -eq 'Processing') { + + <######### Insert the resource extraction here ########> + + $Outages = $Resources | Where-Object { $_.TYPE -eq 'Microsoft.ResourceHealth/events' -and $_.properties.description -like '*How can customers make incidents like this less impactful?*' } + + <######### Insert the resource Process here ########> + + if($Outages) + { + $tmp = @() + foreach ($1 in $Outages) { + $ImpactedSubs = $1.properties.impact.impactedRegions.impactedSubscriptions | Select-Object -Unique + + $Data = $1.properties + + foreach ($Sub0 in $ImpactedSubs) + { + $sub1 = $SUB | Where-Object { $_.id -eq $Sub0 } + + $StartTime = $Data.impactStartTime + $StartTime = [datetime]$StartTime + $StartTime = $StartTime.ToString("yyyy-MM-dd HH:mm") + + $Mitigation = $Data.impactMitigationTime + $Mitigation = [datetime]$Mitigation + $Mitigation = $Mitigation.ToString("yyyy-MM-dd HH:mm") + + $ImpactedService = if ($1.properties.impact.impactedService.count -gt 1) { $1.properties.impact.impactedService | ForEach-Object { $_ + ' ,' } }else { $1.properties.impact.impactedService} + $ImpactedService = [string]$ImpactedService + $ImpactedService = if ($ImpactedService -like '* ,*') { $ImpactedService -replace ".$" }else { $ImpactedService } + + $HTML = New-Object -Com 'HTMLFile' + $HTML.write([ref]$1.properties.description) + $OutageDescription = $Html.body.innerText + $SplitDescription = $OutageDescription.split('How can we make our incident communications more useful?').split('How can customers make incidents like this less impactful?').split('How are we making incidents like this less likely or less impactful?').split('How did we respond?').split('What went wrong and why?').split('What happened?') + + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.name; + 'Outage ID' = $1.name; + 'Event Type' = $Data.eventType; + 'Status' = $Data.status; + 'Event Level' = $Data.eventlevel; + 'Title' = $Data.title; + 'Impact Start Time' = $StartTime; + 'Impact Mitigation Time' = $Mitigation; + 'Impacted Services' = $ImpactedService; + 'What happened' = ($SplitDescription[1]).Split([Environment]::NewLine)[1]; + 'What went wrong and why' = ($SplitDescription[2]).Split([Environment]::NewLine)[1]; + 'How did we respond' = ($SplitDescription[3]).Split([Environment]::NewLine)[1]; + 'How are we making incidents like this less likely or less impactful' = ($SplitDescription[4]).Split([Environment]::NewLine)[1]; + 'How can customers make incidents like this less impactful' = ($SplitDescription[5]).Split([Environment]::NewLine)[1] + } + $tmp += $obj + } + } + $tmp + } +} + +<######## Resource Excel Reporting Begins Here ########> + +Else { + <######## $SmaResources.(RESOURCE FILE NAME) ##########> + + if ($SmaResources.Outages) { + + $TableName = ('OutagesTable_'+($SmaResources.Outages.id | Select-Object -Unique).count) + + $Style = @( + New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' -Range 'A:E' + New-ExcelStyle -HorizontalAlignment Left -NumberFormat '0' -WrapText -Width 55 -Range 'F:F' + New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' -Range 'G:I' + New-ExcelStyle -HorizontalAlignment Left -NumberFormat '0' -WrapText -Width 80 -Range 'J:N' + ) + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('Outage ID') + $Exc.Add('Event Type') + $Exc.Add('Status') + $Exc.Add('Event Level') + $Exc.Add('Title') + $Exc.Add('Impact Start Time') + $Exc.Add('Impact Mitigation Time') + $Exc.Add('Impacted Services') + $Exc.Add('What happened') + $Exc.Add('What went wrong and why') + $Exc.Add('How did we respond') + $Exc.Add('How are we making incidents like this less likely or less impactful') + $Exc.Add('How can customers make incidents like this less impactful') + + $ExcelVar = $SmaResources.Outages + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'Outages' -AutoSize -TableName $TableName -MaxAutoSizeRows 100 -TableStyle $tableStyle -Numberformat '0' -Style $Style + + } +} \ No newline at end of file diff --git a/Modules/Scripts/APIs/ReservationRecom.ps1 b/Modules/Scripts/APIs/ReservationRecom.ps1 new file mode 100644 index 0000000..48a9850 --- /dev/null +++ b/Modules/Scripts/APIs/ReservationRecom.ps1 @@ -0,0 +1,101 @@ +<# +.Synopsis +Inventory for Azure Reservation Recommendations + +.DESCRIPTION +Excel Sheet Name: Reservation Advisor + +.Link +https://github.com/microsoft/ARI/Modules/APIs/ReservationRecom.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 25th Aug, 2024 +Authors: Claudio Merola + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +If ($Task -eq 'Processing') { + + <######### Insert the resource extraction here ########> + + $Reserv = $Resources | Where-Object { $_.TYPE -eq 'Microsoft.Consumption/reservationRecommendations' } + + <######### Insert the resource Process here ########> + + if($Reserv) + { + $tmp = @() + foreach ($1 in $Reserv) { + $SubId = $1.id.split('/')[2] + $sub1 = $SUB | Where-Object { $_.id -eq $SubId } + $data = $1.PROPERTIES + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.Name; + 'Current SKU' = $1.SKU; + 'Location' = $1.location; + 'Resource Type' = $data.resourceType; + 'Instance Flexibility Group' = $data.instanceFlexibilityGroup; + 'Recommended Size' = $data.normalizedSize; + 'Recommended Number of Reservations'= $data.recommendedQuantity; + 'Instance Flexibility Ratio' = $data.instanceFlexibilityRatio; + 'Quantity Normalized' = $data.recommendedQuantityNormalized; + 'Cost With No Reserved Instance' = $data.costWithNoReservedInstances; + 'Cost With Reserved Instance' = $data.totalCostWithReservedInstances; + 'Net Savings' = $data.netSavings; + 'Reservation Term' = $data.term; + 'Scope' = $data.scope; + } + $tmp += $obj + } + $tmp + } +} + +<######## Resource Excel Reporting Begins Here ########> + +Else { + <######## $SmaResources.(RESOURCE FILE NAME) ##########> + + if ($SmaResources.ReservationRecom) { + + $TableName = ('ReservRecTable_'+($SmaResources.ReservationRecom.id | Select-Object -Unique).count) + + $Style = @() + $Style += New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' -Range A:I + $Style += New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '#,##0.00' -Range J:L + $Style += New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' -Range M:N + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('Current SKU') + $Exc.Add('Location') + $Exc.Add('Resource Type') + $Exc.Add('Instance Flexibility Group') + $Exc.Add('Recommended Size') + $Exc.Add('Recommended Number of Reservations') + $Exc.Add('Instance Flexibility Ratio') + $Exc.Add('Quantity Normalized') + $Exc.Add('Cost With No Reserved Instance') + $Exc.Add('Cost With Reserved Instance') + $Exc.Add('Net Savings') + $Exc.Add('Reservation Term') + $Exc.Add('Scope') + + $ExcelVar = $SmaResources.ReservationRecom + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'Reservation Advisor' -AutoSize -TableName $TableName -MaxAutoSizeRows 100 -TableStyle $tableStyle -Style $Style + + + } +} \ No newline at end of file diff --git a/Modules/Scripts/APIs/SupportTickets.ps1 b/Modules/Scripts/APIs/SupportTickets.ps1 new file mode 100644 index 0000000..3c98037 --- /dev/null +++ b/Modules/Scripts/APIs/SupportTickets.ps1 @@ -0,0 +1,113 @@ +<# +.Synopsis +Inventory for Azure Support Tickets + +.DESCRIPTION +Excel Sheet Name: SupportTickets + +.Link +https://github.com/microsoft/ARI/Modules/APIs/SupportTickets.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 4.0.1 +First Release Date: 25th Aug, 2024 +Authors: Claudio Merola + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +If ($Task -eq 'Processing') { + + <######### Insert the resource extraction here ########> + + $Tickets = $Resources | Where-Object { $_.TYPE -eq 'Microsoft.Support/supportTickets' } + + <######### Insert the resource Process here ########> + + if($Tickets) + { + $tmp = @() + foreach ($1 in $Tickets) { + $data = $1.PROPERTIES + + $timecreated = $data.createdDate + $timecreated = [datetime]$timecreated + $timecreated = $timecreated.ToString("yyyy-MM-dd HH:mm") + + $ProblemDate = $data.problemStartTime + $ProblemDate = [datetime]$ProblemDate + $ProblemDate = $ProblemDate.ToString("yyyy-MM-dd HH:mm") + + $ModDate = $data.modifiedDate + $ModDate = [datetime]$ModDate + $ModDate = $ModDate.ToString("yyyy-MM-dd HH:mm") + + $obj = @{ + 'ID' = $1.id; + 'Support Ticket' = $data.supportTicketId; + 'Title' = $data.title; + 'Support Plan' = $data.supportPlanType; + 'Service' = $data.serviceDisplayName; + 'Current Severity' = $data.severity; + 'Status' = $data.status; + 'Creation Date' = $timecreated; + '24/7 Response' = $data.require24X7Response; + 'Ticket SLA (minutes)' = $data.serviceLevelAgreement.slaMinutes; + 'Problem Start Date' = $ProblemDate; + 'Last Modified Date' = $ModDate; + 'Support Engineer' = $data.supportEngineer.emailAddress; + 'Ticket Contact Name' = ($data.contactDetails.firstName + ' ' + $data.contactDetails.lastName); + 'Ticket Contact Email' = $data.contactDetails.primaryEmailAddress; + 'Ticket Contact Country' = $data.contactDetails.country; + } + $tmp += $obj + } + $tmp + } +} + +<######## Resource Excel Reporting Begins Here ########> + +Else { + <######## $SmaResources.(RESOURCE FILE NAME) ##########> + + if ($SmaResources.SupportTickets) { + + $TableName = ('TicketsTable_'+($SmaResources.SupportTickets.id | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat '0' + + $cond = @() + $cond += New-ConditionalText Open -Range F:F + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Support Ticket') + $Exc.Add('Title') + $Exc.Add('Support Plan') + $Exc.Add('Service') + $Exc.Add('Current Severity') + $Exc.Add('Status') + $Exc.Add('Creation Date') + $Exc.Add('24/7 Response') + $Exc.Add('Ticket SLA (minutes)') + $Exc.Add('Support Engineer') + $Exc.Add('Problem Start Date') + $Exc.Add('Last Modified Date') + $Exc.Add('Ticket Contact Name') + $Exc.Add('Ticket Contact Email') + $Exc.Add('Ticket Contact Country') + + $ExcelVar = $SmaResources.SupportTickets + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'SupportTickets' -AutoSize -TableName $TableName -MaxAutoSizeRows 100 -TableStyle $tableStyle -ConditionalText $cond -Numberformat '0' -Style $Style + + + } +} \ No newline at end of file diff --git a/Modules/Analytics/AzureAI.ps1 b/Modules/Scripts/Analytics/AzureAI.ps1 similarity index 100% rename from Modules/Analytics/AzureAI.ps1 rename to Modules/Scripts/Analytics/AzureAI.ps1 diff --git a/Modules/Analytics/ComputerVision.ps1 b/Modules/Scripts/Analytics/ComputerVision.ps1 similarity index 100% rename from Modules/Analytics/ComputerVision.ps1 rename to Modules/Scripts/Analytics/ComputerVision.ps1 diff --git a/Modules/Analytics/ContentMod.ps1 b/Modules/Scripts/Analytics/ContentMod.ps1 similarity index 100% rename from Modules/Analytics/ContentMod.ps1 rename to Modules/Scripts/Analytics/ContentMod.ps1 diff --git a/Modules/Analytics/ContentSafety.ps1 b/Modules/Scripts/Analytics/ContentSafety.ps1 similarity index 100% rename from Modules/Analytics/ContentSafety.ps1 rename to Modules/Scripts/Analytics/ContentSafety.ps1 diff --git a/Modules/Analytics/CustomVision.ps1 b/Modules/Scripts/Analytics/CustomVision.ps1 similarity index 100% rename from Modules/Analytics/CustomVision.ps1 rename to Modules/Scripts/Analytics/CustomVision.ps1 diff --git a/Modules/Analytics/Databricks.ps1 b/Modules/Scripts/Analytics/Databricks.ps1 similarity index 100% rename from Modules/Analytics/Databricks.ps1 rename to Modules/Scripts/Analytics/Databricks.ps1 diff --git a/Modules/Analytics/DocIntelligence.ps1 b/Modules/Scripts/Analytics/DocIntelligence.ps1 similarity index 100% rename from Modules/Analytics/DocIntelligence.ps1 rename to Modules/Scripts/Analytics/DocIntelligence.ps1 diff --git a/Modules/Analytics/EvtHub.ps1 b/Modules/Scripts/Analytics/EvtHub.ps1 similarity index 100% rename from Modules/Analytics/EvtHub.ps1 rename to Modules/Scripts/Analytics/EvtHub.ps1 diff --git a/Modules/Analytics/FaceAPI.ps1 b/Modules/Scripts/Analytics/FaceAPI.ps1 similarity index 100% rename from Modules/Analytics/FaceAPI.ps1 rename to Modules/Scripts/Analytics/FaceAPI.ps1 diff --git a/Modules/Analytics/HealthInsights.ps1 b/Modules/Scripts/Analytics/HealthInsights.ps1 similarity index 100% rename from Modules/Analytics/HealthInsights.ps1 rename to Modules/Scripts/Analytics/HealthInsights.ps1 diff --git a/Modules/Analytics/ImmersiveReader.ps1 b/Modules/Scripts/Analytics/ImmersiveReader.ps1 similarity index 100% rename from Modules/Analytics/ImmersiveReader.ps1 rename to Modules/Scripts/Analytics/ImmersiveReader.ps1 diff --git a/Modules/Analytics/Language.ps1 b/Modules/Scripts/Analytics/Language.ps1 similarity index 100% rename from Modules/Analytics/Language.ps1 rename to Modules/Scripts/Analytics/Language.ps1 diff --git a/Modules/Analytics/MachineLearning.ps1 b/Modules/Scripts/Analytics/MachineLearning.ps1 similarity index 100% rename from Modules/Analytics/MachineLearning.ps1 rename to Modules/Scripts/Analytics/MachineLearning.ps1 diff --git a/Modules/Analytics/SearchServices.ps1 b/Modules/Scripts/Analytics/SearchServices.ps1 similarity index 100% rename from Modules/Analytics/SearchServices.ps1 rename to Modules/Scripts/Analytics/SearchServices.ps1 diff --git a/Modules/Analytics/SpeechService.ps1 b/Modules/Scripts/Analytics/SpeechService.ps1 similarity index 100% rename from Modules/Analytics/SpeechService.ps1 rename to Modules/Scripts/Analytics/SpeechService.ps1 diff --git a/Modules/Analytics/Streamanalytics.ps1 b/Modules/Scripts/Analytics/Streamanalytics.ps1 similarity index 100% rename from Modules/Analytics/Streamanalytics.ps1 rename to Modules/Scripts/Analytics/Streamanalytics.ps1 diff --git a/Modules/Analytics/Synapse.ps1 b/Modules/Scripts/Analytics/Synapse.ps1 similarity index 100% rename from Modules/Analytics/Synapse.ps1 rename to Modules/Scripts/Analytics/Synapse.ps1 diff --git a/Modules/Analytics/Translator.ps1 b/Modules/Scripts/Analytics/Translator.ps1 similarity index 100% rename from Modules/Analytics/Translator.ps1 rename to Modules/Scripts/Analytics/Translator.ps1 diff --git a/Modules/Analytics/WrkSpace.ps1 b/Modules/Scripts/Analytics/WrkSpace.ps1 similarity index 100% rename from Modules/Analytics/WrkSpace.ps1 rename to Modules/Scripts/Analytics/WrkSpace.ps1 diff --git a/Modules/Compute/APPSERVICEPLAN.ps1 b/Modules/Scripts/Compute/APPSERVICEPLAN.ps1 similarity index 100% rename from Modules/Compute/APPSERVICEPLAN.ps1 rename to Modules/Scripts/Compute/APPSERVICEPLAN.ps1 diff --git a/Modules/Compute/APPSERVICES.ps1 b/Modules/Scripts/Compute/APPSERVICES.ps1 similarity index 100% rename from Modules/Compute/APPSERVICES.ps1 rename to Modules/Scripts/Compute/APPSERVICES.ps1 diff --git a/Modules/Compute/ARCServers.ps1 b/Modules/Scripts/Compute/ARCServers.ps1 similarity index 93% rename from Modules/Compute/ARCServers.ps1 rename to Modules/Scripts/Compute/ARCServers.ps1 index d7f90ac..ddaadef 100644 --- a/Modules/Compute/ARCServers.ps1 +++ b/Modules/Scripts/Compute/ARCServers.ps1 @@ -13,7 +13,7 @@ https://github.com/microsoft/ARI/Modules/Compute/ARCServers.ps1 This powershell Module is part of Azure Resource Inventory (ARI) .NOTES -Version: 3.0.1 +Version: 4.0.1 First Release Date: 19th November, 2020 Authors: Claudio Merola and Renato Gregio @@ -64,6 +64,14 @@ If ($Task -eq 'Processing') $Subnet = $data.networkprofile.networkinterfaces.ipaddresses.subnet.addressprefix } + $LastStatus = $data.laststatuschange + $LastStatus = [datetime]$LastStatus + $LastStatus = $LastStatus.ToString("yyyy-MM-dd HH:mm") + + $InstallDate = $data.osinstalldate + $InstallDate = [datetime]$InstallDate + $InstallDate = $InstallDate.ToString("yyyy-MM-dd HH:mm") + foreach ($Tag in $Tags) { $obj = @{ 'ID' = $1.id; @@ -87,12 +95,12 @@ If ($Task -eq 'Processing') 'MS SQL Server' = $data.mssqldiscovered; 'Agent Version' = $data.agentversion; 'Status' = $data.status; - 'Last Status Change' = [string](get-date($data.laststatuschange)); + 'Last Status Change' = $LastStatus; 'IP Address' = $IP; 'Subnet' = $Subnet; 'OS Name' = $data.osName; 'OS Version' = $data.osVersion; - 'OS Install Date' = [string](get-date($data.osinstalldate)); + 'OS Install Date' = $InstallDate; 'Operating System' = $data.osSku; 'License Status' = $data.licenseprofile.licensestatus; 'License Channel' = $data.licenseprofile.licensechannel; @@ -162,8 +170,5 @@ Else ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | Export-Excel -Path $File -WorksheetName 'ARC Servers' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -Style $Style - <######## Insert Column comments and documentations here following this model #########> - - Close-ExcelPackage $excel } } \ No newline at end of file diff --git a/Modules/Compute/ARO.ps1 b/Modules/Scripts/Compute/ARO.ps1 similarity index 100% rename from Modules/Compute/ARO.ps1 rename to Modules/Scripts/Compute/ARO.ps1 diff --git a/Modules/Compute/AVD.ps1 b/Modules/Scripts/Compute/AVD.ps1 similarity index 100% rename from Modules/Compute/AVD.ps1 rename to Modules/Scripts/Compute/AVD.ps1 diff --git a/Modules/Compute/CloudServices.ps1 b/Modules/Scripts/Compute/CloudServices.ps1 similarity index 99% rename from Modules/Compute/CloudServices.ps1 rename to Modules/Scripts/Compute/CloudServices.ps1 index 07af095..033b24f 100644 --- a/Modules/Compute/CloudServices.ps1 +++ b/Modules/Scripts/Compute/CloudServices.ps1 @@ -60,7 +60,7 @@ If ($Task -eq 'Processing') { } $tmp += $obj if ($ResUCount -eq 1) { $ResUCount = 0 } - } + } } $tmp } diff --git a/Modules/Compute/VM.ps1 b/Modules/Scripts/Compute/VM.ps1 similarity index 99% rename from Modules/Compute/VM.ps1 rename to Modules/Scripts/Compute/VM.ps1 index e1b5e54..d120540 100644 --- a/Modules/Compute/VM.ps1 +++ b/Modules/Scripts/Compute/VM.ps1 @@ -1,4 +1,4 @@ -<# +<# .Synopsis Inventory for Azure Virtual Machine @@ -34,7 +34,7 @@ If ($Task -eq 'Processing') $vmsizemap = @{} foreach($location in ($vm | Select-Object -ExpandProperty location -Unique)) { - foreach ($vmsize in ( az vm list-sizes -l $location | ConvertFrom-Json)) + foreach ($vmsize in ( Get-AzVMSize -Location $location )) { $vmsizemap[$vmsize.name] = @{ CPU = $vmSize.numberOfCores diff --git a/Modules/Compute/VMWare.ps1 b/Modules/Scripts/Compute/VMWare.ps1 similarity index 100% rename from Modules/Compute/VMWare.ps1 rename to Modules/Scripts/Compute/VMWare.ps1 diff --git a/Modules/Containers/AKS.ps1 b/Modules/Scripts/Containers/AKS.ps1 similarity index 99% rename from Modules/Containers/AKS.ps1 rename to Modules/Scripts/Containers/AKS.ps1 index c0fa60e..c6fc153 100644 --- a/Modules/Containers/AKS.ps1 +++ b/Modules/Scripts/Containers/AKS.ps1 @@ -139,6 +139,7 @@ Else $condtxt = @() #AKS + $condtxt += New-ConditionalText 1.28 -Range F:F $condtxt += New-ConditionalText 1.27 -Range F:F $condtxt += New-ConditionalText 1.26 -Range F:F $condtxt += New-ConditionalText 1.25 -Range F:F @@ -147,6 +148,7 @@ Else $condtxt += New-ConditionalText 1.22 -Range F:F $condtxt += New-ConditionalText 1.21 -Range F:F #Orchestrator + $condtxt += New-ConditionalText 1.28 -Range AC:AC $condtxt += New-ConditionalText 1.27 -Range AC:AC $condtxt += New-ConditionalText 1.26 -Range AC:AC $condtxt += New-ConditionalText 1.25 -Range AC:AC diff --git a/Modules/Containers/CONTAINER.ps1 b/Modules/Scripts/Containers/CONTAINER.ps1 similarity index 100% rename from Modules/Containers/CONTAINER.ps1 rename to Modules/Scripts/Containers/CONTAINER.ps1 diff --git a/Modules/Containers/REGISTRIES.ps1 b/Modules/Scripts/Containers/REGISTRIES.ps1 similarity index 100% rename from Modules/Containers/REGISTRIES.ps1 rename to Modules/Scripts/Containers/REGISTRIES.ps1 diff --git a/Modules/Containers/VMSS.ps1 b/Modules/Scripts/Containers/VMSS.ps1 similarity index 100% rename from Modules/Containers/VMSS.ps1 rename to Modules/Scripts/Containers/VMSS.ps1 diff --git a/Modules/Data/CosmosDB.ps1 b/Modules/Scripts/Data/CosmosDB.ps1 similarity index 100% rename from Modules/Data/CosmosDB.ps1 rename to Modules/Scripts/Data/CosmosDB.ps1 diff --git a/Modules/Data/MariaDB.ps1 b/Modules/Scripts/Data/MariaDB.ps1 similarity index 100% rename from Modules/Data/MariaDB.ps1 rename to Modules/Scripts/Data/MariaDB.ps1 diff --git a/Modules/Data/MySQL.ps1 b/Modules/Scripts/Data/MySQL.ps1 similarity index 100% rename from Modules/Data/MySQL.ps1 rename to Modules/Scripts/Data/MySQL.ps1 diff --git a/Modules/Data/MySQLflexible.ps1 b/Modules/Scripts/Data/MySQLflexible.ps1 similarity index 100% rename from Modules/Data/MySQLflexible.ps1 rename to Modules/Scripts/Data/MySQLflexible.ps1 diff --git a/Modules/Data/POSTGRE.ps1 b/Modules/Scripts/Data/POSTGRE.ps1 similarity index 100% rename from Modules/Data/POSTGRE.ps1 rename to Modules/Scripts/Data/POSTGRE.ps1 diff --git a/Modules/Data/POSTGREFlexible.ps1 b/Modules/Scripts/Data/POSTGREFlexible.ps1 similarity index 100% rename from Modules/Data/POSTGREFlexible.ps1 rename to Modules/Scripts/Data/POSTGREFlexible.ps1 diff --git a/Modules/Data/Purview.ps1 b/Modules/Scripts/Data/Purview.ps1 similarity index 100% rename from Modules/Data/Purview.ps1 rename to Modules/Scripts/Data/Purview.ps1 diff --git a/Modules/Data/RedisCache.ps1 b/Modules/Scripts/Data/RedisCache.ps1 similarity index 100% rename from Modules/Data/RedisCache.ps1 rename to Modules/Scripts/Data/RedisCache.ps1 diff --git a/Modules/Data/SQLDB.ps1 b/Modules/Scripts/Data/SQLDB.ps1 similarity index 100% rename from Modules/Data/SQLDB.ps1 rename to Modules/Scripts/Data/SQLDB.ps1 diff --git a/Modules/Data/SQLMI.ps1 b/Modules/Scripts/Data/SQLMI.ps1 similarity index 97% rename from Modules/Data/SQLMI.ps1 rename to Modules/Scripts/Data/SQLMI.ps1 index 7c1c001..627e0ff 100644 --- a/Modules/Data/SQLMI.ps1 +++ b/Modules/Scripts/Data/SQLMI.ps1 @@ -1,117 +1,117 @@ -<# -.Synopsis -Inventory for Azure SQL Server - -.DESCRIPTION -This script consolidates information for all microsoft.sql/servers resource provider in $Resources variable. -Excel Sheet Name: SQL MI - -.Link -https://github.com/microsoft/ARI/Modules/Data/SQLSERVER.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.3.2 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> - -<######## Default Parameters. Don't modify this ########> - -param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) - -if ($Task -eq 'Processing') { - - $SQLSERVERMI = $Resources | Where-Object { $_.TYPE -eq 'microsoft.sql/managedInstances' } - - if($SQLSERVERMI) - { - $tmp = @() - - foreach ($1 in $SQLSERVERMI) { - $ResUCount = 1 - $sub1 = $SUB | Where-Object { $_.id -eq $1.subscriptionId } - $data = $1.PROPERTIES - - $Tags = if(!!($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} - - $pvteps = if(!($1.privateEndpointConnections)) {[pscustomobject]@{id = 'NONE'}} else {$1.privateEndpointConnections | Select-Object @{Name="id";Expression={$_.id.split("/")[8]}}} - - foreach ($pvtep in $pvteps) { - foreach ($Tag in $Tags) { - $obj = @{ - 'ID' = $1.id; - 'Subscription' = $sub1.Name; - 'Resource Group' = $1.RESOURCEGROUP; - 'Name' = $1.NAME; - 'Location' = $1.LOCATION; - 'SkuName' = $1.sku.Name; - 'SkuCapacity' = $1.sku.capacity; - 'SkuTier' = $1.sku.tier; - 'Admin Login' = $data.adminitrators.login; - 'AzureADOnlyAuthentication' = $data.adminitrators.azureADOnlyAuthentication; - 'Private Endpoint' = $pvtep.id; - 'FQDN' = $data.fullyQualifiedDomainName; - 'Public Network Access' = $data.publicDataEndpointEnabled; - 'licenseType' = $data.licenseType; - 'managedInstanceCreateMode' = $data.managedInstanceCreateMode; - 'Resource U' = $ResUCount; - 'Zone Redundant' = $data.zoneRedundant; - 'Tag Name' = [string]$Tag.Name; - 'Tag Value' = [string]$Tag.Value - } - $tmp += $obj - if ($ResUCount -eq 1) { $ResUCount = 0 } - } - } - } - $tmp - } -} -else { - if ($SmaResources.SQLMI) { - - $TableName = ('SQLMITable_'+($SmaResources.SQLMI.id | Select-Object -Unique).count) - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 - - $condtxt = @() - $condtxt += New-ConditionalText FALSE -Range J:J - $condtxt += New-ConditionalText FALSO -Range J:J - $condtxt += New-ConditionalText FAUX -Range J:J - $condtxt += New-ConditionalText NONE -Range J:J - $condtxt += New-ConditionalText Enabled -Range L:L - $condtxt += New-ConditionalText VRAI -Range L:L - - $Exc = New-Object System.Collections.Generic.List[System.Object] - $Exc.Add('Subscription') - $Exc.Add('Resource Group') - $Exc.Add('Name') - $Exc.Add('Location') - $Exc.Add('SkuName') - $Exc.Add('SkuCapacity') - $Exc.Add('SkuTier') - $Exc.Add('Admin Login') - $Exc.Add('ActiveDirectoryOnlyAuthentication') - $Exc.Add('Private Endpoint') - $Exc.Add('FQDN') - $Exc.Add('Public Network Access') - $Exc.Add('licenseType') - $Exc.Add('managedInstanceCreateMode') - $Exc.Add('Zone Redundant') - if($InTag) - { - $Exc.Add('Tag Name') - $Exc.Add('Tag Value') - } - - $ExcelVar = $SmaResources.SQLMI - - $ExcelVar | - ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | - Export-Excel -Path $File -WorksheetName 'SQL MI' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -ConditionalText $condtxt -Style $Style - - } +<# +.Synopsis +Inventory for Azure SQL Server + +.DESCRIPTION +This script consolidates information for all microsoft.sql/servers resource provider in $Resources variable. +Excel Sheet Name: SQL MI + +.Link +https://github.com/microsoft/ARI/Modules/Data/SQLSERVER.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 2.3.2 +First Release Date: 19th November, 2020 +Authors: Claudio Merola and Renato Gregio + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +if ($Task -eq 'Processing') { + + $SQLSERVERMI = $Resources | Where-Object { $_.TYPE -eq 'microsoft.sql/managedInstances' } + + if($SQLSERVERMI) + { + $tmp = @() + + foreach ($1 in $SQLSERVERMI) { + $ResUCount = 1 + $sub1 = $SUB | Where-Object { $_.id -eq $1.subscriptionId } + $data = $1.PROPERTIES + + $Tags = if(!!($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} + + $pvteps = if(!($1.privateEndpointConnections)) {[pscustomobject]@{id = 'NONE'}} else {$1.privateEndpointConnections | Select-Object @{Name="id";Expression={$_.id.split("/")[8]}}} + + foreach ($pvtep in $pvteps) { + foreach ($Tag in $Tags) { + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.Name; + 'Resource Group' = $1.RESOURCEGROUP; + 'Name' = $1.NAME; + 'Location' = $1.LOCATION; + 'SkuName' = $1.sku.Name; + 'SkuCapacity' = $1.sku.capacity; + 'SkuTier' = $1.sku.tier; + 'Admin Login' = $data.adminitrators.login; + 'AzureADOnlyAuthentication' = $data.adminitrators.azureADOnlyAuthentication; + 'Private Endpoint' = $pvtep.id; + 'FQDN' = $data.fullyQualifiedDomainName; + 'Public Network Access' = $data.publicDataEndpointEnabled; + 'licenseType' = $data.licenseType; + 'managedInstanceCreateMode' = $data.managedInstanceCreateMode; + 'Resource U' = $ResUCount; + 'Zone Redundant' = $data.zoneRedundant; + 'Tag Name' = [string]$Tag.Name; + 'Tag Value' = [string]$Tag.Value + } + $tmp += $obj + if ($ResUCount -eq 1) { $ResUCount = 0 } + } + } + } + $tmp + } +} +else { + if ($SmaResources.SQLMI) { + + $TableName = ('SQLMITable_'+($SmaResources.SQLMI.id | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 + + $condtxt = @() + $condtxt += New-ConditionalText FALSE -Range J:J + $condtxt += New-ConditionalText FALSO -Range J:J + $condtxt += New-ConditionalText FAUX -Range J:J + $condtxt += New-ConditionalText NONE -Range J:J + $condtxt += New-ConditionalText Enabled -Range L:L + $condtxt += New-ConditionalText VRAI -Range L:L + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('Resource Group') + $Exc.Add('Name') + $Exc.Add('Location') + $Exc.Add('SkuName') + $Exc.Add('SkuCapacity') + $Exc.Add('SkuTier') + $Exc.Add('Admin Login') + $Exc.Add('ActiveDirectoryOnlyAuthentication') + $Exc.Add('Private Endpoint') + $Exc.Add('FQDN') + $Exc.Add('Public Network Access') + $Exc.Add('licenseType') + $Exc.Add('managedInstanceCreateMode') + $Exc.Add('Zone Redundant') + if($InTag) + { + $Exc.Add('Tag Name') + $Exc.Add('Tag Value') + } + + $ExcelVar = $SmaResources.SQLMI + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'SQL MI' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -ConditionalText $condtxt -Style $Style + + } } \ No newline at end of file diff --git a/Modules/Data/SQLMIDB.ps1 b/Modules/Scripts/Data/SQLMIDB.ps1 similarity index 97% rename from Modules/Data/SQLMIDB.ps1 rename to Modules/Scripts/Data/SQLMIDB.ps1 index 1cdf7fe..a2687c5 100644 --- a/Modules/Data/SQLMIDB.ps1 +++ b/Modules/Scripts/Data/SQLMIDB.ps1 @@ -1,98 +1,98 @@ -<# -.Synopsis -Inventory for Azure SQL Server - -.DESCRIPTION -This script consolidates information for all microsoft.sql/servers resource provider in $Resources variable. -Excel Sheet Name: SQL MI DBs - -.Link -https://github.com/microsoft/ARI/Modules/Data/SQLSERVER.ps1 - -.COMPONENT -This powershell Module is part of Azure Resource Inventory (ARI) - -.NOTES -Version: 2.3.2 -First Release Date: 19th November, 2020 -Authors: Claudio Merola and Renato Gregio - -#> - -<######## Default Parameters. Don't modify this ########> - -param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) - -if ($Task -eq 'Processing') { - - $SQLSERVERMIDB = $Resources | Where-Object { $_.TYPE -eq 'microsoft.sql/managedinstances/databases' } - - if($SQLSERVERMIDB) - { - $tmp = @() - - foreach ($1 in $SQLSERVERMIDB) { - $ResUCount = 1 - $sub1 = $SUB | Where-Object { $_.id -eq $1.subscriptionId } - $data = $1.PROPERTIES - - $Tags = if(!!($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} - - $pvteps = if(!($data.privateEndpointConnections)) {[pscustomobject]@{id = 'NONE'}} else {$data.privateEndpointConnections | Select-Object @{Name="id";Expression={$_.id.split("/")[10]}}} - - foreach ($pvtep in $pvteps) { - foreach ($Tag in $Tags) { - $obj = @{ - 'ID' = $1.id; - 'Subscription' = $sub1.Name; - 'MI parent' = $1.id.split("/")[8]; - 'Name' = $1.NAME; - 'Collation' = $data.collation; - 'CreationDate' = $data.creationDate; - 'DefaultSecondaryLocation' = $data.defaultSecondaryLocation; - 'Status' = $data.status; - 'Tag Name' = [string]$Tag.Name; - 'Tag Value' = [string]$Tag.Value - } - $tmp += $obj - if ($ResUCount -eq 1) { $ResUCount = 0 } - } - } - } - $tmp - } -} -else { - if ($SmaResources.SQLMIDB) { - - $TableName = ('SQLMIDBTable_'+($SmaResources.SQLMIDB.id | Select-Object -Unique).count) - $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 - - $condtxt = @() - $condtxt += New-ConditionalText FALSE -Range J:J - $condtxt += New-ConditionalText FALSO -Range J:J - $condtxt += New-ConditionalText FAUX -Range J:J - $condtxt += New-ConditionalText offline -Range G:G - - $Exc = New-Object System.Collections.Generic.List[System.Object] - $Exc.Add('Subscription') - $Exc.Add('MI parent') - $Exc.Add('Name') - $Exc.Add('Collation') - $Exc.Add('CreationDate') - $Exc.Add('DefaultSecondaryLocation') - $Exc.Add('Status') - if($InTag) - { - $Exc.Add('Tag Name') - $Exc.Add('Tag Value') - } - - $ExcelVar = $SmaResources.SQLMIDB - - $ExcelVar | - ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | - Export-Excel -Path $File -WorksheetName 'SQL MI DBs' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -ConditionalText $condtxt -Style $Style - - } +<# +.Synopsis +Inventory for Azure SQL Server + +.DESCRIPTION +This script consolidates information for all microsoft.sql/servers resource provider in $Resources variable. +Excel Sheet Name: SQL MI DBs + +.Link +https://github.com/microsoft/ARI/Modules/Data/SQLSERVER.ps1 + +.COMPONENT +This powershell Module is part of Azure Resource Inventory (ARI) + +.NOTES +Version: 2.3.2 +First Release Date: 19th November, 2020 +Authors: Claudio Merola and Renato Gregio + +#> + +<######## Default Parameters. Don't modify this ########> + +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) + +if ($Task -eq 'Processing') { + + $SQLSERVERMIDB = $Resources | Where-Object { $_.TYPE -eq 'microsoft.sql/managedinstances/databases' } + + if($SQLSERVERMIDB) + { + $tmp = @() + + foreach ($1 in $SQLSERVERMIDB) { + $ResUCount = 1 + $sub1 = $SUB | Where-Object { $_.id -eq $1.subscriptionId } + $data = $1.PROPERTIES + + $Tags = if(!!($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} + + $pvteps = if(!($data.privateEndpointConnections)) {[pscustomobject]@{id = 'NONE'}} else {$data.privateEndpointConnections | Select-Object @{Name="id";Expression={$_.id.split("/")[10]}}} + + foreach ($pvtep in $pvteps) { + foreach ($Tag in $Tags) { + $obj = @{ + 'ID' = $1.id; + 'Subscription' = $sub1.Name; + 'MI parent' = $1.id.split("/")[8]; + 'Name' = $1.NAME; + 'Collation' = $data.collation; + 'CreationDate' = $data.creationDate; + 'DefaultSecondaryLocation' = $data.defaultSecondaryLocation; + 'Status' = $data.status; + 'Tag Name' = [string]$Tag.Name; + 'Tag Value' = [string]$Tag.Value + } + $tmp += $obj + if ($ResUCount -eq 1) { $ResUCount = 0 } + } + } + } + $tmp + } +} +else { + if ($SmaResources.SQLMIDB) { + + $TableName = ('SQLMIDBTable_'+($SmaResources.SQLMIDB.id | Select-Object -Unique).count) + $Style = New-ExcelStyle -HorizontalAlignment Center -AutoSize -NumberFormat 0 + + $condtxt = @() + $condtxt += New-ConditionalText FALSE -Range J:J + $condtxt += New-ConditionalText FALSO -Range J:J + $condtxt += New-ConditionalText FAUX -Range J:J + $condtxt += New-ConditionalText offline -Range G:G + + $Exc = New-Object System.Collections.Generic.List[System.Object] + $Exc.Add('Subscription') + $Exc.Add('MI parent') + $Exc.Add('Name') + $Exc.Add('Collation') + $Exc.Add('CreationDate') + $Exc.Add('DefaultSecondaryLocation') + $Exc.Add('Status') + if($InTag) + { + $Exc.Add('Tag Name') + $Exc.Add('Tag Value') + } + + $ExcelVar = $SmaResources.SQLMIDB + + $ExcelVar | + ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | + Export-Excel -Path $File -WorksheetName 'SQL MI DBs' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -ConditionalText $condtxt -Style $Style + + } } \ No newline at end of file diff --git a/Modules/Data/SQLPOOL.ps1 b/Modules/Scripts/Data/SQLPOOL.ps1 similarity index 100% rename from Modules/Data/SQLPOOL.ps1 rename to Modules/Scripts/Data/SQLPOOL.ps1 diff --git a/Modules/Data/SQLSERVER.ps1 b/Modules/Scripts/Data/SQLSERVER.ps1 similarity index 100% rename from Modules/Data/SQLSERVER.ps1 rename to Modules/Scripts/Data/SQLSERVER.ps1 diff --git a/Modules/Data/SQLVM.ps1 b/Modules/Scripts/Data/SQLVM.ps1 similarity index 100% rename from Modules/Data/SQLVM.ps1 rename to Modules/Scripts/Data/SQLVM.ps1 diff --git a/Modules/Infrastructure/AppGW.ps1 b/Modules/Scripts/Infrastructure/AppGW.ps1 similarity index 100% rename from Modules/Infrastructure/AppGW.ps1 rename to Modules/Scripts/Infrastructure/AppGW.ps1 diff --git a/Modules/Infrastructure/AutomationAcc.ps1 b/Modules/Scripts/Infrastructure/AutomationAcc.ps1 similarity index 100% rename from Modules/Infrastructure/AutomationAcc.ps1 rename to Modules/Scripts/Infrastructure/AutomationAcc.ps1 diff --git a/Modules/Infrastructure/AvSet.ps1 b/Modules/Scripts/Infrastructure/AvSet.ps1 similarity index 100% rename from Modules/Infrastructure/AvSet.ps1 rename to Modules/Scripts/Infrastructure/AvSet.ps1 diff --git a/Modules/Infrastructure/BASTION.ps1 b/Modules/Scripts/Infrastructure/BASTION.ps1 similarity index 100% rename from Modules/Infrastructure/BASTION.ps1 rename to Modules/Scripts/Infrastructure/BASTION.ps1 diff --git a/Modules/Infrastructure/Frontdoor.ps1 b/Modules/Scripts/Infrastructure/Frontdoor.ps1 similarity index 100% rename from Modules/Infrastructure/Frontdoor.ps1 rename to Modules/Scripts/Infrastructure/Frontdoor.ps1 diff --git a/Modules/Infrastructure/RecoveryVault.ps1 b/Modules/Scripts/Infrastructure/RecoveryVault.ps1 similarity index 100% rename from Modules/Infrastructure/RecoveryVault.ps1 rename to Modules/Scripts/Infrastructure/RecoveryVault.ps1 diff --git a/Modules/Infrastructure/Vault.ps1 b/Modules/Scripts/Infrastructure/Vault.ps1 similarity index 100% rename from Modules/Infrastructure/Vault.ps1 rename to Modules/Scripts/Infrastructure/Vault.ps1 diff --git a/Modules/Integration/APIM.ps1 b/Modules/Scripts/Integration/APIM.ps1 similarity index 100% rename from Modules/Integration/APIM.ps1 rename to Modules/Scripts/Integration/APIM.ps1 diff --git a/Modules/Integration/AppInsights.ps1 b/Modules/Scripts/Integration/AppInsights.ps1 similarity index 100% rename from Modules/Integration/AppInsights.ps1 rename to Modules/Scripts/Integration/AppInsights.ps1 diff --git a/Modules/Integration/Backup.ps1 b/Modules/Scripts/Integration/Backup.ps1 similarity index 100% rename from Modules/Integration/Backup.ps1 rename to Modules/Scripts/Integration/Backup.ps1 diff --git a/Modules/Integration/IOTHubs.ps1 b/Modules/Scripts/Integration/IOTHubs.ps1 similarity index 100% rename from Modules/Integration/IOTHubs.ps1 rename to Modules/Scripts/Integration/IOTHubs.ps1 diff --git a/Modules/Integration/ServiceBUS.ps1 b/Modules/Scripts/Integration/ServiceBUS.ps1 similarity index 100% rename from Modules/Integration/ServiceBUS.ps1 rename to Modules/Scripts/Integration/ServiceBUS.ps1 diff --git a/Modules/Networking/AzureFirewall.ps1 b/Modules/Scripts/Networking/AzureFirewall.ps1 similarity index 100% rename from Modules/Networking/AzureFirewall.ps1 rename to Modules/Scripts/Networking/AzureFirewall.ps1 diff --git a/Modules/Networking/Connections.ps1 b/Modules/Scripts/Networking/Connections.ps1 similarity index 100% rename from Modules/Networking/Connections.ps1 rename to Modules/Scripts/Networking/Connections.ps1 diff --git a/Modules/Networking/ExpressRoute.ps1 b/Modules/Scripts/Networking/ExpressRoute.ps1 similarity index 100% rename from Modules/Networking/ExpressRoute.ps1 rename to Modules/Scripts/Networking/ExpressRoute.ps1 diff --git a/Modules/Networking/LoadBalancer.ps1 b/Modules/Scripts/Networking/LoadBalancer.ps1 similarity index 97% rename from Modules/Networking/LoadBalancer.ps1 rename to Modules/Scripts/Networking/LoadBalancer.ps1 index 50d02b4..b0f3b9e 100644 --- a/Modules/Networking/LoadBalancer.ps1 +++ b/Modules/Scripts/Networking/LoadBalancer.ps1 @@ -13,7 +13,7 @@ https://github.com/microsoft/ARI/Modules/Networking/LoadBalancer.ps1 This powershell Module is part of Azure Resource Inventory (ARI) .NOTES -Version: 3.1.1 +Version: 3.4.1 First Release Date: 19th November, 2020 Authors: Claudio Merola and Renato Gregio @@ -21,7 +21,7 @@ Authors: Claudio Merola and Renato Gregio <######## Default Parameters. Don't modify this ########> -param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) +param($SCPath, $Sub, $Intag, $Resources, $Task , $File, $SmaResources, $TableStyle, $Unsupported) If ($Task -eq 'Processing') { $LoadBalancer = $Resources | Where-Object { $_.TYPE -eq 'microsoft.network/loadbalancers' } @@ -30,7 +30,7 @@ If ($Task -eq 'Processing') { { $tmp = @() - foreach ($1 in $LoadBalancer) { + foreach ($1 in $LoadBalancer ) { $ResUCount = 1 $sub1 = $SUB | Where-Object { $_.Id -eq $1.subscriptionId } $FrontEnds = @() @@ -46,7 +46,7 @@ If ($Task -eq 'Processing') { $RetFeature = ($Unsupported | Where-Object {$_.Id -eq 8}).RetiringFeature } $Tags = if(![string]::IsNullOrEmpty($1.tags.psobject.properties)){$1.tags.psobject.properties}else{'0'} - foreach ($2 in $data.frontendIPConfigurations) + $FrontEnds = foreach ($2 in $data.frontendIPConfigurations) { if (![string]::IsNullOrEmpty($2.properties.subnet.id)) { @@ -56,7 +56,7 @@ If ($Task -eq 'Processing') { FrontType = 'VNET' frontsub = $2.properties.subnet.id.split('/')[10] } - $FrontEnds += $tmps + $tmps } elseif (![string]::IsNullOrEmpty($2.properties.publicIPAddress.id)) { @@ -66,10 +66,10 @@ If ($Task -eq 'Processing') { FrontType = 'Public IP' frontsub = $null } - $FrontEnds += $tmps + $tmps } } - foreach ($3 in $data.backendAddressPools) + $Backends = foreach ($3 in $data.backendAddressPools) { if (![string]::IsNullOrEmpty($3.properties.backendIPConfigurations.id)) { @@ -78,10 +78,10 @@ If ($Task -eq 'Processing') { BackTarget = $3.properties.backendIPConfigurations.id.split('/')[8] BackType = $3.properties.backendIPConfigurations.id.split('/')[7] } - $Backends += $tmps + $tmps } } - foreach ($4 in $data.probes) + $Probes = foreach ($4 in $data.probes) { $tmps = [pscustomobject]@{ name = $4.name @@ -90,14 +90,14 @@ If ($Task -eq 'Processing') { Port = $4.properties.port Threshold = $4.properties.numberOfProbes } - $Probes += $tmps + $tmps } $TempAr = @() $ob = [pscustomobject]@{ - loop = 'FrontEnd' - number = $FrontEnds.Count - } + loop = 'FrontEnd' + number = $FrontEnds.Count + } $TempAr += $ob $ob = [pscustomobject]@{ loop = 'BackEnd' @@ -110,11 +110,15 @@ If ($Task -eq 'Processing') { } $TempAr += $ob $Order = $TempAr | Select-Object -Property loop,number | Sort-Object number + $FrontEnds = if(![string]::IsNullOrEmpty($FrontEnds)){$FrontEnds}else{'0'} + $Backends = if(![string]::IsNullOrEmpty($Backends)){$Backends}else{'0'} + $Probes = if(![string]::IsNullOrEmpty($Probes)){$Probes}else{'0'} if (($Order.loop | Select-Object -First 1) -eq 'Probe') { if (($Order.loop | Select-Object -First 1 -Skip 1) -eq 'FrontEnd') { + foreach ($Probe in $Probes) { foreach ($FrontEnd in $FrontEnds) diff --git a/Modules/Networking/NATGAteway.ps1 b/Modules/Scripts/Networking/NATGAteway.ps1 similarity index 100% rename from Modules/Networking/NATGAteway.ps1 rename to Modules/Scripts/Networking/NATGAteway.ps1 diff --git a/Modules/Networking/NetworkInterface.ps1 b/Modules/Scripts/Networking/NetworkInterface.ps1 similarity index 100% rename from Modules/Networking/NetworkInterface.ps1 rename to Modules/Scripts/Networking/NetworkInterface.ps1 diff --git a/Modules/Networking/NetworkSecurityGroup.ps1 b/Modules/Scripts/Networking/NetworkSecurityGroup.ps1 similarity index 94% rename from Modules/Networking/NetworkSecurityGroup.ps1 rename to Modules/Scripts/Networking/NetworkSecurityGroup.ps1 index 7c50c6f..36445bb 100644 --- a/Modules/Networking/NetworkSecurityGroup.ps1 +++ b/Modules/Scripts/Networking/NetworkSecurityGroup.ps1 @@ -13,9 +13,10 @@ https://github.com/microsoft/ARI/Modules/Networking/NetworkSecurityGroup.ps1 This powershell Module is part of Azure Resource Inventory (ARI) .NOTES -Version: 3.1.0 +Version: 4.1.0 First Release Date: 2021.10.05 -Authors: Christopher Lewis +Authors: Christopher Lewis, + Claudio Merola #> @@ -83,7 +84,9 @@ If ($Task -eq 'Processing') { $FinalSUBs = if ($FinalSUBs -like '* ,*') { $FinalSUBs -replace ".$" }else { $FinalSUBs } } - foreach ($2 in $data.securityRules) + $SecurityRules = $data.securityRules + $SecurityRules = if (![string]::IsNullOrEmpty($SecurityRules)) { $SecurityRules }else { '0' } + foreach ($2 in $SecurityRules) { foreach ($Tag in $Tags) { if (![string]::IsNullOrEmpty($2.properties.sourceAddressPrefixes)) @@ -192,13 +195,9 @@ If ($Task -eq 'Processing') { $tmp } } Else { - # -------------------------------------------------------------------------------- - # the $SmaResources object for a module should be the same as the name of the file. - # In this case the file name is "NetworkSecurityGroup.ps1" so the SMA object - # is $SmaResources.NetworkSecurityGroup - # -------------------------------------------------------------------------------- - $ExcelVar = $SmaResources.NetworkSecurityGroup - if ($ExcelVar) { + if ($SmaResources.NetworkSecurityGroup) { + + $Excelvar = $SmaResources.NetworkSecurityGroup $TableName = ('NSGTable_'+($SmaResources.NetworkSecurityGroup.id | Select-Object -Unique).count) $Style = @() @@ -207,7 +206,6 @@ If ($Task -eq 'Processing') { $Style += New-ExcelStyle -HorizontalAlignment Center -WrapText -NumberFormat 0 -Range "O:O" -Width 70 $Style += New-ExcelStyle -HorizontalAlignment Center -WrapText -NumberFormat 0 -Range "Q:R" -Width 70 - #Conditional formats. Note that this can be $() for none $condtxt = @() $condtxt += New-ConditionalText TRUE -Range G:G $condtxt += New-ConditionalText - -Range E:E -ConditionalType ContainsText @@ -245,9 +243,5 @@ If ($Task -eq 'Processing') { ForEach-Object { [PSCustomObject]$_ } | Select-Object -Unique $Exc | Export-Excel -Path $File -WorksheetName 'Network Security Groups' -AutoSize -MaxAutoSizeRows 100 -TableName $TableName -TableStyle $tableStyle -ConditionalText $condtxt -Style $Style -NoNumberConversion $noNumberConversion - - <######## Insert Column comments and documentations here following this model. See StoraceAcc.ps1 for samples #########> - - } } diff --git a/Modules/Networking/PrivateDNS.ps1 b/Modules/Scripts/Networking/PrivateDNS.ps1 similarity index 100% rename from Modules/Networking/PrivateDNS.ps1 rename to Modules/Scripts/Networking/PrivateDNS.ps1 diff --git a/Modules/Networking/PrivateEndpoint.ps1 b/Modules/Scripts/Networking/PrivateEndpoint.ps1 similarity index 100% rename from Modules/Networking/PrivateEndpoint.ps1 rename to Modules/Scripts/Networking/PrivateEndpoint.ps1 diff --git a/Modules/Networking/PublicDNS.ps1 b/Modules/Scripts/Networking/PublicDNS.ps1 similarity index 100% rename from Modules/Networking/PublicDNS.ps1 rename to Modules/Scripts/Networking/PublicDNS.ps1 diff --git a/Modules/Networking/PublicIP.ps1 b/Modules/Scripts/Networking/PublicIP.ps1 similarity index 100% rename from Modules/Networking/PublicIP.ps1 rename to Modules/Scripts/Networking/PublicIP.ps1 diff --git a/Modules/Networking/ROUTETABLE.ps1 b/Modules/Scripts/Networking/ROUTETABLE.ps1 similarity index 100% rename from Modules/Networking/ROUTETABLE.ps1 rename to Modules/Scripts/Networking/ROUTETABLE.ps1 diff --git a/Modules/Networking/TrafficManager.ps1 b/Modules/Scripts/Networking/TrafficManager.ps1 similarity index 100% rename from Modules/Networking/TrafficManager.ps1 rename to Modules/Scripts/Networking/TrafficManager.ps1 diff --git a/Modules/Networking/VNETGTW.ps1 b/Modules/Scripts/Networking/VNETGTW.ps1 similarity index 100% rename from Modules/Networking/VNETGTW.ps1 rename to Modules/Scripts/Networking/VNETGTW.ps1 diff --git a/Modules/Networking/VirtualNetwork.ps1 b/Modules/Scripts/Networking/VirtualNetwork.ps1 similarity index 99% rename from Modules/Networking/VirtualNetwork.ps1 rename to Modules/Scripts/Networking/VirtualNetwork.ps1 index ffbe708..d749ca3 100644 --- a/Modules/Networking/VirtualNetwork.ps1 +++ b/Modules/Scripts/Networking/VirtualNetwork.ps1 @@ -13,7 +13,7 @@ https://github.com/microsoft/ARI/Modules/Networking/VirtualNetwork.ps1 This powershell Module is part of Azure Resource Inventory (ARI) .NOTES -Version: 3.2.1 +Version: 3.2.2 First Release Date: 19th November, 2020 Authors: Claudio Merola and Renato Gregio @@ -106,7 +106,7 @@ If ($Task -eq 'Processing') { 'Available IPs' = [string]$AvailableIPs; 'Subnet Name' = $2.name; 'Private Subnet' = if($2.properties.defaultOutboundAccess -eq 'false'){'true'}else{'false'}; - 'Subnet Prefix' = $Prefixes; + 'Subnet Prefix' = [string]$Prefixes; 'Subnet Private Link Service Network Policies' = $2.properties.privateLinkServiceNetworkPolicies; 'Subnet Private Endpoint Network Policies' = $2.properties.privateEndpointNetworkPolicies; 'Subnet Delegations' = $Delegations; diff --git a/Modules/Networking/VirtualWAN.ps1 b/Modules/Scripts/Networking/VirtualWAN.ps1 similarity index 100% rename from Modules/Networking/VirtualWAN.ps1 rename to Modules/Scripts/Networking/VirtualWAN.ps1 diff --git a/Modules/Networking/vNETPeering.ps1 b/Modules/Scripts/Networking/vNETPeering.ps1 similarity index 100% rename from Modules/Networking/vNETPeering.ps1 rename to Modules/Scripts/Networking/vNETPeering.ps1 diff --git a/Modules/Storage/DataExplorerCluster.ps1 b/Modules/Scripts/Storage/DataExplorerCluster.ps1 similarity index 100% rename from Modules/Storage/DataExplorerCluster.ps1 rename to Modules/Scripts/Storage/DataExplorerCluster.ps1 diff --git a/Modules/Storage/NetApp.ps1 b/Modules/Scripts/Storage/NetApp.ps1 similarity index 100% rename from Modules/Storage/NetApp.ps1 rename to Modules/Scripts/Storage/NetApp.ps1 diff --git a/Modules/Storage/StorageAcc.ps1 b/Modules/Scripts/Storage/StorageAcc.ps1 similarity index 100% rename from Modules/Storage/StorageAcc.ps1 rename to Modules/Scripts/Storage/StorageAcc.ps1 diff --git a/Modules/Storage/VMDisk.ps1 b/Modules/Scripts/Storage/VMDisk.ps1 similarity index 100% rename from Modules/Storage/VMDisk.ps1 rename to Modules/Scripts/Storage/VMDisk.ps1 diff --git a/README.md b/README.md index 58dcc28..59d5f4d 100644 --- a/README.md +++ b/README.md @@ -12,177 +12,179 @@ Tags: Powershell, Azure, Inventory, Excel Report, Customer Engineer
-![Logo](images/ARI_Logo.png) +

+ +

# Azure Resource Inventory -Azure Resource inventory (ARI) is a powerful script written in powershell that generates an Excel report of any Azure Environment you have read access. +Azure Resource inventory (ARI) is a powerful powershell module that generates an Excel report of any Azure Environment you have read access. This project is intend to help Cloud Admins and anyone that might need an easy and fast way to build a full Excel Report of an Azure Environment.
-## What's new ? - -
- -### Version 3 is alive!! +### What's new ?
-![Overview](images/ARIv3-Overview.png) +- Version 3.5 is here: + - ARI Powershell Module + - New Automation Account + - Azure Rest API
-Among the many improvements, those are the highlights of the new version: +## Azure Resource Inventory Overview
-#### 1) Support for 6 extra resource types, including NetApp and VMWare Solution. +

+ +


-Since the begining of the project, we wanted ARI to evolve and keep pace with the improvements on Azure Resources. Keeping that in mind we are adding extra modules for newer resources. +

+ +

-We also reviewed and updated some of the old resources as well. +#### Network Topology View
-#### 2) Diagram was completely rebuild and now support environments with more than 30.000 resources +

+ +


-Network Topology was cool but in large environments it had some problems (i.e.: freezing and never finishing), and even when it finished it might take forever. - -We added parallel processing to diagram, now during the execution of ARI, an extra folder (DiagramCache) will be created, that folder is used by the diagram to store temporary components of the diagrams, after all the parallel processing is done those files are merged in the main diagram. - -Now diagram will even finish way before the Excel file. +- An extra detail is that if you hover the mouse cursor over any resource in the Network Topology you get the resource details:
-#### 3) Network Topology in the Diagram now identifies the Hub and Spokes Virtual Network +

+ +


-![Draw.IO](images/DrawioImage.png) +- This feature is available for any resource and even peering lines:
-Tab names were added in the diagram and now the Network Topology is the first tab. - -Also in the Network Topology, we are using color in the diagram to identify the different Virtual Network usages in HUB-Spoke topologies. +

+ +

-Colors will also be used to indicate broken peers. +

-#### 4) Diagram now include "Organizational View" (Management Groups) +#### Organization View
-![Draw.IOOrg](images/DrawioOrganization.png) +

+ +


-We added extra tabs in the new diagram, the second tab is called "Organization" and will present the hierarquical view of subscriptions in the environment. - -The idea is to make easier to align your environment with the Microsoft's Landing Zone design ([What is an Azure landing zone](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/)). +#### Resources View
-#### 5) Diagram now include Resource Overview for every subscription in the environment +

+ +


-![Draw.IOOrg](images/drawiosubs.png) +## Version 3.5
-Since not everyone have really complex network environments, many people complain about diagram not really presenting much for their environments. - -This change now. Every single Subscription will be a tab in the diagram, those tabs will contain the Subscription, the resource groups and the sum of every type of resource in the resource groups. By now almost every type of draw.io stencil available will be identified, with more coming in the next months. +Among the many improvements, there are two that will considerable change the way we use the script and type of data we are reporting:
-#### 6) ARI in Automation Account +#### 1) Azure Resource Inventory (Powershell Module)
-![Overview](images/Automation.png) +We expect this change will positively change the experience of installing and executing ARI:
-Some people were asking to run ARI in Azure Automation Account and since the old script for automation accounts was not working we managed to fix it for this version. But now is require to use Runtime 7.2 and add the modules: "ImportExcel", "Az.ResourceGraph", "Az.Storage", "Az.Account" and "ThreadJob" in the Automation Account. +Installing ARI: -The required steps are present in the: [Automation Guide](https://github.com/microsoft/ARI/blob/main/Automation/README.md). +``` +Install-Module -Name AzureResourceInventory +```
+

+ +

+
-> ### *1) Excel Overview* +Now to run the script just execute "Invoke-ARI" with the regular parameters: ---------------------- +``` +Invoke-ARI +```
-- The dashboard shows an overall view and summary of resources in the environment. +

+ +


-![Overview](images/ARIv3-Overview.png) +#### 2) Automation is now fully integrated within the ARI Module
-- The resource sheet present details and recommendations, security and costs reducing tips for the resources. +The process to run Azure Resource Inventory using Automation Accounts was changed to fully integrate with the new ARI Module -
- -![Overview](images/ARIv3ExcelExample.png)
-> ### *2) Azure Diagram Inventory!* - ---------------------- +

+ +

-By default everytime you run the Azure Resource Inventory the diagram will be created. +
-If you do not wish to have the diagram created, you must use the __-SkipDiagram__ parameter. -Also, by default the Network Topology will not consider Virtual Networks that are not connected trough peering. If you wants to include those Virtual Networks in the diagram, you must use the parameter __-DiagramFullEnvironment__. +The required steps are present in the: [Automation Guide](https://github.com/microsoft/ARI/blob/main/Automation/README.md).
-#### Diagram: -
-

- -

+#### 3) Azure Rest API
-- An extra detail is that if you hover the mouse cursor over any resource in the Network Topology you get the resource details: +We are finally incorporating Azure REST API data into ARI. -
+At this time we are only including: -

- -

+ - Azure Support Tickets + - Azure Health Incidents + - Azure Advisor Score Data + - Reservation Recommendations -
+We expect this will open doors for extra types of data to be included in the script in the future. -- This feature is available for any resource and even peering lines:
-

- -

- -

@@ -191,17 +193,18 @@ Also, by default the Network Topology will not consider Virtual Networks that ar | Parameter | Description | | |------------------------|-------------------------------------------------------------------------------------------------------------|----------------------------| | TenantID | Specify the tenant ID you want to create a Resource Inventory. | `-TenantID ` | -| AppId | Service Principal Authentication | `-AppId ` | -| Secret | Client secret of the Service Principal | `-Secret ` | | SubscriptionID | Specifies Subscription(s) to be inventoried. | `-SubscriptionID ` | | ManagementGroup | Specifies the Management Group to be inventoried(all Subscriptions on it) | `-ManagementGroup ` | -| Lite | Speficies to use only the Import-Excel module and don't create the charts (using Excel's API) | `-Lite` | +| Lite | Specifies to use only the Import-Excel module and don't create the charts (using Excel's API) | `-Lite` | | SecurityCenter | Include Security Center Data. | `-SecurityCenter` | | SkipAdvisory | Do not collect Azure Advisory. | `-SkipAdvisory` | +| Automation | Required when running the script with Automation Account | `-Automation` | +| StorageAccount | Storage Account Name (Required when running the script with Automation Account) | `-StorageAccount` | +| StorageContainer | Storage Account Container Name (Required when running the script with Automation Account) | `-StorageContainer` | | IncludeTags | Include Resource Tags. | `-IncludeTags` | | Debug | Run in a Debug mode. | `-Debug` | | DiagramFullEnvironment | Network Diagram of the entire environment | `-DiagramFullEnvironment` | -| Diagram | Create a Visio Diagram. | `-Diagram` | +| Diagram | Create a Draw.IO Diagram. | `-Diagram` | | SkipDiagram | To skip the diagrams creation | `-SkipDiagram` | | DeviceLogin | Authenticating on Azure using the Device login approach | `-DeviceLogin` | | AzureEnvironment | Choose between Azure environments
> Registered Azure Clouds. Use `az cloud list` to get the list | `-AzureEnvironment ` | @@ -216,35 +219,35 @@ Also, by default the Network Topology will not consider Virtual Networks that ar #### Examples - For CloudShell: ```bash - />./AzureResourceInventory.ps1 + />./Invoke-ARI -Debug ``` - Powershell Desktop: ```bash - />./AzureResourceInventory.ps1 + />./Invoke-ARI -TenantID ``` - > If you do not specify Resource Inventory will be performed on all subscriptions for the selected tenant. + > If you do not specify the Subscription Resource Inventory will be performed on all subscriptions for the selected tenant. > To perform the inventory in a specific Tenant and subscription use `-TenantID` and `-SubscriptionID` parameter ```bash - />./AzureResourceInventory.ps1 -TenantID -SubscriptionID + />./Invoke-ARI -TenantID -SubscriptionID ``` - Including Tags: ```bash - />./AzureResourceInventory.ps1 -TenantID --IncludeTags + />./Invoke-ARI -TenantID --IncludeTags ``` > By Default Azure Resource inventory do not include Resource Tags. - Collecting Security Center Data: ```bash - />./AzureResourceInventory.ps1 -TenantID -SubscriptionID -SecurityCenter + />./Invoke-ARI -TenantID -SubscriptionID -SecurityCenter ``` > By Default Azure Resource inventory do not collect Security Center Data. - Skipping Azure Advisor: ```bash - />./AzureResourceInventory.ps1 -TenantID -SubscriptionID -SkipAdvisory + />./Invoke-ARI -TenantID -SubscriptionID -SkipAdvisory ``` > By Default Azure Resource inventory collects Azure Advisor Data. -- Creating Network Diagram: +- Skipping Network Diagram: ```bash - />./AzureResourceInventory.ps1 -TenantID -Diagram + />./Invoke-ARI -TenantID -SkipDiagram ```
@@ -258,12 +261,8 @@ These instructions will get you a copy of the project up and running on your loc
### Supportability -|Resource Provider|Results|Draw.io Diagram|Comments| -|-----------------|-------------|-----------------|-------------| -|Windows|Fully successfully tested|Supported|Best Results| -|MAC|Fully successfully tested|Not Supported|| -|Linux|Tested on Ubuntu Desktop|Not Supported|No Table auto-fit for columns| -|CloudShell|Tested on Azure CloudShell|Not Supported|No Table auto-fit for columns| + +Even the script might work in almost all environments. Some components (i.e the Topology Diagram) use some APIs and components only present in Windows environment.
@@ -272,28 +271,18 @@ These instructions will get you a copy of the project up and running on your loc |Tool |Version| |-----------------|-------------| |Windows|11 22H2| -|Powershell|5.1.19041.1237| -|ImportExcel|7.8| -|azure-cli|2.48.1| -|AzCLI account|0.2.3| -|AzCLI resource-graph|2.1.0| +|Powershell|7.4.4| +
### Prerequisites -You can use Azure Resource Inventory in both in Cloudshell and Powershell Desktop. - -What things you need to run the script - - -1. Install-Module [ImportExcel](https://github.com/dfinke/ImportExcel) -2. Install [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) -3. Install Azure CLI [Account](https://docs.microsoft.com/en-us/cli/azure/azure-cli-extensions-list) Extension -4. Install Azure CLI [Resource-Graph](https://docs.microsoft.com/en-us/cli/azure/azure-cli-extensions-list) Extension +Since the script is a Powershell Module, and we fully migrated az cli to powershell. No extra requirements are needed. +Just install the AzureResourceInventory Module and all the required modules will be automatically installed as well. -By default Azure Resource Inventory will call to install the required Powershell modules and Azure CLI components but you must have administrator privileges during the script execution. +By default Azure Resource Inventory will call to install the required Powershell modules but you must have administrator privileges during the script execution. Special Thanks for __Doug Finke__, the Author of Powershell [ImportExcel](https://github.com/dfinke/ImportExcel) Module. @@ -319,13 +308,13 @@ Special Thanks for __Doug Finke__, the Author of Powershell [ImportExcel](https:
-* Its really simple to use Azure Resource Inventory, all that you need to do is to call this script in PowerShell. +* Its really simple to use Azure Resource Inventory, all that you need to do is to invoke this cmdlet in PowerShell. -* Run "AzureResourceInventory.ps1". In Azure CloudShell you're already authenticated. In PowerShell Desktop you will be redirected to Azure sign-in page. +* Run "Invoke-ARI". In Azure CloudShell you're already authenticated. In PowerShell Desktop you will be redirected to Azure sign-in page.
-![Tenants Menu](images/Execution.png) +![RunningARI](images/RunningARI.gif) * If you have privileges in multiple tenants you can specify the desired one by using "-TenantID" parameter or Azure Resource will scan all your tenants ID and ask you to choose one. diff --git a/images/ARIv3-Overview.png b/images/ARIv3-Overview.png deleted file mode 100644 index 202e9d6..0000000 Binary files a/images/ARIv3-Overview.png and /dev/null differ diff --git a/images/ARIv35-Overview.png b/images/ARIv35-Overview.png new file mode 100644 index 0000000..fc4bad8 Binary files /dev/null and b/images/ARIv35-Overview.png differ diff --git a/images/Execution.png b/images/Execution.png deleted file mode 100644 index bd43167..0000000 Binary files a/images/Execution.png and /dev/null differ diff --git a/images/InstallARI.gif b/images/InstallARI.gif new file mode 100644 index 0000000..0df8aaf Binary files /dev/null and b/images/InstallARI.gif differ diff --git a/images/RunningARI.gif b/images/RunningARI.gif new file mode 100644 index 0000000..bfcfc01 Binary files /dev/null and b/images/RunningARI.gif differ